Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal Linking component #4546

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Examples/UIExplorer/XHRExample.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var {
AlertIOS,
CameraRoll,
Image,
LinkingIOS,
Linking,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

property Linking Property not found in Object.create

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the bot linting against my PR branch or master?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

property Linking Property not found in Object.create

PixelRatio,
ProgressViewIOS,
StyleSheet,
Expand Down Expand Up @@ -210,7 +210,7 @@ class FormUploader extends React.Component {
return;
}
var url = xhr.responseText.slice(index).split('\n')[0];
LinkingIOS.openURL(url);
Linking.openURL(url);
};
var formdata = new FormData();
if (this.state.randomPhoto) {
Expand Down
188 changes: 188 additions & 0 deletions Libraries/Components/Linking/Linking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/**
* 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 Linking
* @flow
*/
'use strict';

var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var Platform = require('Platform');

if (Platform.OS === 'android') {
var RCTLinking = require('NativeModules').IntentAndroid;
} else {
var RCTLinking = require('NativeModules').LinkingManager;
}

var Map = require('Map');
var invariant = require('invariant');

var _notifHandlers = new Map();
var _initialURL = RCTLinking.initialURL;

var DEVICE_NOTIF_EVENT = 'openURL';

/**
* `Linking` gives you a general interface to interact with both incoming
* and outgoing app 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 = Linking.popInitialURL();
* }
* ```
*
* In case you also want to listen to incoming app links during your app's
* execution you'll need to add the following lines to you `*AppDelegate.m`:
*
* ```
* - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
* sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
* {
* return [RCTLinkingManager application:application openURL:url
* sourceApplication:sourceApplication annotation:annotation];
* }
*
* // Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
* - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
* restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
* {
* return [RCTLinkingManager application:application
* continueUserActivity:userActivity
* restorationHandler:restorationHandler];
* }
*
* ```
*
* And then on your React component you'll be able to listen to the events on
* `Linking` as follows
*
* ```
* componentDidMount() {
* Linking.addEventListener('url', this._handleOpenURL);
* },
* componentWillUnmount() {
* Linking.removeEventListener('url', this._handleOpenURL);
* },
* _handleOpenURL(event) {
* console.log(event.url);
* }
* ```
*
* #### Triggering App links
*
* To trigger an app link (browser, email or custom schemas), call
*
* ```
* Linking.openURL(url)
* ```
*
* If you want to check if any installed app can handle a given URL beforehand, call
* ```
* Linking.canOpenURL(url, (supported) => {
* if (!supported) {
* AlertIOS.alert('Can\'t handle url: ' + url);
* } else {
* Linking.openURL(url);
* }
* });
* ```
*/
class Linking {
/**
* Add a handler to Linking changes by listening to the `url` event type
* and providing the handler
* @platform ios
*/
static addEventListener(type: string, handler: Function) {
invariant(
type === 'url',
'Linking only supports `url` events'
);
var listener = RCTDeviceEventEmitter.addListener(
DEVICE_NOTIF_EVENT,
handler
);
_notifHandlers.set(handler, listener);
}

/**
* Remove a handler by passing the `url` event type and the handler
* @platform ios
*/
static removeEventListener(type: string, handler: Function ) {
invariant(
type === 'url',
'Linking only supports `url` events'
);
var listener = _notifHandlers.get(handler);
if (!listener) {
return;
}
listener.remove();
_notifHandlers.delete(handler);
}

/**
* Try to open the given `url` with any of the installed apps.
*/
static openURL(url: string) {
this._validateURL(url);
RCTLinking.openURL(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
*
* NOTE: As of iOS 9, your app needs to provide the `LSApplicationQueriesSchemes` key
* inside `Info.plist`.
*
* @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'
);
RCTLinking.canOpenURL(url, callback);
}

/**
* If the app launch was triggered by an app link, it will pop the link url,
* otherwise it will return `null`
* On Android, Refer http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
*/
static popInitialURL(): ?string {
var initialURL = _initialURL;
_initialURL = null;
return initialURL;
}

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 = Linking;
1 change: 1 addition & 0 deletions Libraries/react-native/react-native.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ var ReactNative = {
get InteractionManager() { return require('InteractionManager'); },
get LayoutAnimation() { return require('LayoutAnimation'); },
get LinkingIOS() { return require('LinkingIOS'); },
get Linking() { return require('Linking'); },
get NetInfo() { return require('NetInfo'); },
get PanResponder() { return require('PanResponder'); },
get PixelRatio() { return require('PixelRatio'); },
Expand Down
1 change: 1 addition & 0 deletions Libraries/react-native/react-native.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
InteractionManager: require('InteractionManager'),
LayoutAnimation: require('LayoutAnimation'),
LinkingIOS: require('LinkingIOS'),
Linking: require('Linking'),
NetInfo: require('NetInfo'),
PanResponder: require('PanResponder'),
PixelRatio: require('PixelRatio'),
Expand Down