-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: revision of #5476 It has only one method `shareTextContent` and next will be`shareBinaryContent`. In Android, Promise can't receive a result, because `startActivityForResult` is not working with `Intent.ACTION_SEND`. Maybe we can use `createChooser(Intent target, CharSequence title, IntentSender sender)` which requires API level 22. Closes #5904 Differential Revision: D3612889 fbshipit-source-id: 0e7aaf34b076a99089cc76bd649e6da067d9a760
- Loading branch information
Showing
16 changed files
with
700 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* The examples provided by Facebook are for non-commercial testing and | ||
* evaluation purposes only. | ||
* | ||
* Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
* | ||
* @flow | ||
*/ | ||
'use strict'; | ||
|
||
var React = require('react'); | ||
var ReactNative = require('react-native'); | ||
var { | ||
StyleSheet, | ||
View, | ||
Text, | ||
TouchableHighlight, | ||
Share, | ||
} = ReactNative; | ||
|
||
exports.framework = 'React'; | ||
exports.title = 'Share'; | ||
exports.description = 'Share data with other Apps.'; | ||
exports.examples = [{ | ||
title: 'Share Text Content', | ||
render() { | ||
return <ShareMessageExample />; | ||
} | ||
}]; | ||
|
||
class ShareMessageExample extends React.Component { | ||
_shareMessage: Function; | ||
_shareText: Function; | ||
_showResult: Function; | ||
state: any; | ||
|
||
constructor(props) { | ||
super(props); | ||
|
||
this._shareMessage = this._shareMessage.bind(this); | ||
this._shareText = this._shareText.bind(this); | ||
this._showResult = this._showResult.bind(this); | ||
|
||
this.state = { | ||
result: '' | ||
}; | ||
} | ||
|
||
render() { | ||
return ( | ||
<View> | ||
<TouchableHighlight style={styles.wrapper} | ||
onPress={this._shareMessage}> | ||
<View style={styles.button}> | ||
<Text>Click to share message</Text> | ||
</View> | ||
</TouchableHighlight> | ||
<TouchableHighlight style={styles.wrapper} | ||
onPress={this._shareText}> | ||
<View style={styles.button}> | ||
<Text>Click to share message, URL and title</Text> | ||
</View> | ||
</TouchableHighlight> | ||
<Text>{this.state.result}</Text> | ||
</View> | ||
); | ||
} | ||
|
||
_shareMessage() { | ||
Share.share({ | ||
message: 'React Native | A framework for building native apps using React' | ||
}) | ||
.then(this._showResult) | ||
.catch((error) => this.setState({result: 'error: ' + error.message})); | ||
} | ||
|
||
_shareText() { | ||
Share.share({ | ||
message: 'A framework for building native apps using React', | ||
url: 'http://facebook.github.io/react-native/', | ||
title: 'React Native' | ||
}, { | ||
dialogTitle: 'Share React Native website', | ||
excludedActivityTypes: [ | ||
'com.apple.UIKit.activity.PostToTwitter' | ||
], | ||
tintColor: 'green' | ||
}) | ||
.then(this._showResult) | ||
.catch((error) => this.setState({result: 'error: ' + error.message})); | ||
} | ||
|
||
_showResult(result) { | ||
if (result.action === Share.sharedAction) { | ||
if (result.activityType) { | ||
this.setState({result: 'shared with an activityType: ' + result.activityType}); | ||
} else { | ||
this.setState({result: 'shared'}); | ||
} | ||
} else if (result.action === Share.dismissedAction) { | ||
this.setState({result: 'dismissed'}); | ||
} | ||
} | ||
|
||
} | ||
|
||
|
||
var styles = StyleSheet.create({ | ||
wrapper: { | ||
borderRadius: 5, | ||
marginBottom: 5, | ||
}, | ||
button: { | ||
backgroundColor: '#eeeeee', | ||
padding: 10, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* Copyright (c) 2016-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule Share | ||
* @flow | ||
*/ | ||
'use strict'; | ||
|
||
const Platform = require('Platform'); | ||
const { | ||
ActionSheetManager, | ||
ShareModule | ||
} = require('NativeModules'); | ||
const invariant = require('fbjs/lib/invariant'); | ||
const processColor = require('processColor'); | ||
|
||
type Content = { title?: string, message: string } | { title?: string, url: string }; | ||
type Options = { dialogTitle?: string, excludeActivityTypes?: Array<string>, tintColor?: string }; | ||
|
||
class Share { | ||
|
||
/** | ||
* Open a dialog to share text content. | ||
* | ||
* In iOS, Returns a Promise which will be invoked an object containing `action`, `activityType`. | ||
* If the user dismissed the dialog, the Promise will still be resolved with action being `Share.dismissedAction` | ||
* and all the other keys being undefined. | ||
* | ||
* In Android, Returns a Promise which always be resolved with action being `Share.sharedAction`. | ||
* | ||
* ### Content | ||
* | ||
* - `message` - a message to share | ||
* - `title` - title of the message | ||
* | ||
* #### iOS | ||
* | ||
* - `url` - an URL to share | ||
* | ||
* At least one of URL and message is required. | ||
* | ||
* ### Options | ||
* | ||
* #### iOS | ||
* | ||
* - `excludedActivityTypes` | ||
* - `tintColor` | ||
* | ||
* #### Android | ||
* | ||
* - `dialogTitle` | ||
* | ||
*/ | ||
static share(content: Content, options: Options = {}): Promise<Object> { | ||
invariant( | ||
typeof content === 'object' && content !== null, | ||
'Content must a valid object' | ||
); | ||
invariant( | ||
typeof content.url === 'string' || typeof content.message === 'string', | ||
'At least one of URL and message is required' | ||
); | ||
invariant( | ||
typeof options === 'object' && options !== null, | ||
'Options must be a valid object' | ||
); | ||
|
||
if (Platform.OS === 'android') { | ||
invariant( | ||
!content.title || typeof content.title === 'string', | ||
'Invalid title: title should be a string.' | ||
); | ||
return ShareModule.share(content, options.dialogTitle); | ||
} else if (Platform.OS === 'ios') { | ||
return new Promise((resolve, reject) => { | ||
ActionSheetManager.showShareActionSheetWithOptions( | ||
{...content, ...options, tintColor: processColor(options.tintColor)}, | ||
(error) => reject(error), | ||
(success, activityType) => { | ||
if (success) { | ||
resolve({ | ||
'action': 'sharedAction', | ||
'activityType': activityType | ||
}); | ||
} else { | ||
resolve({ | ||
'action': 'dismissedAction' | ||
}); | ||
} | ||
} | ||
); | ||
}); | ||
} else { | ||
return Promise.reject(new Error('Unsupported platform')); | ||
} | ||
} | ||
|
||
/** | ||
* The content was successfully shared. | ||
*/ | ||
static get sharedAction() { return 'sharedAction'; } | ||
|
||
/** | ||
* The dialog has been dismissed. | ||
* @platform ios | ||
*/ | ||
static get dismissedAction() { return 'dismissedAction'; } | ||
|
||
} | ||
|
||
module.exports = Share; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
ReactAndroid/src/androidTest/java/com/facebook/react/tests/ShareTestCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/** | ||
* Copyright (c) 2014-present, Facebook, Inc. | ||
* All rights reserved. | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
*/ | ||
|
||
package com.facebook.react.tests; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import android.app.Activity; | ||
import android.app.AlertDialog; | ||
import android.app.Instrumentation.ActivityMonitor; | ||
import android.content.DialogInterface; | ||
import android.content.Intent; | ||
import android.content.IntentFilter; | ||
import android.content.IntentFilter.MalformedMimeTypeException; | ||
import android.support.v4.app.DialogFragment; | ||
|
||
import com.facebook.react.bridge.BaseJavaModule; | ||
import com.facebook.react.testing.ReactInstanceSpecForTest; | ||
import com.facebook.react.bridge.ReactMethod; | ||
import com.facebook.react.bridge.JavaScriptModule; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.bridge.WritableNativeMap; | ||
import com.facebook.react.modules.share.ShareModule; | ||
import com.facebook.react.testing.ReactAppInstrumentationTestCase; | ||
|
||
/** | ||
* Test case for {@link ShareModule}. | ||
*/ | ||
public class ShareTestCase extends ReactAppInstrumentationTestCase { | ||
|
||
private static interface ShareTestModule extends JavaScriptModule { | ||
public void showShareDialog(WritableMap content, WritableMap options); | ||
} | ||
|
||
private static class ShareRecordingModule extends BaseJavaModule { | ||
|
||
private int mOpened = 0; | ||
private int mErrors = 0; | ||
|
||
@Override | ||
public String getName() { | ||
return "ShareRecordingModule"; | ||
} | ||
|
||
@ReactMethod | ||
public void recordOpened() { | ||
mOpened++; | ||
} | ||
|
||
@ReactMethod | ||
public void recordError() { | ||
mErrors++; | ||
} | ||
|
||
public int getOpened() { | ||
return mOpened; | ||
} | ||
|
||
public int getErrors() { | ||
return mErrors; | ||
} | ||
|
||
} | ||
|
||
final ShareRecordingModule mRecordingModule = new ShareRecordingModule(); | ||
|
||
@Override | ||
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { | ||
return super.createReactInstanceSpecForTest() | ||
.addNativeModule(mRecordingModule) | ||
.addJSModule(ShareTestModule.class); | ||
} | ||
|
||
@Override | ||
protected String getReactApplicationKeyUnderTest() { | ||
return "ShareTestApp"; | ||
} | ||
|
||
private ShareTestModule getTestModule() { | ||
return getReactContext().getCatalystInstance().getJSModule(ShareTestModule.class); | ||
} | ||
|
||
public void testShowBasicShareDialog() { | ||
final WritableMap content = new WritableNativeMap(); | ||
content.putString("message", "Hello, ReactNative!"); | ||
final WritableMap options = new WritableNativeMap(); | ||
|
||
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_CHOOSER); | ||
intentFilter.addCategory(Intent.CATEGORY_DEFAULT); | ||
ActivityMonitor monitor = getInstrumentation().addMonitor(intentFilter, null, true); | ||
|
||
getTestModule().showShareDialog(content, options); | ||
|
||
waitForBridgeAndUIIdle(); | ||
getInstrumentation().waitForIdleSync(); | ||
|
||
assertEquals(1, monitor.getHits()); | ||
assertEquals(1, mRecordingModule.getOpened()); | ||
assertEquals(0, mRecordingModule.getErrors()); | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.