如何从原生iOS Widget跳转至Flutter应用指定页面
解决Flutter Widget跳转指定路由的问题
问题原因
Widget点击链接只能打开Flutter初始路由,是因为Flutter默认的routes配置仅处理App内部导航跳转,不会自动解析外部URL Scheme传递的路由信息。需要同时配置iOS侧的URL Scheme,并在Flutter侧添加外部链接的处理逻辑。
解决步骤
1. 确认iOS项目的URL Scheme配置
打开iOS/Runner/Info.plist,添加URL Scheme配置(确保CFBundleURLSchemes的值和你pubspec.yaml里的应用名一致,这里是interval_timer):
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>interval_timer</string> </array> <key>CFBundleURLName</key> <string>你的Bundle ID</string> <!-- 替换成你项目的Bundle ID,比如com.yourname.intervaltimer --> </dict> </array>
2. 修改Widget中的Link URL
调整Swift代码里的链接,把目标路由通过参数传递给Flutter,形式更灵活:
Link(destination: URL(string: "interval_timer://deeplink?route=/profile")!) { Text(intervalString) }
也可以直接用路径形式:interval_timer:///profile,后续解析时取URL的path即可。
3. Flutter侧添加Deep Link处理逻辑
需要监听App冷启动和后台唤醒时的外部URL,解析后跳转到对应路由。这里用原生MethodChannel实现,无需依赖第三方库:
第一步:iOS侧传递URL到Flutter
打开iOS/Runner/AppDelegate.swift,添加URL处理代码:
import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) // 处理冷启动时的URL if let url = launchOptions?[.url] as? URL { let channel = FlutterMethodChannel(name: "com.yourname.interval_timer/deeplink", binaryMessenger: window?.rootViewController as! FlutterViewController) channel.invokeMethod("handleDeepLink", arguments: url.absoluteString) } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // 处理App从后台唤醒时的URL override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let channel = FlutterMethodChannel(name: "com.yourname.interval_timer/deeplink", binaryMessenger: window?.rootViewController as! FlutterViewController) channel.invokeMethod("handleDeepLink", arguments: url.absoluteString) return true } }
注意把com.yourname.interval_timer/deeplink里的Bundle ID部分替换成你自己的。
第二步:Flutter侧监听并处理路由
修改你的Flutter主页面代码,添加MethodChannel监听和路由处理:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> with WidgetsBindingObserver { late MethodChannel _deepLinkChannel; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); // 初始化MethodChannel,名称要和iOS侧一致 _deepLinkChannel = const MethodChannel('com.yourname.interval_timer/deeplink'); _deepLinkChannel.setMethodCallHandler(_handleDeepLink); } Future<void> _handleDeepLink(MethodCall call) async { if (call.method == 'handleDeepLink') { final String link = call.arguments as String; final Uri uri = Uri.parse(link); // 解析路由参数(对应Widget里的?route=/profile) final String? targetRoute = uri.queryParameters['route']; if (targetRoute != null && mounted) { // 跳转目标路由,如果App已在后台,用pushReplacement避免重复栈 if (Navigator.of(context).canPop()) { Navigator.pushReplacementNamed(context, targetRoute); } else { Navigator.pushNamed(context, targetRoute); } } } } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // 确保App从后台唤醒时能处理最新的链接 if (state == AppLifecycleState.resumed) { // 可在此主动触发链接检查,比如通过channel调用iOS侧获取最新链接 } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/workouts', routes: { '/workouts': (context) => const Home(screenIndex: 0), '/jumpin': (context) => const Home(screenIndex: 1), '/profile': (context) => const Home(screenIndex: 2), }, ); } } // 你的Home组件 class Home extends StatelessWidget { final int screenIndex; const Home({super.key, required this.screenIndex}); @override Widget build(BuildContext context) { return Scaffold( body: Center(child: Text('Screen $screenIndex')), ); } }
4. 测试验证
重新运行iOS项目,添加Widget到桌面,点击链接后应该能直接跳转到/profile页面,无论App是冷启动还是后台唤醒状态。
内容的提问来源于stack exchange,提问作者Nikita
相关产品推荐
相关产品推荐

