Flutter iOS端结合GetX与app_links实现Deep Link时重复推送同一页面(Android端正常)
Flutter iOS端结合GetX与app_links实现Deep Link时重复推送同一页面(Android端正常)
兄弟,我看了你这个问题,iOS下杀后台打开Deep Link会重复push同一个页面,Android却正常,这情况我之前做项目时也碰到过,结合你贴的代码和日志分析,大概率是冷启动时Splash的初始化逻辑和Deep Link的处理逻辑撞车了,而且Deep Link的处理可能被触发了两次,咱们一步步来解决:
问题根源拆解
从你描述的日志和代码来看:
- iOS冷启动打开Deep Link时,
ControllerSplash的getLocalData()(带延迟跳转)和DeepLinkingService的链接监听同时运行 - 你的
DeepLinkingService里同时用了getInitialLink()(冷启动获取初始链接)和uriLinkStream(监听运行时链接),iOS在冷启动时这两个可能会同时返回同一个Deep Link,导致两次处理路由 - 另外Splash里的延迟跳转逻辑没有考虑Deep Link的情况,可能会在Deep Link跳转后,又触发一次路由冲突
具体修复方案
1. 给DeepLinkingService加重复处理防护,避免同一链接被处理两次
修改你的controller_deep_linking.dart,记录已经处理过的链接,同时区分冷启动初始链接和stream链接,避免重复触发:
class DeepLinkingService extends GetxService { final AppLinks _appLinks = AppLinks(); Uri? _pendingUri; bool _isAppInitialized = false; bool _isProcessingLink = false; Uri? _processedInitialUri; // 新增:记录已处理的初始链接 bool get isProcessingLink => _isProcessingLink; bool get hasPendingLink => _pendingUri != null; Future<DeepLinkingService> init() async { AppLog.i("Initializing DeepLinkingService"); // 先处理冷启动的初始链接 final initialUri = await _appLinks.getInitialLink(); if (initialUri != null) { _processedInitialUri = initialUri; if (_isAppInitialized) { await _handleDeepLink(initialUri); } else { _pendingUri = initialUri; } } // 监听运行时的链接流,过滤掉已处理的初始链接 _appLinks.uriLinkStream.listen((Uri? uri) async { AppLog.i("Received URI while app running: $uri"); if (uri != null && uri != _processedInitialUri) { // 新增判断:跳过已处理的初始链接 if (_isAppInitialized) { await _handleDeepLink(uri); } else { _pendingUri = uri; } } }); return this; } // 处理appReady的方法,确保只处理一次pending链接 void appReady() { _isAppInitialized = true; if (_pendingUri != null && !_isProcessingLink) { _handleDeepLink(_pendingUri!); _pendingUri = null; // 处理后清空pending链接,避免重复处理 } } // 处理Deep Link的核心方法,加锁避免并行处理 Future<void> _handleDeepLink(Uri uri) async { if (_isProcessingLink) return; _isProcessingLink = true; try { AppLog.i("Processing deep link: $uri"); // 你的路由处理逻辑,比如跳转到instructor_detail await Get.toNamed(uri.path, parameters: uri.queryParameters); } catch (e) { AppLog.e("Error handling deep link: $e"); } finally { _isProcessingLink = false; } } }
2. 调整Splash页面的延迟跳转逻辑,优先响应Deep Link
修改controller_splash.dart里的getLocalData(),当存在pending的Deep Link时,取消默认的延迟跳转,让Deep Link优先处理:
getLocalData() async { SharedPreferences preferences = await SharedPreferences.getInstance(); bool? isFirstTime = await AppPreference.readBool(AppPreference.isUsersFirstTime) ?? true; // 新增:检查是否有pending的Deep Link,如果有就跳过默认跳转 final deepLinkService = Get.find<DeepLinkingService>(); if (deepLinkService.hasPendingLink) { AppLog.i("Pending deep link found, skipping default splash navigation"); return; } // 下面是你原来的跳转逻辑,保持不变 if (isFirstTime) { await AppPreference.writeBool(AppPreference.isUsersFirstTime, false); Future.delayed( const Duration(seconds: 2), () { Get.offAndToNamed(ScreenOnboarding.pageId); }, ); } else if (preferences.containsKey(AppPreference.authToken)) { // ... 你的原有代码 } else { // ... 你的原有代码 } }
3. 确保Splash的onClose()正确触发appReady
现在你的onClose()里已经调用了deepLinkService.appReady(),这个是对的,确保当Splash页面关闭后(也就是app初始化完成),再处理pending的Deep Link,避免在Splash还没加载完时就跳转,导致路由冲突。
额外注意点
- iOS的info.plist里要正确配置Deep Link的关联域名(Associated Domains),确保链接能正确被app捕获
- 测试时一定要彻底杀死app(划掉后台)再测试冷启动的Deep Link,因为后台运行时的逻辑和冷启动不一样
- GetX的路由跳转尽量用
Get.offAndToNamed或者Get.toNamed时加参数避免重复页面,不过核心还是解决重复触发的问题
这样修改后,应该就能解决iOS端重复push页面的问题了,你可以先试试这几个调整~
内容来源于stack exchange
相关产品推荐
相关产品推荐

