CallKit技术问题:如何在应用内添加号码至CXCallDirectoryProvider黑名单
如何在运行时更新CallKit黑名单?
我希望在应用运行期间将号码添加至CallKit的黑名单列表中。目前我尝试更新黑名单但未能成功,相关代码如下:
let callDirectoryExtensionContext = CXCallDirectoryExtensionContext.init() let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ xx_xxx_xxx_xxxx ] for phoneNumber in phoneNumbers { callDirectoryExtensionContext.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber) } let callDirectoryProvider = CXCallDirectoryProvider.init() callDirectoryProvider.beginRequest(with: callDirectoryExtensionContext) CXCallDirectoryManager.sharedInstance.reloadExtension(withIdentifier: "com.xxxxxxx.xxxxx.CustomCallDirectoryProvider") { (error) in if let error = error { print(error.localizedDescription) } }请问是否可以通过CallKit实现黑名单号码的更新或添加?
当然可以实现!你当前的代码问题在于错误地手动初始化了CXCallDirectoryExtensionContext和CXCallDirectoryProvider——这些对象是系统在调用你的Call Directory Extension时自动提供的,主应用不能直接操作它们。正确的做法是让主应用传递数据给扩展,然后触发扩展重新加载,由扩展自己完成黑名单的更新。
下面是具体的实现步骤:
1. 确保项目包含Call Directory Extension
如果还没有,在Xcode中给项目添加一个Call Directory Extension target(File > New > Target > iOS > Call Directory Extension)。这个扩展是处理黑名单逻辑的核心。
2. 配置App Groups实现数据共享
主应用和扩展需要共享黑名单数据,所以要开启App Groups:
- 打开Xcode项目设置,选中主应用target,在
Signing & Capabilities中添加App Groups,创建一个组(比如group.com.yourapp.blocklist)。 - 同样给Call Directory Extension target添加同一个App Group。
3. 在主应用中存储新的黑名单号码
当用户在主应用中添加号码到黑名单时,把号码存入共享存储(比如UserDefaults):
// 存储新号码到共享UserDefaults let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.blocklist")! var blockedNumbers = sharedDefaults.array(forKey: "BlockedNumbers") as? [CXCallDirectoryPhoneNumber] ?? [] // 注意:号码要转成带国家代码的64位整数,比如中国号码138xxxxxxx要存为86138xxxxxxx blockedNumbers.append(8613800000000) sharedDefaults.set(blockedNumbers, forKey: "BlockedNumbers") sharedDefaults.synchronize()
4. 在Call Directory Extension中实现更新逻辑
在扩展的CXCallDirectoryProvider子类里,重写beginRequest(with:)方法,读取共享数据并更新黑名单:
class CustomCallDirectoryProvider: CXCallDirectoryProvider { override func beginRequest(with context: CXCallDirectoryExtensionContext) { context.delegate = self // 可选:如果需要完全替换现有黑名单,先移除所有条目 context.removeAllBlockingEntries() // 读取共享存储中的最新黑名单 let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.blocklist")! if let phoneNumbers = sharedDefaults.array(forKey: "BlockedNumbers") as? [CXCallDirectoryPhoneNumber] { for number in phoneNumbers { context.addBlockingEntry(withNextSequentialPhoneNumber: number) } } // 完成请求,通知系统更新完成 context.completeRequest() } } extension CustomCallDirectoryProvider: CXCallDirectoryExtensionContextDelegate { func requestFailed(for context: CXCallDirectoryExtensionContext, withError error: Error) { // 处理请求失败的情况,比如打印错误日志 print("Call Directory扩展请求失败: \(error.localizedDescription)") } }
5. 在主应用中触发扩展重新加载
存储完新号码后,调用CXCallDirectoryManager的方法让系统重新加载扩展,这样扩展就会执行上面的更新逻辑:
CXCallDirectoryManager.shared.reloadExtension(withIdentifier: "com.xxxxxxx.xxxxx.CustomCallDirectoryProvider") { error in if let error = error { print("黑名单更新失败: \(error.localizedDescription)") } else { print("黑名单已成功更新") } }
额外注意事项
- 号码格式:
CXCallDirectoryPhoneNumber是Int64类型,必须使用带国家代码的完整号码(比如美国号码是1xxxxxxxxx,中国是86xxxxxxxxx),不能用带分隔符的字符串。 - 用户权限:首次使用时,系统会请求用户允许你的应用使用Call Directory功能,要确保用户授权了。
- 性能:如果黑名单号码很多,建议分批处理或者优化读取逻辑,避免扩展超时。
内容的提问来源于stack exchange,提问作者Jas_meet
相关产品推荐
相关产品推荐

