使用嵌套的 DrawerNavigator、TabNavigator 和 StackNavigator 进行深度链接
Deeplink with nested DrawerNavigator, TabNavigator and StackNavigator
我正在尝试为我的 React Native 应用程序配置深层链接,遵循 official documentation, but I haven't been able to make it work. I mean, the app does open if I run adb shell am start -W -a android.intent.action.VIEW -d “crf://" packageName
or xcrun simctl openurl booted crf://
but I haven't been able to open a specific screen; it always launches to the app home screen. I'm almost sure it has to do with the nested navigators, since I have a TabbarNavigator
inside a DrawerNavigator
and a StackNavigator
inside all of that. I followed the instructions regarding nested navigators in the documentation and also this post,除此之外,但没有成功。我想去 EventHomeScreen
、PersonDetailScreen
和 ProgramSessionDetail
这是我的代码:
NavigatorRouter
const mainNavigator = createStackNavigator(
{
[Constants.APP_HOME_SCENE_KEY]:{
screen: AppHomeScreen,
navigationOptions: {
title: 'App Home',
showBack: false,
showSearch: false,
},
path: ''
},
[Constants.EVENT_HOME_SCENE_KEY]:{
screen: navPropMapper()(EventHomeScreen),
navigationOptions:{
title: 'Home',
path: 'event'
}
},
[Constants.ATTENDEE_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(PersonDetailScreen),
navigationOptions:{
title: 'Attendee Detail',
// path: 'person/:user'
path: 'person'
}
},
[Constants.PROGRAM_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(ProgramSessionDetail),
navigationOptions:{
title: 'Program',
path: 'program/:idLecture'
}
}
},
{
initialRouteName: `${Constants.APP_HOME_SCENE_KEY}`,
defaultNavigationOptions: {
header: props => <NavBar {...props} />,
gesturesEnabled: false,
showBack: true,
showHome: false,
showSearch: true,
showWebExplorer: false
}
});
const tabbarNavigator = createBottomTabNavigator({
Main: {
screen: mainNavigator,
path: 'tabs'
},
}, {
tabBarComponent: Tabbar,
});
const drawerNavigator = createDrawerNavigator({
Drawer: {
screen: tabbarNavigator,
navigationOptions:{
drawerLockMode: 'locked-closed',
},
path: 'drawer'
},
}, {
contentComponent: ({ props }) => <DrawerContainer {...props}/>,
drawerPosition: 'right',
unmountInactiveRoutes: true,
defaultNavigationOptions: {
header: null,
}
});
const wraperNavigator = createStackNavigator({
MainComponents: {
screen: drawerNavigator,
path: 'main'
},
[Constants.MODAL_FEEDBACK]:{
screen: navPropMapper()(Modal),
navigationOptions:{
title: 'Feedback',
}
},
[Constants.MODAL_LOGIN]:{
screen: navPropMapper()(ModalLogin),
navigationOptions:{
title: 'Login',
}
},
}, {
mode: 'modal',
cardStyle:{
backgroundColor: 'transparent',
opacity: 1,
},
cardShadowEnabled: true,
cardOverlayEnabled: true,
transparentCard: true,
defaultNavigationOptions: {
header: null,
gesturesEnabled: false,
},
});
export default createAppContainer(wraperNavigator)
App.js
class App extends Component {
render () {
return (
<Provider store={store}>
<RootContainer />
</Provider>
)
}
}
export default App
根容器
class CRrootContainer extends Component {
render () {
return (
<View style={styles.applicationView}>
<NavigationRouter uriPrefix={'crf://'}/>
</View>
)
}
}
const mapStateToProps = (state) => {
return {
navState: state.navigation,
}
}
// wraps redux integration
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
})
export default connect(mapStateToProps, mapDispatchToProps)(rootContainer)
iOS URI 和方案
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];
}
URL 类型:
Android方案:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="packageName">
<application
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="crf"/>
</intent-filter>
</activity>
</application>
</manifest>
我正在尝试的命令是:
xcrun simctl openurl booted crf://main/drawer/tabs/event
对于 iOS.
和
adb shell am start -W -a android.intent.action.VIEW -d “crf://main/drawer/tabs/event" packageName
for Android(packageName是我的应用包的名字`
我的 react-navigation
版本是 3.6.1
和 react-native: 0.59.9
.
你能尝试设置一个事件侦听器吗?
class CRrootContainer extends Component {
async componentDidMount(){
if (Platform.OS === "android") {
let url = await Linking.getInitialURL();
if(url) this._setDeepLink(url);
} else {
Linking.addEventListener("url", this._handleOpenURL);
}
};
_handleOpenURL = event => {
this._setDeepLink(event.url);
};
_setDeepLink = url => {
const { navigate } = this.props.navigation;
const route = url.replace(/.*?:\/\//g, "");
const routeName = route.split("/")[0];
console.log("root====>", routeName);
if (routeName === "foo") {
navigate("fooRoute"); // to navigate route based on deep link url
}
};
componentWillUnmount() {
Linking.removeEventListener("url");
}
render () {
return (
<View style={styles.applicationView}>
<NavigationRouter uriPrefix={'crf://'}/>
</View>
)
}
}
const mapStateToProps = (state) => {
return {
navState: state.navigation,
}
}
// wraps redux integration
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
})
export default connect(mapStateToProps, mapDispatchToProps)(rootContainer)
所以它最终成为一个菜鸟错误,将 path:
关键字放在错误的位置;它需要在 navigationOptions 之外,而不是在里面。此外,抽屉导航器和标签栏导航器上的路径值应为空。
const mainNavigator = createStackNavigator(
{
[Constants.APP_HOME_SCENE_KEY]:{
screen: AppHomeScreen,
navigationOptions: {
title: 'App Home',
showBack: false,
showSearch: false,
},
path: ''
},
[Constants.EVENT_HOME_SCENE_KEY]:{
screen: navPropMapper()(EventHomeScreen),
navigationOptions:{
title: 'Home',
},
path: 'event'
},
[Constants.ATTENDEE_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(PersonDetailScreen),
navigationOptions:{
title: 'Attendee Detail'
},
path: 'person'
},
[Constants.PROGRAM_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(ProgramSessionDetail),
navigationOptions:{
title: 'Program'
},
path: 'program/:idLecture'
}
},
{
initialRouteName: `${Constants.APP_HOME_SCENE_KEY}`,
defaultNavigationOptions: {
header: props => <NavBar {...props} />,
gesturesEnabled: false,
showBack: true,
showHome: false,
showSearch: true,
showWebExplorer: false
}
});
const tabbarNavigator = createBottomTabNavigator({
Main: {
screen: mainNavigator,
path: ''
},
}, {
tabBarComponent: Tabbar,
});
const drawerNavigator = createDrawerNavigator({
Drawer: {
screen: tabbarNavigator,
navigationOptions:{
drawerLockMode: 'locked-closed',
},
path: ''
},
}, {
contentComponent: ({ props }) => <DrawerContainer {...props}/>,
drawerPosition: 'right',
unmountInactiveRoutes: true,
defaultNavigationOptions: {
header: null,
}
});
const wraperNavigator = createStackNavigator({
MainComponents: {
screen: drawerNavigator,
path: ''
},
[Constants.MODAL_FEEDBACK]:{
screen: navPropMapper()(Modal),
navigationOptions:{
title: 'Feedback',
}
},
[Constants.MODAL_LOGIN]:{
screen: navPropMapper()(ModalLogin),
navigationOptions:{
title: 'Login',
}
},
}, {
mode: 'modal',
cardStyle:{
backgroundColor: 'transparent',
opacity: 1,
},
cardShadowEnabled: true,
cardOverlayEnabled: true,
transparentCard: true,
defaultNavigationOptions: {
header: null,
gesturesEnabled: false,
},
});
export default createAppContainer(wraperNavigator)
我正在尝试为我的 React Native 应用程序配置深层链接,遵循 official documentation, but I haven't been able to make it work. I mean, the app does open if I run adb shell am start -W -a android.intent.action.VIEW -d “crf://" packageName
or xcrun simctl openurl booted crf://
but I haven't been able to open a specific screen; it always launches to the app home screen. I'm almost sure it has to do with the nested navigators, since I have a TabbarNavigator
inside a DrawerNavigator
and a StackNavigator
inside all of that. I followed the instructions regarding nested navigators in the documentation and also this post,除此之外,但没有成功。我想去 EventHomeScreen
、PersonDetailScreen
和 ProgramSessionDetail
这是我的代码:
NavigatorRouter
const mainNavigator = createStackNavigator(
{
[Constants.APP_HOME_SCENE_KEY]:{
screen: AppHomeScreen,
navigationOptions: {
title: 'App Home',
showBack: false,
showSearch: false,
},
path: ''
},
[Constants.EVENT_HOME_SCENE_KEY]:{
screen: navPropMapper()(EventHomeScreen),
navigationOptions:{
title: 'Home',
path: 'event'
}
},
[Constants.ATTENDEE_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(PersonDetailScreen),
navigationOptions:{
title: 'Attendee Detail',
// path: 'person/:user'
path: 'person'
}
},
[Constants.PROGRAM_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(ProgramSessionDetail),
navigationOptions:{
title: 'Program',
path: 'program/:idLecture'
}
}
},
{
initialRouteName: `${Constants.APP_HOME_SCENE_KEY}`,
defaultNavigationOptions: {
header: props => <NavBar {...props} />,
gesturesEnabled: false,
showBack: true,
showHome: false,
showSearch: true,
showWebExplorer: false
}
});
const tabbarNavigator = createBottomTabNavigator({
Main: {
screen: mainNavigator,
path: 'tabs'
},
}, {
tabBarComponent: Tabbar,
});
const drawerNavigator = createDrawerNavigator({
Drawer: {
screen: tabbarNavigator,
navigationOptions:{
drawerLockMode: 'locked-closed',
},
path: 'drawer'
},
}, {
contentComponent: ({ props }) => <DrawerContainer {...props}/>,
drawerPosition: 'right',
unmountInactiveRoutes: true,
defaultNavigationOptions: {
header: null,
}
});
const wraperNavigator = createStackNavigator({
MainComponents: {
screen: drawerNavigator,
path: 'main'
},
[Constants.MODAL_FEEDBACK]:{
screen: navPropMapper()(Modal),
navigationOptions:{
title: 'Feedback',
}
},
[Constants.MODAL_LOGIN]:{
screen: navPropMapper()(ModalLogin),
navigationOptions:{
title: 'Login',
}
},
}, {
mode: 'modal',
cardStyle:{
backgroundColor: 'transparent',
opacity: 1,
},
cardShadowEnabled: true,
cardOverlayEnabled: true,
transparentCard: true,
defaultNavigationOptions: {
header: null,
gesturesEnabled: false,
},
});
export default createAppContainer(wraperNavigator)
App.js
class App extends Component {
render () {
return (
<Provider store={store}>
<RootContainer />
</Provider>
)
}
}
export default App
根容器
class CRrootContainer extends Component {
render () {
return (
<View style={styles.applicationView}>
<NavigationRouter uriPrefix={'crf://'}/>
</View>
)
}
}
const mapStateToProps = (state) => {
return {
navState: state.navigation,
}
}
// wraps redux integration
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
})
export default connect(mapStateToProps, mapDispatchToProps)(rootContainer)
iOS URI 和方案
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];
}
URL 类型:
Android方案:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="packageName">
<application
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="crf"/>
</intent-filter>
</activity>
</application>
</manifest>
我正在尝试的命令是:
xcrun simctl openurl booted crf://main/drawer/tabs/event
对于 iOS.
和
adb shell am start -W -a android.intent.action.VIEW -d “crf://main/drawer/tabs/event" packageName
for Android(packageName是我的应用包的名字`
我的 react-navigation
版本是 3.6.1
和 react-native: 0.59.9
.
你能尝试设置一个事件侦听器吗?
class CRrootContainer extends Component {
async componentDidMount(){
if (Platform.OS === "android") {
let url = await Linking.getInitialURL();
if(url) this._setDeepLink(url);
} else {
Linking.addEventListener("url", this._handleOpenURL);
}
};
_handleOpenURL = event => {
this._setDeepLink(event.url);
};
_setDeepLink = url => {
const { navigate } = this.props.navigation;
const route = url.replace(/.*?:\/\//g, "");
const routeName = route.split("/")[0];
console.log("root====>", routeName);
if (routeName === "foo") {
navigate("fooRoute"); // to navigate route based on deep link url
}
};
componentWillUnmount() {
Linking.removeEventListener("url");
}
render () {
return (
<View style={styles.applicationView}>
<NavigationRouter uriPrefix={'crf://'}/>
</View>
)
}
}
const mapStateToProps = (state) => {
return {
navState: state.navigation,
}
}
// wraps redux integration
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
})
export default connect(mapStateToProps, mapDispatchToProps)(rootContainer)
所以它最终成为一个菜鸟错误,将 path:
关键字放在错误的位置;它需要在 navigationOptions 之外,而不是在里面。此外,抽屉导航器和标签栏导航器上的路径值应为空。
const mainNavigator = createStackNavigator(
{
[Constants.APP_HOME_SCENE_KEY]:{
screen: AppHomeScreen,
navigationOptions: {
title: 'App Home',
showBack: false,
showSearch: false,
},
path: ''
},
[Constants.EVENT_HOME_SCENE_KEY]:{
screen: navPropMapper()(EventHomeScreen),
navigationOptions:{
title: 'Home',
},
path: 'event'
},
[Constants.ATTENDEE_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(PersonDetailScreen),
navigationOptions:{
title: 'Attendee Detail'
},
path: 'person'
},
[Constants.PROGRAM_DETAIL_SCENE_KEY]:{
screen: navPropMapper()(ProgramSessionDetail),
navigationOptions:{
title: 'Program'
},
path: 'program/:idLecture'
}
},
{
initialRouteName: `${Constants.APP_HOME_SCENE_KEY}`,
defaultNavigationOptions: {
header: props => <NavBar {...props} />,
gesturesEnabled: false,
showBack: true,
showHome: false,
showSearch: true,
showWebExplorer: false
}
});
const tabbarNavigator = createBottomTabNavigator({
Main: {
screen: mainNavigator,
path: ''
},
}, {
tabBarComponent: Tabbar,
});
const drawerNavigator = createDrawerNavigator({
Drawer: {
screen: tabbarNavigator,
navigationOptions:{
drawerLockMode: 'locked-closed',
},
path: ''
},
}, {
contentComponent: ({ props }) => <DrawerContainer {...props}/>,
drawerPosition: 'right',
unmountInactiveRoutes: true,
defaultNavigationOptions: {
header: null,
}
});
const wraperNavigator = createStackNavigator({
MainComponents: {
screen: drawerNavigator,
path: ''
},
[Constants.MODAL_FEEDBACK]:{
screen: navPropMapper()(Modal),
navigationOptions:{
title: 'Feedback',
}
},
[Constants.MODAL_LOGIN]:{
screen: navPropMapper()(ModalLogin),
navigationOptions:{
title: 'Login',
}
},
}, {
mode: 'modal',
cardStyle:{
backgroundColor: 'transparent',
opacity: 1,
},
cardShadowEnabled: true,
cardOverlayEnabled: true,
transparentCard: true,
defaultNavigationOptions: {
header: null,
gesturesEnabled: false,
},
});
export default createAppContainer(wraperNavigator)