App linking for UIExplorer iOS

Summary: Add a simple URL parser to add linking support for UIExplorer iOS. Android should be very similar

Reviewed By: javache

Differential Revision: D2931764

fb-gh-sync-id: 0b029106160620267b82bdba510635ce224c5381
shipit-source-id: 0b029106160620267b82bdba510635ce224c5381
This commit is contained in:
Eric Vicenti
2016-02-22 16:15:44 -08:00
committed by facebook-github-bot-6
parent 19f81be9b4
commit e0019f69c1
6 changed files with 109 additions and 9 deletions

View File

@@ -164,7 +164,7 @@ class NavigationAnimatedView extends React.Component {
if (lastState) {
lastState.children.forEach((child, index) => {
if (!NavigationStateUtils.get(nextState, child.key)) {
if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) {
nextScenes.push({
index,
state: child,

View File

@@ -12,6 +12,7 @@
'use strict';
const AsyncStorage = require('AsyncStorage');
const Linking = require('Linking');
const React = require('React');
const BackAndroid = require('BackAndroid');
const Platform = require('Platform');
@@ -36,17 +37,44 @@ function getBackAction(): BackAction {
}
type Props = {
/*
* Set up the rendering of the app for a given navigation state
*/
renderNavigation: NavigationRenderer;
/*
* A function that will output the latest navigation state as a function of
* the (optional) previous state, and an action
*/
reducer: NavigationReducer;
/*
* Provide this key, and the container will store the navigation state in
* AsyncStorage through refreshes, with the provided key
*/
persistenceKey: ?string;
/*
* The default action to be passed into the reducer when getting the first
* state. Defaults to {type: 'RootContainerInitialAction'}
*/
initialAction: NavigationAction;
/*
* Provide linkingActionMap to instruct the container to subscribe to linking
* events, and use this mapper to convert URIs into actions that your app can
* handle
*/
linkingActionMap: (uri: string) => NavigationAction;
};
class NavigationRootContainer extends React.Component {
_handleOpenURLEvent: Function;
props: Props;
constructor(props: Props) {
super(props);
this.handleNavigation = this.handleNavigation.bind(this);
this._handleOpenURLEvent = this._handleOpenURLEvent.bind(this);
let navState = null;
if (!this.props.persistenceKey) {
navState = this.props.reducer(null, props.initialAction);
@@ -54,6 +82,10 @@ class NavigationRootContainer extends React.Component {
this.state = { navState };
}
componentDidMount() {
if (this.props.LinkingActionMap) {
Linking.getInitialURL().then(this._handleOpenURL.bind(this));
Platform.OS === 'ios' && Linking.addEventListener('url', this._handleOpenURLEvent);
}
if (this.props.persistenceKey) {
AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
if (err || !storedString) {
@@ -68,6 +100,21 @@ class NavigationRootContainer extends React.Component {
});
}
}
componentWillUnmount() {
Platform.OS === 'ios' && Linking.removeEventListener('url', this._handleOpenURLEvent);
}
_handleOpenURLEvent(event: {url: string}) {
this._handleOpenURL(event.url);
}
_handleOpenURL(url: ?string) {
if (!this.props.LinkingActionMap) {
return;
}
const action = this.props.LinkingActionMap(url);
if (action) {
this.handleNavigation(action);
}
}
getChildContext(): Object {
return {
onNavigate: this.handleNavigation,
@@ -101,7 +148,7 @@ NavigationRootContainer.childContextTypes = {
NavigationRootContainer.defaultProps = {
initialAction: {
type: 'NavigationRootContainerInitialAction',
type: 'RootContainerInitialAction',
},
};