You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:24:51