developer.apple.com/documentati…
developer.apple.com/documentati…
LiveCommunicationKit
在 iOS 17.4 及更高版本中,Apple 引入了 LiveCommunicationKit 框架,为开发者提供了新的 VoIP 通话交互接口。与之前的 CallKit 相比,LiveCommunicationKit 在锁屏状态下不会全屏弹出,也不会在通讯录中留下通话记录。 
目前,关于 LiveCommunicationKit 的官方文档和使用示例相对有限。然而,微信在其 iOS 版 8.0.55 更新中,采用了 LiveCommunicationKit 接口来优化语音接听体验。 
如果您正在开发 VoIP 功能,并希望使用 LiveCommunicationKit,建议您:
- 查阅官方文档:访问 Apple 开发者文档,查看 LiveCommunicationKit 的最新信息和使用指南。 
- 参考现有应用的实现:研究像微信这样的应用如何集成 LiveCommunicationKit,以获取实际的应用案例。
- 关注开发者社区:参与 iOS 开发者论坛和社区,获取其他开发者的经验分享和最佳实践。
自己的微信在升级最新的 8.0.56 版本后,进入微信 App 依次点击 我-设置-消息通知,如果新增了「语音和视频通话用系统电话接听」或「语音通话用弹窗快捷接听」的开关,就说明有了 LiveCommunicationKit 功能。
CallKit
在 Objective-C 中使用 CallKit 主要用于集成 VoIP(网络电话)功能,使 VoIP 通话可以与 iOS 系统的原生电话 UI 进行交互。下面是详细的实现步骤:
1. 配置 Info.plist
在 Info.plist 添加后台模式,确保 App 在后台仍能接收来电:
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
2. 导入 CallKit 和 PushKit
在 ViewController.h 或 AppDelegate.h 中:
#import <CallKit/CallKit.h>
#import <PushKit/PushKit.h>
3. 创建 CallManager 处理通话逻辑
新建 CallManager.h 和 CallManager.m,用于管理 CallKit 功能。
CallManager.h
#import <Foundation/Foundation.h>
#import <CallKit/CallKit.h>
@interface CallManager : NSObject <CXProviderDelegate>
@property (nonatomic, strong) CXProvider *provider;
@property (nonatomic, strong) CXCallController *callController;
- (void)reportIncomingCallWithUUID:(NSUUID *)uuid callerName:(NSString *)callerName;
- (void)startCallWithHandle:(NSString *)handle;
- (void)endCallWithUUID:(NSUUID *)uuid;
@end
CallManager.m
#import "CallManager.h"
@implementation CallManager
- (instancetype)init {
self = [super init];
if (self) {
CXProviderConfiguration *config = [[CXProviderConfiguration alloc] initWithLocalizedName:@"My VoIP App"];
config.supportsVideo = YES; // 支持视频通话
config.maximumCallsPerCallGroup = 1;
config.supportedHandleTypes = [NSSet setWithObjects:@(CXHandleTypePhoneNumber), @(CXHandleTypeEmailAddress), nil];
self.provider = [[CXProvider alloc] initWithConfiguration:config];
[self.provider setDelegate:self queue:nil];
self.callController = [[CXCallController alloc] init];
}
return self;
}
#pragma mark - 处理来电
- (void)reportIncomingCallWithUUID:(NSUUID *)uuid callerName:(NSString *)callerName {
CXCallUpdate *update = [[CXCallUpdate alloc] init];
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:callerName];
update.hasVideo = NO;
[self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError * _Nullable error) {
if (error) {
NSLog(@"报告来电失败: %@", error.localizedDescription);
} else {
NSLog(@"来电成功报告");
}
}];
}
#pragma mark - 处理拨打电话
- (void)startCallWithHandle:(NSString *)handle {
NSUUID *uuid = [NSUUID UUID];
CXHandle *callHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:uuid handle:callHandle];
CXTransaction *transaction = [[CXTransaction alloc] initWithAction:startCallAction];
[self.callController requestTransaction:transaction completion:^(NSError * _Nullable error) {
if (error) {
NSLog(@"发起呼叫失败: %@", error.localizedDescription);
} else {
NSLog(@"呼叫已发起");
}
}];
}
#pragma mark - 处理挂断电话
- (void)endCallWithUUID:(NSUUID *)uuid {
CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:uuid];
CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction];
[self.callController requestTransaction:transaction completion:^(NSError * _Nullable error) {
if (error) {
NSLog(@"结束通话失败: %@", error.localizedDescription);
} else {
NSLog(@"通话已结束");
}
}];
}
#pragma mark - CXProviderDelegate
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
NSLog(@"用户接听了电话");
[action fulfill];
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
NSLog(@"用户挂断了电话");
[action fulfill];
}
@end
4. 处理 VoIP 推送
在 AppDelegate.h 中:
#import <UIKit/UIKit.h>
#import <PushKit/PushKit.h>
#import "CallManager.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate, PKPushRegistryDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) PKPushRegistry *pushRegistry;
@property (strong, nonatomic) CallManager *callManager;
@end
在 AppDelegate.m 中:
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.callManager = [[CallManager alloc] init];
self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
self.pushRegistry.delegate = self;
self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
return YES;
}
#pragma mark - PushKit 处理 VoIP 推送
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
NSString *token = [credentials.token description];
NSLog(@"VoIP Token: %@", token);
// 这里可以将 token 发送到服务器
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type {
NSLog(@"收到 VoIP 推送: %@", payload.dictionaryPayload);
NSUUID *uuid = [NSUUID UUID];
NSString *callerName = @"未知来电";
[self.callManager reportIncomingCallWithUUID:uuid callerName:callerName];
}
@end