使用嵌套的 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,除此之外,但没有成功。我想去 EventHomeScreenPersonDetailScreenProgramSessionDetail

这是我的代码:

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.1react-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)