推荐序

本文介绍了 iOS 10 中的 Call Directory Extension 特性,并且最终 Demo 出一个来电黑名单的 App。

作者:余龙泽,哈工大软件工程大四学生,之前在美图公司实习,在iOS学习道路上不断努力中。

感谢作者授权,以下是正文。


iOS 10 中引入了许多令人振奋的新特性,其中 CallKit 让我特别感兴趣。这是一个非常重要的 API,继 2014 年苹果推出 VoIP 证书后,这次 VoIP 接口的开放,以及一个全新的 App Extension,简直是 VOIP 的福音,可见苹果对 VOIP 的重视。并且,”that enable call blocking and caller identification. You can create an app extension that can associate a phone number with a name or tell the system when a number should be blocked.” 这意味着现在可以通过 Call Directory Extension 来实现电话黑名单功能了。Cool~ 本文简单阐述了如果实现简单的来电黑名单功能。

阅读须知:目前学习的资料也仅限相关 API,另外 API 也没有详细的注释,所以本文主要是个人探索所得,如果有什么错误,还望见谅并予以指正。现在,让我们开始吧~

API 介绍

Extension 一直给我的印象就是很轻量,单一的,就如之前接触的  Photo Editing Extension 一样,使用起来十分简单。这次的 Call Directory Extension 也不出例外,出奇的简单。只涉及了两个类,四个方法。下面我们逐一介绍:

////  CXCallDirectoryProvider.h//  CallKit@available(iOS 10.0, *)
public class CXCallDirectoryProvider : NSObject, NSExtensionRequestHandling { public func beginRequest(with context: CXCallDirectoryExtensionContext)}

首先是第一个类 CXCallDirectoryProvider,它是来电的响应者,为我们提供了 beginRequest 方法,该方法在 Containing App 调用 reload 或者在 设置 —> 电话 —> Call Blocking & Identification 里开启权限的时候,会自动被调用。所以我们之后将要重写它,来实现黑名单相关逻辑。怎么样,简单吧~
Now, Go on~

接下来是另外一个类 CXCallDirectoryExtensionContext,它提供了另外三个方法,如下所示:

////  CXCallDirectoryExtensionContext.h//  CallKit@available(iOS 10.0, *)
public class CXCallDirectoryExtensionContext : NSExtensionContext { public func addBlockingEntry(withNextSequentialPhoneNumber phoneNumber: String) public func addIdentificationEntry(withNextSequentialPhoneNumber phoneNumber: String, label: String) public func completeRequest(completionHandler completion: ((Bool) -> Swift.Void)? = nil)}

不难看出,CXCallDirectoryExtensionContext 主要负责提交我们处理好的请求。说白点,我们利用它来让系统知道,我们对某个来电所做出的判断。 addBlockingEntry 方法,接受一个电话号码字符串,形如 “+8618…69” (PS:不要问我为什么要加区号 .. 这都是血与泪的经验),来直接加入黑名单,也就是不接听该来电。addIdentificationEntry 方法,接受一个电话号码字符串以及对该号码的描述,也就是来电的时候需要显示的内容。 completeRequest 也就是提交之前的处理结果。至此,我们所要做的工作就完成了。

实战演示

虽然自认为上面的描述已经够详细了,不过这里还是有必要详细走一遍流程,以免遗漏。

开发环境:Xcode8.0 Beta + 64 位 iOS10 设备(至于为什么 64 位,之后再解释,说多了都是泪 ..)

1. 创建工程

没什么特别。 Xcode —> File —> New —> Project。随便选个 iOS Application,创建即可。这里我选择开发语言为 Swift,你随意~。

这里我们的目标是来电黑名单,也就是 Extension 部分,所以创建好的 Containing App,不用做什么改动。

2. 添加 Extension

Xcode —> File —> New —> Target。创建一个 Call Directory Extension,如下图所示:

这里注意下底部的说明, (This extension and the app it is bundled with must be 64-bit only)也就是,这个 extension 只支持 64 位的设备,坑爹有没有!!之前创建太急,没认真看,用那台 5C 倒腾了半天,就是出问题。只好狠心把主力机也升级了。

创建好 Extension,会弹出这样的提示框:

询问我们是否激活这个 scheme,当然选择激活咯,继续~

之后只要关注 xxxHandler.swift 即可,xxx 是你之前创建的 extension 命名。

这里的相关代码如下:

import Foundation
import CallKit class CallDirectoryHandler: CXCallDirectoryProvider { override func beginRequest(with context: CXCallDirectoryExtensionContext) {
// --- 1
guard let phoneNumbersToBlock = retrievePhoneNumbersToBlock() else {
NSLog("Unable to retrieve phone numbers to block")
let error = NSError(domain: "CallDirectoryHandler", code: , userInfo: nil)
context.cancelRequest(withError: error)
return
} // --- 2
for phoneNumber in phoneNumbersToBlock {
context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
} // --- 3
guard let (phoneNumbersToIdentify, phoneNumberIdentificationLabels) = retrievePhoneNumbersToIdentifyAndLabels() else {
NSLog("Unable to retrieve phone numbers to identify and their labels")
let error = NSError(domain: "CallDirectoryHandler", code: , userInfo: nil)
context.cancelRequest(withError: error)
return
} // --- 4
for (phoneNumber, label) in zip(phoneNumbersToIdentify, phoneNumberIdentificationLabels) {
context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)
} // --- 5
context.completeRequest()
} private func retrievePhoneNumbersToBlock() -> [String]? {
// retrieve list of phone numbers to block
return ["+8618xxxx157"]
} private func retrievePhoneNumbersToIdentifyAndLabels() -> (phoneNumbers: [String], labels: [String])? {
// retrieve list of phone numbers to identify, and their labels
return (["+8618xxxx569"], [" 测试 "])
} }

一个简单的来电黑名单,我们只要补全 retrievePhoneNumbersToBlockretrievePhoneNumbersToIdentifyAndLabels 中的相关数据即可,它们分别表示直接加入黑名单的号码以及识别出来,需要判断的号码。

现在我们具体看一下这个类到底做了什么。

beginRequest ,该方法在 Containing App 调用 reload 或者在 设置 —> 电话 —> Call Blocking & Identification 里开启权限的时候,会自动被调用。每次调用,都会提交当前的黑名单列表,具体操作如下:

// —- 1 中,先判断是否成功调用了 retrievePhoneNumbersToBlock 方法,如果没有,则打印 Log: Unable to retrieve phone numbers to block,然后直接终止这次请求并返回。

// —- 2 中,遍历添加黑名单中的号码,这里的号码将直接拦截。

// —- 3 中,先判断是否成功调用了 retrievePhoneNumbersToIdentifyAndLabels 方法,如果没有,则打印 Log: Unable to retrieve phone numbers to identify and their labels,然后直接终止这次请求并返回。

// —- 4 中,遍历添加识别后的号码及其描述,这里的号码将连带描述一起显示。

// —- 5 中,完成提交请求。

到这里,代码已经全部完成了。

3. 开启权限

之后我们运行该 App 到设备中,然后进入设备的设置 —> 电话 —> Call Blocking & Identification,开启我们的 App 即可。如下图所示:

相关思考及后续

虽然实现黑名单功能很简单,但是这里我认为主要的问题应该是集中在,如何编辑这个黑名单列表。列表数据项可能很多,并且数据可能是实时更新添加的,那应该怎么做才更好呢?这里我的第一反应就是利用 App Group 实现数据共享,在 Containing App 完成相关的数据操作,在 Extension App 中去获取即可。至于可行性,倒是没有验证过,如果不行,就当我瞎比比咯~。 当然,可能还有其他的办法,以及可能还会遇到其他的问题,这里在之后的学习过程中,我会逐步完善。

当然,对于 CallKit 的学习,我也仅限于这一两天,还是没有资料的情况下。所以文中难免存在各种错误以及遗漏,欢迎指正。

这之后,继续 CallKit 的学习,实现它的另外一个功能:VoIP App。 wait…

Enjoy it~

参考链接

Enhancing VoIP Apps with CallKit:https://developer.apple.com/videos/play/wwdc2016/230/

CallKit: https://developer.apple.com/reference/callkit

Call Directory Extension 初探的更多相关文章

  1. App Extensions篇之Share Extension

    转载请注明出处:http://www.cnblogs.com/zhanggui/p/7119572.html 1.前言 这里主要是对App Extension的一些介绍以及详细给大家介绍一下Share ...

  2. iOS - App Extension 整体总结

    一.App Extension的介绍 App Extension可以让你扩展你APP的自定义功能和内容,使用户可以在与其他应用或者系统进行互动的时候去使用它.app extension即为本文所说的e ...

  3. iOS App Extension入门

    转自简书:http://www.jianshu.com/p/8cf08db29356   iOS 10推出了很多新功能,其中有几个高调的变化:通知栏更加实用,电话可以防骚扰,iMessage变得更加有 ...

  4. 利用callKit实现电话防骚扰

    callKit框架是ios10之后更新的一个框架,代替了原来的CoreTelephony.framework,使用CallKit可以实现电话的拦截 首先创建一个项目之后,创建一个target,选择Ca ...

  5. Orchard详解--第九篇 拓展模块及引用的处理

    在分析Orchard的模块加载之前,先简要说一下因为Orchard中的模块并不是都被根(启动)项目所引用的,所以当Orchard需要加载一个模块时首先需要保证该模块所依赖的其它程序集能够被找到,那么才 ...

  6. IOS-电话拦截

    IOS10的电话拦截理念与android不一样,基于隐私保护的理念IOS没把对方号码送给应用,因此需要反过来由app把需要识别或拦截的电话存入系统数据库.这一功能通过Call Directory Ex ...

  7. 微软BI 之SSIS 系列 - 在 SSIS 中将指定目录下的所有文件分类输出到不同文件夹

    开篇介绍 比如有这样的一个需求,旧的一个业务系统通常将产出的文件输出到同一个指定的目录下的不同子目录,输出的文件类型有 XML,EXCEL, TXT 这些不同后缀的文件.现在需要在 SSIS 中将它们 ...

  8. CallKit iOS 教程

    原文:CallKit Tutorial for iOS 作者:József Vesza 译者:kmyhy 对 VoIP App 开发者来说,iOS 的支持并不友好.尤其是它的通知发送这一块,太糙了.你 ...

  9. iOS开发人员:事实上你还有非常多东西须要学

    iOS 新特性总结(since iOS6) iOS 6 1.废除viewDidUnLoad 收到内存警告须要到didReceiveMemoryWarning中处理 [小技巧] -(void)didRe ...

随机推荐

  1. JS实现继承多态

    //类对象构造模版,无new访问,类似静态访问 var Class = { create: function () { return function () { //initialize初始化 //a ...

  2. 从用python自动生成.h的头文件集合和类声明集合到用python读写文件

    最近在用python自动生成c++的类.因为这些类会根据需求不同产生不同的类,所以需要用python自动生成.由于会产生大量的类,而且这些类是变化的.所以如果是在某个.h中要用include来加载这些 ...

  3. 2016022609 - redis哈希命令集合

    参考:http://www.yiibai.com/redis/redis_hashes.html Redis的哈希值是字符串字段和字符串值之间的映射,所以他们是表示对象的完美数据类型 在Redis中的 ...

  4. xfire实现webservice客户端之测试关注点

    日前的工作接触到很多系统间的Webservice调用,这里想谈谈基于spring+xfire实现的webservice的客户端踩过的一些坑,需要测试关注的点. xFire的配置项 在spring中实现 ...

  5. 第一个deeplearning4jproject跑起

    deeplearning4j是基于java的深度学习库,当然,它有许多特点,但暂时还没学那么深入,所以就不做介绍了 需要学习dl4j,无从下手,就想着先看看官网的examples,于是,下载了exam ...

  6. 保留你的dSYM文件

    大家编译iPhone程序的时候,都会发现二进制文件的旁边生成了一个.dSYM文件.以前一直不知道这个文件是用来干嘛的,今天才知道这个是symbol file,用来debug用的. 大家可以读读这篇文档 ...

  7. LA 3904

    一道DP题: 一共有三种砖,1*2,2*1,2*2,然后要你铺满整个n*2的地板,求不重复的铺法数: 方法: 首先计算了不考虑对称的情况,然后计算只考虑对称的情况: 所以结果就是(不考虑对称数+只考虑 ...

  8. NOT EXISTS优化

    INSERT INTO F_PTY_INDIV (PTY_ID, PTY_NAME, GENDER_CD, BIRTHDAY, CERT_TYPE, CERT_NO, SOCINSUR_NO, COU ...

  9. WPF 界面布局DockPanel stackPanel WrapPanel 元素内容以及位置控制

    1 DockPanel 1) 默认充满整个窗口. 2) 最后一个出现的部分,默认充满剩余空间. 3) 非最后一个出现的部分,根据其中内容,进行分配空间s 2 StackPanel 实现居左,居右,居中 ...

  10. C++Primer第5版学习笔记(二)

    C++Primer第5版学习笔记(二) 第三章的重难点内容         这篇笔记记录了我在学习C++常用基本语法的学习过程,基本只记录一些重难点,对概念的描述不是一开始就详尽和准确的,而是层层深入 ...