问题描述
跨时空app中,用到了 fluwx 和 appscheme 两个插件,分别用于 微信SDK 接入和监听应用协议(URL Scheme,iOS 中 H5 唤起 app 几乎都用到它)
发现两个插件同时使用时,原先正常的微信分享功能,在 iOS 端就无法使用了。
问题原因
反复重现后,发现问题出在应用首次调用 微信openSDK 的认证过程。
应用唤起微信获取到 token 后,会被微信通过 universal_link 唤起,这时候 fluwx 注册的监听(用于接收微信通过 universal_link 带回的 token 参数)没有被调用,以至于没有将 token 信息保存下来。于是后续应用每次调用 微信openSDK 都由于没有认证信息,而被认为是首次调用,重复上述过程。
根因追溯
所以症结在于 fluwx 的回调,为什么被拦截了。
根据 Flutter 的 objc++ 代码可以看出,对于监听到的传入 URL 处理逻辑是:
遍历 _delegates 如果 url 已处理完成,则跳出循环
1 | // https://github.com/flutter/engine/blob/9f650edd14dd0d74acb3d6ad65eb794b1e4b27e3/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm#L312 |
而 _delegate 则是在 addDelegate: 中被加入的。_delegate 的是一個 PointerArray,他的顺序是在 plugin 被 register 时,调用 addDelegate: 确定下来的。
1 | // https://github.com/flutter/engine/blob/9f650edd14dd0d74acb3d6ad65eb794b1e4b27e3/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm#L98 |
而 Flutter plugin 注册的顺序则是由自动生成的文件 GeneratedPluginRegistrant.m 所决定。
1 | // |
那么 Flutter 是如何生成 GeneratedPluginRegistrant.m 的呢?
1 | // https://github.com/flutter/flutter/blob/39d7a019c150ca421b980426e85b254a0ec63ebd/packages/flutter_tools/gradle/flutter.gradle#L248 |
每次执行 flutter pub get,时,会生成 .flutter-plugins,而 GeneratedPluginRegistrant.m 就是依照首字母排序。
1 | // https://github.com/flutter/flutter/blob/fa4d31b31/packages/flutter_tools/lib/src/plugins.dart#L464 |
这样问题的解决方法就明确了: 修改 appscheme 包的名称,或者改动 Fluter 的逻辑,显然前者的成本要小一些。本地保存一份插件,改名后引用即可,注意及时升级就是了。插件的更新频率,应该低于 Flutter 框架本身。 同时,我还在 appscheme 项目中提了 issue ,期待作者解决。
思考
个人认为,flutter 成功的原因有两个重要方面:其一是跨端 UI 渲染的高性能和一致性;另一个就是完备的插件扩展机制和生态。
前者已被广泛吹捧,这里无需赘述。后者则极大方便了应用功能的集成:同样的功能,可能有好几个插件可以实现,开发者选择最合适自身的即可。开发者的选择,又反过来成为插件推荐的最可靠依据。最终让好的插件脱颖而出。
有人说 flutter 是又一 KPI 产物,对此说法本人认知有限,不置可否。但很明显的体会是:flutter 确实极大拉低了应用开发的门槛。不说 UI 渲染和插件机制有多么牛逼。单是开发框架本身,集成的 Kotlin Gradle cocoapods… 工具链,就足以让初学者望而却步,可能还没入门就放弃了。但 Flutter 框架替我们抹平了这一切,让开发者得以专注于应用功能本身。
调试技巧
最后,提供几个调试 iOS 微信openSDK 到小技巧:
首次调用 微信openSDK ,会多一个 APP 与微信互相跳转的认证过程。认证成功后,就不会再有这个过程,即便是 APP 重装、切换登陆的微信号也不会,除非重装微信,或者修改 universal_link 值。所以如果要调试首次认证过程的话,我会选择修改 universal_link 记录值的方式。
需要修改两处:
- 一是在开放平台改。改后需要结束微信进程后重启,新的记录值生效;
- 二是在 APP 代码侧修改,覆盖安装,或卸载重装 APP 。
交流反馈群
