众所周知,在 iOS 平台上自从 8.0 版本开始,可以为 iOS 开发第三方的输入法键盘了,而这些键盘可以被放在 AppStore 销售了,不过,同时也有着十分严格的权限规则。
对此,苹果为第三方的键盘设计了两种权限,一种是最小的,只有最基本的键盘功能的权限、另一种则相对较多,键盘获取了“完全访问”权限之后基本上就和 android 上键盘差不多,可以访问联系人、可以联网等等。
不过,不少键盘却是为了设置功能而不得不向用户请求这个“完全访问”权限,因为他们发现,如果不这么做,作为插件的键盘就不能访问作为宿主的 app 的存储空间。
在 ios 中,你的键盘虽然是以一个 app 的形式来销售和使用的,但键盘实际上是一个“插件”,它由 ios 单独加载,所以实际上它和你的 app 是“两个不同的应用”,它们有各自独立的存储空间。
这时候如果你要给用户开发一款不请求完全访问权限的键盘,你就需要在键盘里额外添加一个按钮,以及一个界面来设置键盘属性。而这个应用 app,则加入一些空洞的新手引导等内容就草草了事。
比如说
比较老牌的双拼输入法 SPI 就是这么做的,它的 app 里是新手引导和用户论坛,而设置则在键盘上有专门按键:
真的就没有办法了吗?
其实是有的,在 ios 开发中有一个叫做 “AppGroup” 的技术,它可以给同一个开发者的不同 app 打组,为这些 app 提供一个公共的存储空间,这样的话同一个开发者的不同应用之间就可以交换一些配置或者文件,为用户提供更好的服务——比如配置信息。
说起来没什么特别的
苹果对第三方键盘的 AppGroup 使用一开始是没有限制的,可以说这是一个 bug ——利用 AppGroup 键盘即使不获取完全访问权限,也同样可以将收集的信息传走,不过在 ios10 之后,他们完善了权限,——键盘就只能读取而不能往 AppGroup 的共享空间写入内容了。
但好在,我们还是可以做到让 app 控制键盘的。你们已经想到了,只要把配置文件放到共享目录里,然后键盘主动去读取就够了。
那么怎么做到一些更新的问题呢?比如我可以检测文件是否存在,我可以加载配置信息,但是如果一个词库,它只是内容变了……
如果每次都从共享空间撸一份回来,会很耗费资源,所以我用了一个“版本号”的机制,每次进行额外的校对就可以了。
这就是为什么在一开始落格输入法要求用户配置完成之后一定要点“返回”,因为这样才会触发版本更新,键盘才会读取。
这样说起来简单,但做起来就比较复杂——或者说是繁琐,你需要在 app 和键盘里维护统一份序列化和反序列化的工具,这里我自己则用了一个单件模式来专门管理而不是各自访问。(注意不能使用延迟加载,这个特性虽然益处无穷,但你这么做就会导致配置偶尔难以改变,键盘的生命周期是不可预测的 ——尽管一般来说是收起键盘的五秒后)。
代码伺侯
这里我把自己的代码片段贴出来给大家:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** 获取的路径为 app groups 共享路径 - parameter fileName: 文件名 - returns: 共享目录的路径 */ class func get(groupPath fileName: String) ->String { let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.logcg.Input") let fileUrl = url?.appendingPathComponent(fileName) return fileUrl!.path } |
在应用和键盘里都可以使用这个方法来获取 AppGroup 的路径,只不过键盘是只读的,而应用这拥有完全的读写权限。
其他的就和普通的读取配置没什么区别了,你要注意,你同样可以给配置写入,只不过这是无效的——重点是不会有任何的错误提示。
1 2 3 4 5 6 7 8 9 10 11 12 |
func getConfig() { let array = NSArray(contentsOfFile: configPath) if array == nil { return } let configDict = array![0] as! Dictionary<String, AnyObject> if let i = configDict["CustomCodeTableVersion"] {customCodeTableVersion = i as! Int} if let e = configDict["EmojiMode"] {emojiMode = e as! Int} if let i = configDict["AssistCodeVersion"] {assistCodeVersion = i as! Int} if let b = configDict["BoomIsLeft"] {boomIsLeft = b as! Bool} if let i = configDict["AssistCodePlan"] {assistCodePlan = i as! Int} if let i = configDict["CodeTableVersion"] {codeTableVersion = i as! Int} } |
总结
其实搜狗也在用这个方法了,毕竟在不开启完全访问权限的情况下,搜狗还是可以用应用来对键盘进行基本的配置的——你们要注意,在 ios 10 版本之前,键盘是可以给共享空间写入的,我就提这么一句。
本文由 落格博客 原创撰写:落格博客 » 落格输入法 是怎么实现 app 设置而不需要 完全访问 权限的?
转载请保留出处和原文链接:https://www.logcg.com/archives/2488.html