Open source IntentAndroid

Summary: Move the code to the github folder, add more docs and improve the example.

We might want to merge this with `LinkingIOS` later (it has the same functionality
plus support for deep links) but want to see how people use the `IntentAndroid`
API first (and what other methods we should add) to have more data points.

public

Reviewed By: lexs

Differential Revision: D2646936

fb-gh-sync-id: 751f35784d387efcd031f9b458821cdfde048a54
This commit is contained in:
Martin Konicek 2015-11-12 12:35:44 -08:00 committed by facebook-github-bot-6
parent d5209a0829
commit ab7b3b2dea
8 changed files with 290 additions and 4 deletions

View File

@ -0,0 +1,90 @@
/**
* 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.
*/
'use strict';
var React = require('react-native');
var {
IntentAndroid,
StyleSheet,
Text,
TouchableNativeFeedback,
View,
} = React;
var UIExplorerBlock = require('./UIExplorerBlock');
var OpenURLButton = React.createClass({
propTypes: {
url: React.PropTypes.string,
},
handleClick: function() {
IntentAndroid.canOpenURL(this.props.url, (supported) => {
if (supported) {
IntentAndroid.openURL(this.props.url);
} else {
console.log('Don\'t know how to open URI: ' + this.props.url);
}
});
},
render: function() {
return (
<TouchableNativeFeedback
onPress={this.handleClick}>
<View style={styles.button}>
<Text style={styles.text}>Open {this.props.url}</Text>
</View>
</TouchableNativeFeedback>
);
}
});
var IntentAndroidExample = React.createClass({
statics: {
title: 'IntentAndroid',
description: 'Shows how to use Android Intents to open URLs.',
},
render: function() {
return (
<UIExplorerBlock title="Open external URLs">
<OpenURLButton url={'https://www.facebook.com'} />
<OpenURLButton url={'http://www.facebook.com'} />
<OpenURLButton url={'http://facebook.com'} />
<OpenURLButton url={'geo:37.484847,-122.148386'} />
</UIExplorerBlock>
);
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
padding: 10,
paddingTop: 30,
},
button: {
padding: 10,
backgroundColor: '#3B5998',
marginBottom: 10,
},
text: {
color: 'white',
},
});
module.exports = IntentAndroidExample;

View File

@ -38,6 +38,7 @@ var COMPONENTS = [
var APIS = [ var APIS = [
require('./AccessibilityAndroidExample.android'), require('./AccessibilityAndroidExample.android'),
require('./BorderExample'), require('./BorderExample'),
require('./IntentAndroidExample.android'),
require('./LayoutEventsExample'), require('./LayoutEventsExample'),
require('./LayoutExample'), require('./LayoutExample'),
require('./PanResponderExample'), require('./PanResponderExample'),

View File

@ -0,0 +1,90 @@
/**
* Copyright (c) 2015-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 IntentAndroid
*/
'use strict';
var IntentAndroidModule = require('NativeModules').IntentAndroid;
var invariant = require('invariant');
/**
* `IntentAndroid` gives you a general interface to handle external links.
*
* #### Opening external links
*
* To start the corresponding activity for a link (web URL, email, contact etc.), call
*
* ```
* IntentAndroid.openURL(url)
* ```
*
* If you want to check if any installed app can handle a given URL beforehand you can call
* ```
* IntentAndroid.canOpenURL(url, (supported) => {
* if (!supported) {
* console.log('Can\'t handle url: ' + url);
* } else {
* IntentAndroid.openURL(url);
* }
* });
* ```
*/
class IntentAndroid {
/**
* Starts a corresponding external activity for the given URL.
*
* For example, if the URL is "https://www.facebook.com", the system browser will be opened,
* or the "choose application" dialog will be shown.
*
* You can use other URLs, like a location (e.g. "geo:37.484847,-122.148386"), a contact,
* or any other URL that can be opened with {@code Intent.ACTION_VIEW}.
*
* NOTE: This method will fail if the system doesn't know how to open the specified URL.
* If you're passing in a non-http(s) URL, it's best to check {@code canOpenURL} first.
*
* NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
*/
static openURL(url: string) {
this._validateURL(url);
IntentAndroidModule.openURL(url);
}
/**
* Determine whether or not an installed app can handle a given URL.
*
* You can use other URLs, like a location (e.g. "geo:37.484847,-122.148386"), a contact,
* or any other URL that can be opened with {@code Intent.ACTION_VIEW}.
*
* NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
*
* @param URL the URL to open
*/
static canOpenURL(url: string, callback: Function) {
this._validateURL(url);
invariant(
typeof callback === 'function',
'A valid callback function is required'
);
IntentAndroidModule.canOpenURL(url, callback);
}
static _validateURL(url: string) {
invariant(
typeof url === 'string',
'Invalid URL: should be a string. Was: ' + url
);
invariant(
url,
'Invalid URL: cannot be empty'
);
}
}
module.exports = IntentAndroid;

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) 2015-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 IntentAndroid
*/
'use strict';
module.exports = {
openURI: function(url) {
console.error('IntentAndroid is not supported on iOS');
},
};

View File

@ -23,7 +23,7 @@ var _initialURL = RCTLinkingManager &&
var DEVICE_NOTIF_EVENT = 'openURL'; var DEVICE_NOTIF_EVENT = 'openURL';
/** /**
* `LinkingIOS` gives you a general interface to interact with both, incoming * `LinkingIOS` gives you a general interface to interact with both incoming
* and outgoing app links. * and outgoing app links.
* *
* ### Basic Usage * ### Basic Usage
@ -65,13 +65,13 @@ var DEVICE_NOTIF_EVENT = 'openURL';
* *
* #### Triggering App links * #### Triggering App links
* *
* To trigger an app link (browser, email or custom schemas) you call * To trigger an app link (browser, email or custom schemas), call
* *
* ``` * ```
* LinkingIOS.openURL(url) * LinkingIOS.openURL(url)
* ``` * ```
* *
* If you want to check if any installed app can handle a given url beforehand you can call * If you want to check if any installed app can handle a given URL beforehand you can call
* ``` * ```
* LinkingIOS.canOpenURL(url, (supported) => { * LinkingIOS.canOpenURL(url, (supported) => {
* if (!supported) { * if (!supported) {
@ -127,7 +127,7 @@ class LinkingIOS {
} }
/** /**
* Determine whether or not an installed app can handle a given `url` * Determine whether or not an installed app can handle a given URL.
* The callback function will be called with `bool supported` as the only argument * The callback function will be called with `bool supported` as the only argument
* *
* NOTE: As of iOS 9, your app needs to provide a `LSApplicationQueriesSchemes` key * NOTE: As of iOS 9, your app needs to provide a `LSApplicationQueriesSchemes` key

View File

@ -66,6 +66,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
Dimensions: require('Dimensions'), Dimensions: require('Dimensions'),
Easing: require('Easing'), Easing: require('Easing'),
ImagePickerIOS: require('ImagePickerIOS'), ImagePickerIOS: require('ImagePickerIOS'),
IntentAndroid: require('IntentAndroid'),
InteractionManager: require('InteractionManager'), InteractionManager: require('InteractionManager'),
LayoutAnimation: require('LayoutAnimation'), LayoutAnimation: require('LayoutAnimation'),
LinkingIOS: require('LinkingIOS'), LinkingIOS: require('LinkingIOS'),

View File

@ -0,0 +1,85 @@
/**
* Copyright (c) 2015-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.modules.intent;
import android.content.Intent;
import android.net.Uri;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
/**
* Intent module. Launch other activities or open URLs.
*/
public class IntentModule extends ReactContextBaseJavaModule {
public IntentModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "IntentAndroid";
}
/**
* Starts a corresponding external activity for the given URL.
*
* For example, if the URL is "https://www.facebook.com", the system browser will be opened,
* or the "choose application" dialog will be shown.
*
* @param URL the URL to open
*/
@ReactMethod
public void openURL(String url) {
if (url == null || url.isEmpty()) {
throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
}
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// We need Intent.FLAG_ACTIVITY_NEW_TASK since getReactApplicationContext() returns
// the ApplicationContext instead of the Activity context.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getReactApplicationContext().startActivity(intent);
} catch (Exception e) {
throw new JSApplicationIllegalArgumentException(
"Could not open URL '" + url + "': " + e.getMessage());
}
}
/**
* Determine whether or not an installed app can handle a given URL.
*
* @param URL the URL to open
* @param promise a promise that is always resolved with a boolean argument
*/
@ReactMethod
public void canOpenURL(String url, Callback callback) {
if (url == null || url.isEmpty()) {
throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
}
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// We need Intent.FLAG_ACTIVITY_NEW_TASK since getReactApplicationContext() returns
// the ApplicationContext instead of the Activity context.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
boolean canOpen =
intent.resolveActivity(this.getReactApplicationContext().getPackageManager()) != null;
callback.invoke(canOpen);
} catch (Exception e) {
throw new JSApplicationIllegalArgumentException(
"Could not check if URL '" + url + "' can be opened: " + e.getMessage());
}
}
}

View File

@ -18,6 +18,7 @@ import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.fresco.FrescoModule; import com.facebook.react.modules.fresco.FrescoModule;
import com.facebook.react.modules.intent.IntentModule;
import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.storage.AsyncStorageModule; import com.facebook.react.modules.storage.AsyncStorageModule;
import com.facebook.react.modules.toast.ToastModule; import com.facebook.react.modules.toast.ToastModule;
@ -47,6 +48,7 @@ public class MainReactPackage implements ReactPackage {
return Arrays.<NativeModule>asList( return Arrays.<NativeModule>asList(
new AsyncStorageModule(reactContext), new AsyncStorageModule(reactContext),
new FrescoModule(reactContext), new FrescoModule(reactContext),
new IntentModule(reactContext),
new NetworkingModule(reactContext), new NetworkingModule(reactContext),
new WebSocketModule(reactContext), new WebSocketModule(reactContext),
new ToastModule(reactContext)); new ToastModule(reactContext));