iOSApplicationExtension初体验

iOSApplicationExtension初体验

2023年7月3日发(作者:)

iOSApplicationExtension初体验序⾔什么是 Application Extensions?apple 为什么会提供这个功能,她⼜为我们解决了什么问题?早在 iOS8 的时候 apple 就为我们提供了 extension 的能⼒,只是那个时候开放给我们的权限还不多,我们能做的事情远没有像在 iOS10 ⾥这样颠覆。说了半天到底什么是 app extensions?!这⾥引⽤⼀篇 blog 的概况:extension 是 iOS 开放给我们的⼀种对固定系统区域的扩展说的再直⽩⼀点,extensions 让我们能够对系统应⽤,如神圣的电话,短信等做进⼀步的扩展。让⽤户通过原⽣系统应⽤在不打开我们 app 的情况下就可以使⽤我 app 分享出来的能⼒。你可能会问,那⼜能怎么样呢?确实,这个能⼒看起来对开发者并没有直接的好处,反⽽使 apple 将⾃⼰系统应⽤的能⼒变强⼤了。但反过来想,这样不也帮助 app 提升了⽤户导⼊率,让⽤户有更多的⼏率打开我们的 app。解密 App Extensions最近项⽬新需求,希望能识别来电号码。这个需求说实话,在 android 上早已不是什么稀奇的能⼒,各⼤⼿机管家,安全卫⼠都有号码识别和防骚扰的功能。但由于 iOS 限制,电话的相关接⼝都是私有的,想截获来电基本是不可能。在调研过程中,发现有部分 iOS app 尽然做到了号码识别。于是抱着⼈家能做的,我也能做的⼼态,就开始了各种尝试。因为之前有了解 iOS10 的新特性,⾃然就想到了从新特性中下⼿。app extensions ⾃然就变成了最先的尝试⽅案。经过查阅资料,终于粗略的实现了号码识别功能。这⾥值得多说⼀句,强烈推荐仔细阅读⼀下,参考⾥的《WWDC2014之App Extensions学习笔记》。他能很好的帮助你了解,containingapp、extension、host app 之间的关系。extensions 不能单独⽣存,必须依附在 containing app。所以 extensions 都是以 targets 的形式存在于 project。并且伴随着 containingapp 的卸载⽽删除Call Directory Extensioncall directory extension 顾名思义就是对通话的扩展。下⾯我们来从零构建⼀个具备号码识别的 app在已有的⼯程中,file -> new -> target -> call directory extension。根据提⽰完成后,会发现 project 中多了⼀个⽂件夹。⽂件夹的名称就是你之前添加的 target name。⽂件夹⾥有⼀个 ⽂件,这是创建 extension 时 Xcode 为我们⾃动⽣成的。简单说⼀下该⽂件的内容:// /* ⽤户在”设置->电话->来电阻⽌和⾝份认证“中开启应⽤的时候,会触发该⽅法。 所以我们要在这个⽅法中完成来电阻⽌和⾝份认证的操作。好在⾃动⽣成代码已经帮我们做了这部分逻辑。 */

override func beginRequest(with context: CXCallDirectoryExtensionContext) { te = self do { try addBlockingPhoneNumbers(to: context) } catch { NSLog("Unable to add blocking phone numbers") let error = NSError(domain: "CallDirectoryHandler", code: 1, userInfo: nil) Request(withError: error) return } do { try addIdentificationPhoneNumbers(to: context) } catch { NSLog("Unable to add identification phone numbers") let error = NSError(domain: "CallDirectoryHandler", code: 2, userInfo: nil) Request(withError: error) return } // 关键代码,通知系统更新我们为 CXCallDirectoryExtensionContext 添加的资源 teRequest() } private func addBlockingPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws { // 在这⾥我们将需要阻⽌的号码添加进数组即可。需要注意的是,这个数组内容必须是升序。号码前要加 +86 let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ +86, +86 ] // 以下逻辑是关键,将阻⽌号码的数组添加到 CXCallDirectoryExtensionContext for phoneNumber in phoneNumbers { ckingEntry(withNextSequentialPhoneNumber: phoneNumber) } } private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws { // 添加来电提醒的⽤户识别号码和对应的名称,且号码数组的内容必须是升序。号码前要加 +86 var phoneNumbers: [CXCallDirectoryPhoneNumber] = [ +861234567890 ] var labels = [ "robert zhang" ]

for (phoneNumber, label) in zip(phoneNumbers, labels) { ntificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label) } }代码并不难理解。但我相信你会有⼀个疑问,如果需要动态添加资源该怎么办?这个简单,只需要动态读取数据库中相应号码并添加进phoneNumbers 数组就可以了!如果你这样想,那就祝贺你想错了。因为 extensins 与我们的 containing app 并不在同⼀个 bundle,所以她们之间的数据是不可直接共享的。那该怎么办呢?好在 App Groups 可以解决应⽤间共享资源的问题。所以我们需要在 targets -> 选中extension -> Capabilities -> 开启 App Groups,add a new container。并勾选该 App Groups。添加成功后如下图:app 在主应⽤中也得开启 App Groups,勾选刚才添加的 group id。App Groups 建⽴完成后,就可以为她们添加共享数据了。这⾥需要提⽰⼀下。当我们为项⽬开启 App Groups 的时候需要更新⼀下 Provisioning Profile ,否则编译是不会通过的。现在我们动态的为 phoneNumbers 添加数据,代码如下:// private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws { // 添加来电提醒的⽤户识别号码和对应的名称,且号码数组的内容必须是升序。号码前要加 +86 var phoneNumbers: [CXCallDirectoryPhoneNumber] = [ +861234567890 ] var labels = [ "robert zhang" ]

// 动态获取 App Groups 共享资源 if let (phone,label) = readPhoneSrc() { (contentsOf: phone) (contentsOf: label) } for (phoneNumber, label) in zip(phoneNumbers, labels) { ntificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label) } }

/* 从 Groups 的共享⽂件区域获取号码资源 */ private func readPhoneSrc() -> (phoneNumbers:[CXCallDirectoryPhoneNumber],labels:[String])?{ // forSecurityApplicationGroupIdentifier 的参数是 App Groups 的名称 let url = nerURL(forSecurityApplicationGroupIdentifier: "") let containerUrl = url?.appendingPathComponent("Library/Caches/")

let exist = ists(atPath: containerUrl!.path) if exist { let dict = NSDictionary(contentsOf: containerUrl!) as! [String:String] let keys = ()

var phoneNumber: [CXCallDirectoryPhoneNumber] = [] var label = [String]()

for item in keys { (atoll("+86"+item)) (dict[item]!) }

return (phoneNumber,label) }

return nil }代码⽐较简单,就不赘述了。当然这只是 extension 读取 groups 共享资源的代码,你还需要完成主应⽤写⼊资源的逻辑。这部分代码是在主应⽤中的。class DataHelper { static func addPhoneSrc() { // forSecurityApplicationGroupIdentifier 与 App Groups ID 名称⼀致 let url = nerURL(forSecurityApplicationGroupIdentifier: "") // 存储共享资源的⽂件路径 let containerUrl = url?.appendingPathComponent("Library/Caches/")

let exist = ists(atPath: containerUrl!.path) if !exist { let data = NSData(base64Encoded:"aXVstH8gc29cbXP=",options:.ignoreUnknownCharacters) let createSuccess = File(atPath: containerUrl!.path,contents:data as Data?,attributes:nil) print("⽂件创建结果: (createSuccess)") } // 提⽰这⾥可以根据具体业务,完成号码的写⼊ let dicts = NSDictionary(dictionary: ["1234567890":"robert zhang"]) (to: containerUrl!, atomically: true) }}关于 App Groups 资源共享,这⾥使⽤的是 plist ⽂件。当然还有其他的资源共享⽅式,使⽤数据库共享也是可以的。在此只举例了⾝份认证的逻辑,来电阻⽌的思路基本⼀致。这就是全部的内容?当然不是,还有⼀个问题。如果想要实时的更新来电阻⽌和⾝份认证的号码库该怎么办呢?难道每次都去设置中进⾏号码识别的开关操作?当然不⽤这么⿇烦。// 在业务需要的地⽅添加下⾯代码,注意该逻辑需要在主应⽤中。@available(iOS 10.0, *) // call directory 只在 iOS10 以上版本可⽤ func reloadCallDirectory() { let manger = Instance // withIdentifier 为 extension 的 bundle identifier // 判断是否在设置中打开来电阻⽌和⾝份认证的开关 bledStatusForExtension(withIdentifier: "XXXXX", completionHandler: { enabledStatus, error in NSLog("******** (ue) *** (error)") if error == nil { if enabledStatus == d { // withIdentifier 为 extension 的 bundle identifier // 其实就是调⽤ CallDirectoryHandler 的 beginRequest(with context: CXCallDirectoryExtensionContext) ⽅法 Extension(withIdentifier: "XXXXXX", completionHandler: { error in NSLog("======(error == nil ? "OK" : "Error")") }) } } }) }就此,号码识别的功能基本上就完成了。整体来看,难点并不在 Call Directory Extension 的开发,⽽是 App Groups 共享数据。参考

发布者:admin,转转请注明出处:http://www.yc00.com/web/1688382276a129634.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信