iOS自定义键盘如何通过Deep Linking返回源应用?技术咨询
首先直接给结论:你没办法通过编程直接让自定义键盘跳转回源应用,但通过传递URL Scheme给容器应用再打开源应用的思路是可行的,不过有几个关键限制需要留意。
一、为什么不能直接编程返回源应用?
iOS的自定义键盘属于App Extension范畴,它运行在独立的沙箱环境里,和你的容器应用完全分离。苹果出于隐私与安全的严格管控,给Extension设置了诸多权限限制:
- 键盘扩展无权调用
UIApplication.shared.open(_:options:completionHandler:)这类应用切换API,甚至在Extension环境里这个API根本不可用(编译阶段就会报错)。 - 你看到的容器应用左上角"<- Safari"按钮,是系统提供的导航返回逻辑,属于容器应用的导航栈机制,这是系统层面的跳转能力,第三方代码没办法模拟这种直接返回的行为。
二、通过URL Scheme跳转的可行方案(但有局限)
如果想通过容器应用打开源应用,得解决两个核心问题:键盘如何把源应用的Scheme传给容器应用,以及容器应用能否顺利打开该Scheme。
1. 键盘与容器应用共享数据(传递Scheme)
你可以借助App Groups实现键盘扩展和容器应用之间的数据共享,步骤如下:
- 在开发者后台为你的主应用和键盘扩展开启App Groups功能,并设置同一个Group ID(比如
group.com.yourcompany.yourapp)。 - 在容器应用和键盘扩展的
Info.plist中添加App Groups权限项,填入刚才设置的Group ID。 - 键盘扩展中把目标Scheme(这里要注意:键盘无法自动获取源应用的Scheme,后面会讲这个问题)存入共享的UserDefaults:
// 键盘扩展中存储Scheme示例 let sharedDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp") sharedDefaults?.set("safari://", forKey: "SourceAppScheme") sharedDefaults?.synchronize() - 容器应用启动或激活时,读取共享存储中的Scheme并尝试打开:
// 容器应用中读取并打开Scheme示例 let sharedDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp") if let scheme = sharedDefaults?.string(forKey: "SourceAppScheme"), let url = URL(string: scheme), UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url, options: [:], completionHandler: nil) }
2. 关键限制:无法自动获取源应用的Scheme
这里有个绕不开的问题:iOS不允许键盘扩展获取当前宿主应用的Bundle ID或URL Scheme。键盘扩展没有任何公开API能拿到正在使用它的应用的标识信息,所以你没办法自动获取到源应用的Scheme,只能手动指定(比如明确用户从Safari过来,就用safari://),但这显然没法支持“任意源应用”的需求。
另外,iOS 9及以后要求容器应用的Info.plist中添加LSApplicationQueriesSchemes数组,列出你要打开的Scheme,否则canOpenURL(_:)会返回false。但你不可能提前把所有应用的Scheme都列进去,这也进一步限制了“任意源应用”的实现可能性。
三、更实际的替代方案
既然自动跳转有这么多合规性限制,更稳妥的做法是在键盘上添加友好提示,引导用户点击容器应用左上角的系统返回按钮,或者手动切换回源应用。虽然体验不如自动跳转流畅,但这是目前符合iOS安全规则的可行方式。
内容的提问来源于stack exchange,提问作者mahega

