You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:59:50