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:
parent
19f81be9b4
commit
e0019f69c1
|
@ -1276,4 +1276,4 @@
|
|||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTJavaScriptLoader.h"
|
||||
#import "RCTLinkingManager.h"
|
||||
#import "RCTRootView.h"
|
||||
|
||||
@interface AppDelegate() <RCTBridgeDelegate>
|
||||
|
@ -80,6 +81,14 @@
|
|||
return sourceURL;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
|
||||
{
|
||||
return [RCTLinkingManager application:application openURL:url
|
||||
sourceApplication:sourceApplication annotation:annotation];
|
||||
}
|
||||
|
||||
- (void)loadSourceForBridge:(RCTBridge *)bridge
|
||||
withBlock:(RCTSourceLoadBlock)loadCallback
|
||||
{
|
||||
|
|
|
@ -18,10 +18,28 @@
|
|||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.reactjs.ios</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>rnuiexplorer</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
@ -38,11 +56,5 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/-->
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -24,6 +24,7 @@ const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
|
|||
const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
|
||||
|
||||
const {
|
||||
Alert,
|
||||
Animated,
|
||||
AppRegistry,
|
||||
NavigationExperimental,
|
||||
|
@ -54,7 +55,36 @@ import type {
|
|||
UIExplorerExample,
|
||||
} from './UIExplorerList.ios'
|
||||
|
||||
function PathActionMap(path: string): ?Object {
|
||||
// Warning! Hacky parsing for example code. Use a library for this!
|
||||
const exampleParts = path.split('/example/');
|
||||
const exampleKey = exampleParts[1];
|
||||
if (exampleKey) {
|
||||
if (!UIExplorerList.Modules[exampleKey]) {
|
||||
Alert.alert(`${exampleKey} example could not be found!`);
|
||||
return null;
|
||||
}
|
||||
return UIExplorerActions.ExampleAction(exampleKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function URIActionMap(uri: ?string): ?Object {
|
||||
// Warning! Hacky parsing for example code. Use a library for this!
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
const parts = uri.split('rnuiexplorer:/');
|
||||
if (!parts[1]) {
|
||||
return null;
|
||||
}
|
||||
const path = parts[1];
|
||||
return PathActionMap(path);
|
||||
}
|
||||
|
||||
|
||||
class UIExplorerApp extends React.Component {
|
||||
_navigationRootRef: ?NavigationRootContainer;
|
||||
_renderNavigation: Function;
|
||||
componentWillMount() {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
|
@ -64,7 +94,9 @@ class UIExplorerApp extends React.Component {
|
|||
<NavigationRootContainer
|
||||
persistenceKey="UIExplorerState"
|
||||
reducer={UIExplorerNavigationReducer}
|
||||
ref={navRootRef => { this._navigationRootRef = navRootRef; }}
|
||||
renderNavigation={this._renderNavigation}
|
||||
linkingActionMap={URIActionMap}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue