首先要说一下,callkit和pushkit的用途。我一开始误会了这个两货的用法导致浪费了很多时间。 callkit是可以让app调出打电话的页面,走打电话的流程,接听,挂掉。大概就是下图这样子。同时让这个通话能出现在通讯录里,所以这个功能一般用于app里的语音聊天,如果配合pushkit就可以实现在锁屏的情况下调出这个页面。
这里我就来简单介绍一下如何集成CallKit与PushKit
要集成,首先就要导入framework,图中的三个framework都要导入,第一个framework是从通讯录中直接拨打App电话所需要的。
Pushkit
首先从这个开始弄吧。
去苹果账号里申请voip的证书,这个证书和普通的推送证书一样,不懂的直接百度一下吧。或者参考这个www.jianshu.com/p/c85a58ab4…
然后在appdelegate里,导入
#import <PushKit/PushKit.h>
复制代码
然后,在didFinishLaunchingWithOptions里,初始化,并实现代理PKPushRegistryDelegate
PKPushRegistry .*pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
复制代码
然后,实现代理方法。如果能收到token代表,配置成功,token配置成功后就可以让后台给你发推送了。
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{ NSLog(@"%@",credentials.token); //应用启动获取token,并上传服务器 token = [[[[credentials.token description] stringByReplacingOccurrencesOfString:@"<"withString:@""] stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""]; }
这个是接受推送的方法
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
至于你想测试推送,由于我个人是兼职java开发,看这个里测试的,blog.csdn.net/m0_37954663…
Callkit
关于这个我觉得比起我干讲,还是先附上demo 感谢这个大大的demo,看完大体上就知道怎么用 github.com/itomorrow/C…
不过个人觉得还是有点复杂,简化了一下,大佬们都很喜欢搞一个CallKitManager来管理,但我并不需求这么复杂,能实现基础功能就完事了。 gitee.com/klkxxy/call…
创建一个文件实现Callkit的代理CXProviderDelegate
#import <CallKit/CallKit.h> **@interface** ProviderDelegate : NSObject<CXProviderDelegate>
里面实现的代理方法,无非就是,接电话,挂电话,打电弧,静音这种功能。
#import "ProviderDelegate.h"
#import <AVFoundation/AVFAudio.h>
@interface ProviderDelegate ()
@property (nonatomic ,strong) CXProvider *provider;
@end
@implementation** ProviderDelegate
static ProviderDelegate *shared = **nil**;
+ (instancetype)shared{
@synchronized(self) {
if (shared == nil) {
shared = [[ProviderDelegate alloc]init];
}
return shared;
}
}
+(void)configureAudioSession{
NSLog(@"Callkit& Configuring audio session");
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:**nil**];
[session setMode:AVAudioSessionModeVoiceChat error:**nil**];
}
//通过设置CXProviderConfiguration来支持视频通话、电话号码处理,并将通话群组的数字限制为 1 个,其实光看属性名大家也能看得懂吧。
- (CXProviderConfiguration *)config{
**static** CXProviderConfiguration* configInternal = **nil**;
**static** dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
configInternal = [[CXProviderConfiguration alloc] initWithLocalizedName:@"我的"];
configInternal.supportsVideo = **NO**;
configInternal.maximumCallsPerCallGroup = 1;
configInternal.maximumCallGroups = 1;
configInternal.supportedHandleTypes = [NSSet setWithObject:@(CXHandleTypePhoneNumber)];
UIImage* iconMaskImage = [UIImage imageNamed:@"IconMask"];
configInternal.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage);
configInternal.ringtoneSound = @"voip_call.caf";
});
**return** configInternal;
}
- (**instancetype**)init{
**if** (**self**) {
//用一个 CXProviderConfiguration 初始化 CXProvider,前者在后面会定义成一个静态属性。CXProviderConfiguration 用于定义通话的行为和能力。
**self**.provider = [[CXProvider alloc]initWithConfiguration:**self**.config];
//为了能够响应来自于 CXProvider 的事件,你需要设置它的委托。
[**self**.provider setDelegate:**self** queue:**nil**];
}
**return** **self**;
}
//这个方法牛逼了,它是用来更新系统电话属性的。。
-(CXCallUpdate *)callUpdate:(NSString *)handle andHasVideo:(BOOL)hasVideo{
CXCallUpdate *update = [[CXCallUpdate alloc]init];
update.localizedCallerName = @"aaaaaaaa";
update.supportsGrouping = **NO**;
update.supportsHolding = **NO**;
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:handle];
update.hasVideo = hasVideo;
**return** update;
}
- (**void**)providerDidReset:(**nonnull** CXProvider *)provider {
}
- (**void**)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action{
//向系统通讯录更新通话记录
CXCallUpdate *update = [**self** callUpdate:action.handle.value andHasVideo:action.isVideo];
[provider reportCallWithUUID:action.callUUID updated:update];
[action fulfill];
}
- (**void**)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession{
//一定要记得播放铃声呐。。
}
//打电话方法
-(**void**)reportIncomingCall:(NSUUID *)uuid andHandle:(NSString *)handle andHasvideo:(**BOOL**)hasVideo andCompletion:(completion2)completion{
CXCallUpdate *update = [**self** callUpdate:handle andHasVideo:hasVideo];
[**self**.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError * **_Nullable** error) {
**if** (!error) {
}
completion(error);
}];
}
//接电话(按钮的返回)
- (**void**)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action{
[ProviderDelegate configureAudioSession];
[action fulfill];
}
//挂电话的按钮,点击事件
- (**void**)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action{
//在这里添加自己App挂断电话的逻辑
[action fulfill];
}
- (**void**)provider:(CXProvider *)provider performSetHeldCallAction:(CXSetHeldCallAction *)action{
[action fulfill];
}
@end
复制代码
感觉看完上面大概就懂了吧。如果实在不懂,下载上面的demo体验一下。
参考文档
www.pianshen.com/article/110… www.jianshu.com/p/c85a58ab4…
demo
作者:庞然大虎
链接:https://juejin.cn/post/7137601079348297741/
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这个是我的掘金账号,哈哈。