iOS这里要用友盟生成的链接,别自己填,很坑。
在这里插入图片描述

面向开发者和 Agent 的可执行排障指南

一句话结论

这次问题的核心不是微信 SDK 或 QQ SDK 挂了,而是 iOS 回调在 AppDelegate 被 UMLink 提前消费,Flutter 插件链没有机会继续分发,所以 Dart 侧一直等不到 _onWeChatResp/_onQqResp


先回答关键问题:为什么 Flutter 项目更容易出现这类问题

结论

严格说,这类“回调被提前吃掉”的问题不是 Flutter 独有;原生 iOS 也可能发生。
但在 Flutter 项目里,出现概率更高、定位成本更大,原因是回调链更长,多了一层“原生到 Flutter 插件分发”。

Flutter 场景下的真实链路

  1. iOS 系统把回调先交给 AppDelegate
  2. AppDelegate 里若调用 super.application(...),Flutter 的插件生命周期分发器才会继续把事件传给插件。
  3. fluwx / tencent_kit 接到回调后,再通过事件流传到 Dart。
  4. Dart 侧 LoginUtil 中的 completer 才会被 _onWeChatResp/_onQqResp 完成。

只要第 2 步被提前 return true 截断,第 3、4 步都不会发生,最终就是:

  • 用户感知:授权后卡住,最后“登录超时已取消,请重试”;
  • 代码感知:_onWeChatResp/_onQqResp 根本不触发。

为什么在 Flutter 里更难排查

  1. 业务异常发生在 Dart 层,但根因在 iOS 原生入口。
  2. UI 上看到的是“超时”或“取消”,容易误判成网络问题。
  3. 登录兜底逻辑(超时取消)会掩盖分发链断裂,导致反复调参而不是修根因。

这次问题的时间线(含日期)

  1. 2026-04-09(20ca6e2:接入 UMLink,AppDelegateopen/continue 存在提前 return true
  2. 中间阶段:通过登录页“回前台超时取消”缓解,窗口 1s -> 10s -> 3s
  3. 2026-04-16(ad93253:开始把回调交还 super,问题进入正确修复路径。

结论:中间阶段的超时窗口调整是兜底,不是根因修复。


根因拆解

  1. 分发优先级未固化:UMLink、微信、QQ 谁先处理没有明确规则。
  2. UMLink 前置抢处理AppDelegate 里先命中 UMLink 后直接返回,插件链被截断。
  3. 同域多用途冲突takuku.ysiyhua.cn 同时用于单点打开和第三方回调,仅按 host 判定会误分流。

正确解决思路

  1. 未知归属 URL/Universal Link,必须 fallback 到 super
  2. 新 SDK(如 UMLink)不得无条件抢占第三方登录回调链。
  3. 用完整链接区分单点入口:https://takuku.ysiyhua.cn/takuku/web/
  4. 非该完整链接的同域回调,优先按微信/QQ 回调链处理。

错误写法 vs 正确写法(示意)

错误写法(会吞 Flutter 插件回调)

override func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    if ULinkManager.shared.handleUniversalLink(userActivity) {
        return true
    }
    return true // 错误:Flutter 插件链不会再收到回调
}

正确写法(保留 Flutter 插件链)

override func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    let link = userActivity.webpageURL?.absoluteString ?? userActivity.activityType
    let isSingleOpen = link.lowercased().contains("https://takuku.ysiyhua.cn/takuku/web/")

    if isSingleOpen, ULinkManager.shared.handleUniversalLink(userActivity) {
        return true
    }

    // 关键:不确定归属时交还 Flutter 插件分发链
    return super.application(application, continue: userActivity, restorationHandler: restorationHandler)
}

Agent 快速排障 SOP(10-20 分钟)

  1. AppDelegateopen url / continue userActivity 是否存在提前 return true
  2. 查“未命中分支”是否 fallback 到 super
  3. 查日志是否包含:命中分支、handled 值、原始 URL。
  4. 查 Flutter 侧回调监听是否已注册(微信 addSubscriber,QQ respStream)。
  5. 查登录页是否只把“超时取消”当兜底而非主修复。
  6. 真机验证微信授权返回,确认进入 _onWeChatResp
  7. 真机验证 QQ 授权返回,确认进入 _onQqResp
  8. 验证 https://takuku.ysiyhua.cn/takuku/web/ 与登录回调互不干扰。

回归清单(每次改回调必测)

  1. 微信登录:授权返回必须进入 _onWeChatResp
  2. QQ 登录:授权返回必须进入 _onQqResp
  3. 单点链接:/takuku/web/ 不出现“先开 App 再开网页”抖动。
  4. Widget Deep Link 不回归。
  5. UMLink 既有能力不回归。

团队规范(防再犯)

PR 必查项

  1. 是否存在未知回调直接 return true
  2. 是否保留 super fallback。
  3. 是否按完整路径分流同域多用途回调。
  4. 是否补“命中分支 + handled 值”日志。
  5. 是否附微信/QQ/单点/ULink 真机回归结果。

禁止项

  1. 禁止用“调大超时”代替回调链修复。
  2. 禁止新 SDK 无条件前置抢处理。
  3. 禁止仅按 host 判定同域多用途回调。

最终结论

这次问题在 Flutter 项目里之所以显得“诡异”,是因为回调断在原生入口,症状却在 Dart 层暴露。
真正的修复路径永远是:先修原生分发链,再看 Flutter 业务兜底

给 Agent 的一句话策略:先看 AppDelegate 分发,再看插件注册,再看业务超时逻辑。


补充:最终修复版本(配置口径)

最终结论

这次线上稳定方案除了分发顺序修正外,配置层的关键点是:

  1. UMLink 的链接不要手填“自定义业务链接”。
  2. 使用友盟后台/SDK规范生成并下发的 UMLink 链接。

这样做的结果是:

  • UMLink SDK 只会识别并处理属于自己的链接;
  • 不会把微信、QQ 的回调链接误识别为 UMLink;
  • 从源头降低“抢占回调链”的概率。

对开发者的落地建议

  1. UMLink、微信、QQ 三方链接来源分离,禁止混用同一手填业务链接。
  2. 接入时先校验“链接归属”再写分发代码。
  3. 即使配置正确,AppDelegate 仍需保留 super fallback,避免未来新增 SDK 再次截断链路。

感谢您的阅读和参与,HH思无邪愿与您一起在技术的道路上不断探索。如果您喜欢这篇文章,不妨留下您宝贵的赞!如果您对文章有任何疑问或建议,欢迎在评论区留言,我会第一时间处理,您的支持是我前行的动力,愿我们都能成为更好的自己!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐