iOS 初探PushKit集成与CallKit集成

去年苹果推出了一套CallKit框架,用于第三方VOIP通话能快速调用手机本地系统通话界面,在体验上可谓是一大进步.所以我曾经着手的项目被要求在iOS 10以上的系统实现对CallKit框架的使用,于是研究了大半月,总算初步搞定了一些功能的实现.

先强调一点,要想实现远程推送能拉起CallKit界面,首先必须要集成苹果在iOS 8推出的推送框架PushKit,因为只有PushKit能在推送到达时将APP从底层唤醒,一般推送无法实现.而只有底层唤醒了APP,才能通过APP的代码逻辑实现CallKit的调用从而展示出原生通话界面.否则消息到达时只会展示普通的推送而不能像电话到来时一样打开原生接听界面.

第一步,需要先集成PushKit,在app启动时的代理方法中注册PushKit(没有远程推送直接打开原生接听界面的需求的可以直接跳到第二步)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //以下注册代码及详细证书配置可以在苹果PushKit官方文档中找到,在此不做赘述,详见:https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html#//apple_ref/doc/uid/TP40015243-CH30-SW1
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue];
    voipRegistry.delegate = self;
    voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
    
}

同时,PushKit提供了代理方法来确认token是否注册成功

#pragma mark --PKPushRegistryDelegate
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type;
{
    NSLog(@"credentialsToken=%@",credentials.token);
}

PushKit注册成功以后,就可以开始集成CallKit了


第二步,集成CallKit.首先在Project-->Build Phases-->Link Binary With Libraries中添加CallKit.framework


然后在消息的入口(MessageManager)实现CallKit的唤起,先声明一个提供者provider

#import <CallKit/CallKit.h>

@interface:MessageManager()

@property(nonatomic,strong)CXProvider * provider;

@end

在MessageManager收到消息时调用方法receiveCallWithName

-(void)receiveCallWithName:(NSString *)name
{
    
    CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
    NSString *remoteNickName = name;
    
    if (!remoteNickName) {
        remoteNickName = @"未知号码";
    }
    
    [callUpdate setLocalizedCallerName:remoteNickName];
    
    [callUpdate setHasVideo:[self isVideoCall]];
    
    CXHandle *calleeHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:remoteNickName];
    [callUpdate setRemoteHandle:calleeHandle];
    [_provider reportNewIncomingCallWithUUID:[NSUUID UUID] update:callUpdate completion:^(NSError *error){
        completion(error);
    }];
}
在Call结束后,调用finishCallWithReason

-(void)finishCallWithReason:(CXCallEndedReason)reason
{
    [_provider reportCallWithUUID:[NSUUID UUID] endedAtDate:nil reason:reason];
}


此时就可以完成CallKit功能的简单集成与实现.


另外:CallKit也有许多代理方法可供实现,分别对应不同情况下的处理,并不复杂,按需实现即可.

#pragma mark - CXProviderDelegate

/// Called when the provider has been reset. Delegates must respond to this callback by cleaning up all internal call state (disconnecting communication channels, releasing network resources, etc.). This callback can be treated as a request to end all calls without the need to respond to any actions
- (void)providerDidReset:(CXProvider *)provider  {
    NSLog(@"CK: Provider did reset");
}

/// Called when the provider has been fully created and is ready to send actions and receive updates
- (void)providerDidBegin:(CXProvider *)provider {
    NSLog(@"CK: Provider did begin");
}

- (BOOL)provider:(CXProvider *)provider executeTransaction:(CXTransaction *)transaction {
    NSLog(@"CK: Provider execute transaction");
    return NO;
}

// If provider:executeTransaction:error: returned NO, each perform*CallAction method is called sequentially for each action in the transaction
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
    NSLog(@"CK: Start Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
    NSLog(@"CK: Answer Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
    NSLog(@"CK: End Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performSetHeldCallAction:(CXSetHeldCallAction *)action {
    NSLog(@"CK: Set Held Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action {
    NSLog(@"CK: Set Muted Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performSetGroupCallAction:(CXSetGroupCallAction *)action {
    NSLog(@"CK: Set Group Call Action");
    [action fulfill];
}
- (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action {
    NSLog(@"CK: Play DTMF Call Action");
    [action fulfill];
}

/// Called when an action was not performed in time and has been inherently failed. Depending on the action, this timeout may also force the call to end. An action that has already timed out should not be fulfilled or failed by the provider delegate
- (void)provider:(CXProvider *)provider timedOutPerformingAction:(CXAction *)action {
    NSLog(@"CK: Provider Timed out");
}

/// Called when the provider's audio session activation state changes.
- (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession {
    NSLog(@"CK: Audio session activated");
}
- (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSession *)audioSession {
    NSLog(@"CK: Audio session deactivated");
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Unity与iOS集成中,互斥锁问题通常是由于使用了多线程导致的。iOS中的UI操作必须在主线程(也称为UI线程)中执行,而Unity中的游戏逻辑通常是在其他线程中执行的。因此,在Unity与iOS集成中,需要使用互斥锁来确保UI操作和游戏逻辑的同步执行。 具体来说,可以使用iOS中的NSLock类来实现互斥锁。在Unity中,可以通过以下方式将NSLock类导入到Unity项目中: 1. 在Unity项目中创建一个Objective-C类,并将其命名为“iOSBridge”。 2. 在iOSBridge.h文件中添加以下代码: ``` #import <Foundation/Foundation.h> @interface iOSBridge : NSObject - (void)lock; - (void)unlock; @end ``` 3. 在iOSBridge.m文件中添加以下代码: ``` #import "iOSBridge.h" @implementation iOSBridge { NSLock *_lock; } - (id)init { if (self = [super init]) { _lock = [[NSLock alloc] init]; } return self; } - (void)lock { [_lock lock]; } - (void)unlock { [_lock unlock]; } @end ``` 4. 在Unity中创建一个C#类,并将其命名为“iOSBridge”。 5. 在iOSBridge.cs文件中添加以下代码: ``` using System.Runtime.InteropServices; public class iOSBridge { [DllImport("__Internal")] private static extern void lock(); [DllImport("__Internal")] private static extern void unlock(); public static void Lock() { lock(); } public static void Unlock() { unlock(); } } ``` 6. 在需要使用互斥锁的地方,可以通过调用iOSBridge类的Lock和Unlock方法来实现互斥锁的功能。 需要注意的是,在使用互斥锁的时候,要确保锁的范围不要太大,否则可能会导致UI卡顿。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值