繁体   English   中英

如何使用路由处理 Flutter 中的深层链接

[英]How to handle deeplinking in Flutter using routes

我正在尝试构建深层链接功能,到目前为止,应用程序的初始启动和从深层链接中检索参数都进行得很好。

但是,在我深层链接到应用程序后,我在导航到屏幕时遇到了问题。 我该怎么做?

我的代码如下所示:

void main() { 
    runApp(MyApp()); 
}

class MyApp extends StatefulWidget {   
    @override   
    _MyAppState createState() => _MyAppState(); 
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {   
   Uri _latestUri;  
   Object _err;

  StreamSubscription _sub;

  @override   void initState() {
    super.initState();
    _handleIncomingLinks();
  }

  @override void dispose() {
    _sub?.cancel();
    super.dispose();   
  }

  void _handleIncomingLinks() {
    _sub = uriLinkStream.listen((Uri uri) {
      if (!mounted) return;
      print('got uri: $uri'); // printed: got uri: myapp://?key1=test
      setState(() {
        _latestUri = uri;
        _err = null;

        Navigator.pushNamed(context, 'login'); // This doesn't work because the context does not include navigator
      });
    }, onError: (Object err) {
      if (!mounted) return;
      print('got err: $err');
      setState(() {
        _latestUri = null;
        if (err is FormatException) {
          _err = err;
        } else {
          _err = null;
        }
      });
    });   
  }

  @override Widget build(BuildContext context) {
    return MaterialApp(
          initialRoute: 'splash-screen',
          onGenerateRoute: (settings) {
            switch (settings.name) {
              case 'splash-screen':
                return
                  PageTransition(
                        child: BlocProvider(
                          create: (context) => SplashScreenCubit(APIRepository(
                              apiClient: APIClient(httpClient: http.Client()))),
                          child: SplashScreen(),
                        ),
                        type: PageTransitionType.rightToLeft,
                        settings: settings);
                break;
              case 'create-account':
                return PageTransition(
                    child: BlocProvider(
                      create: (context) => CreateAccountScreenCubit(
                          APIRepository(
                              apiClient: APIClient(httpClient: http.Client()))),
                      child: CreateAccountScreen(),
                    ),
                    type: PageTransitionType.rightToLeft,
                    settings: settings);
                break;
              case 'login':
                return PageTransition(
                        child: BlocProvider(
                          create: (context) => LoginScreenCubit(APIRepository(
                              apiClient: APIClient(httpClient: http.Client()))),
                          child: LoginScreen(),
                        ),
                        type: PageTransitionType.rightToLeft,
                        settings: settings);
                break;
              default:
                 return null;
           },
        );
     }
  }

如果您需要的是能够在不从Navigtor.of获取上下文的情况下进行导航,因为您想处理深层链接,则需要使用navigatorKey属性,您可以在此处阅读详细信息。

那么你的代码将是这样的

void main() { ... }

class MyApp extends StatefulWidget { ... }

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {   
   Uri _latestUri;  
   Object _err;
   GlobalKey<NavigatorState> navigatorKey = GlobalKey();

  StreamSubscription _sub;

  @override   void initState() { ... }

  @override void dispose() { ... }

  void _handleIncomingLinks() {
     _sub = uriLinkStream.listen((Uri uri) {
      if (!mounted) return;
      print('got uri: $uri'); // printed: got uri: myapp://?key1=test
      setState(() {
        _latestUri = uri;
        _err = null;
      });

      // use the navigatorkey currentstate to navigate to the page you are intended to visit
      navigatorKey.currentState.pushNamedAndRemoveUntil('login', (route) => false);
    }, onError: (Object err) { ... });

  @override Widget build(BuildContext context) { ... }

}

你的深度链接流可以在 build 方法之前触发,但此时你不能调用Navigator 所以,你可以使用修复它addPostFrameCallback提供SchedulerBinding

添加PostFrameCallback

在此帧结束时安排回调。

不请求新帧。

此回调在帧期间运行,紧接在持久帧回调之后(即主渲染管道已刷新的时间)。 如果帧正在进行中并且尚未执行帧后回调,则在帧期间仍会执行已注册的回调。 否则,注册的回调将在下一帧期间执行。

回调按添加顺序执行。

不能取消注册帧后回调。 它们只被调用一次。

...

void _handleIncomingLinks() {
  _sub = uriLinkStream.listen((Uri uri) {
    if (!mounted) return;
    print('got uri: $uri'); // printed: got uri: myapp://?key1=test
    setState(() {
      _latestUri = uri;
      _err = null;

      // Call your navigator inside addPostFrameCallback
      WidgetsBinding.instance?.addPostFrameCallback((_) {
        Navigator.pushNamed(context, 'login');
      });
    });
  }, onError: (Object err) {
    if (!mounted) return;
    print('got err: $err');
    setState(() {
      _latestUri = null;
      if (err is FormatException) {
        _err = err;
      } else {
        _err = null;
      }
    });
  });
}

...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM