Add deep linking support to IntentAndroid

Summary:
Add a method to handle URLs registered to the app,

```js
IntentAndroid.getInitialURL(url => {
    if (url) {
        // do stuff
    }
});
```

Refer - http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters

The API cannot be same as the iOS API (i.e. as a constant), as the activity is not availble at the time of module initialization. Moreover, multiple activties can share the same bridge instance, and the activity itself is not a constant. Hence the initialURL can change.
Closes https://github.com/facebook/react-native/pull/4320

Reviewed By: svcscm

Differential Revision: D2759667

Pulled By: foghina

fb-gh-sync-id: b725231ae1401fa5565d444eee5a30d303e263ae
This commit is contained in:
Satyajit Sahoo 2015-12-15 06:26:51 -08:00 committed by facebook-github-bot-5
parent cf94a9ea95
commit eb188c8d98
2 changed files with 78 additions and 10 deletions

View File

@ -16,6 +16,26 @@ var invariant = require('invariant');
/**
* `IntentAndroid` gives you a general interface to handle external links.
*
* ### Basic Usage
*
* #### Handling deep links
*
* If your app was launched from an external url registered to your app you can
* access and handle it from any component you want with
*
* ```
* componentDidMount() {
* var url = IntentAndroid.getInitialURL(url => {
* if (url) {
* console.log('Initial url is: ' + url);
* }
* });
* }
* ```
*
* NOTE: For instructions on how to add support for deep linking,
* refer [Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters).
*
* #### Opening external links
*
* To start the corresponding activity for a link (web URL, email, contact etc.), call
@ -75,6 +95,20 @@ class IntentAndroid {
IntentAndroidModule.canOpenURL(url, callback);
}
/**
* If the app launch was triggered by an app link with {@code Intent.ACTION_VIEW},
* it will give the link url, otherwise it will give `null`
*
* Refer http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
*/
static getInitialURL(callback: Function) {
invariant(
typeof callback === 'function',
'A valid callback function is required'
);
IntentAndroidModule.getInitialURL(callback);
}
static _validateURL(url: string) {
invariant(
typeof url === 'string',

View File

@ -9,15 +9,15 @@
package com.facebook.react.modules.intent;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
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.
@ -33,25 +33,58 @@ public class IntentModule extends ReactContextBaseJavaModule {
return "IntentAndroid";
}
/**
* Return the URL the activity was started with
*
* @param callback a callback which is called with the initial URL
*/
@ReactMethod
public void getInitialURL(Callback callback) {
try {
Activity currentActivity = getCurrentActivity();
String initialURL = null;
if (currentActivity != null) {
Intent intent = currentActivity.getIntent();
String action = intent.getAction();
Uri uri = intent.getData();
if (Intent.ACTION_VIEW.equals(action) && uri != null) {
initialURL = uri.toString();
}
}
callback.invoke(initialURL);
} catch (Exception e) {
throw new JSApplicationIllegalArgumentException(
"Could not get the initial URL : " + e.getMessage());
}
}
/**
* 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
* @param url the URL to open
*/
@ReactMethod
public void openURL(String url) {
if (url == null || url.isEmpty()) {
throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
}
try {
Activity currentActivity = getCurrentActivity();
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.
if (currentActivity != null) {
currentActivity.startActivity(intent);
} else {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getReactApplicationContext().startActivity(intent);
}
} catch (Exception e) {
throw new JSApplicationIllegalArgumentException(
"Could not open URL '" + url + "': " + e.getMessage());
@ -61,21 +94,22 @@ public class IntentModule extends ReactContextBaseJavaModule {
/**
* 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
* @param url the URL to open
* @param callback a callback that is always called 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;
intent.resolveActivity(getReactApplicationContext().getPackageManager()) != null;
callback.invoke(canOpen);
} catch (Exception e) {
throw new JSApplicationIllegalArgumentException(