iOS CallKit技術(shù)在APP中的應用方案

CallKit和VoIP在APP中的應用

CallKit framework(<CallKit/CallKit.h>)是蘋果在2016年推出iOS10系統(tǒng)時的新功能,可以調(diào)起系統(tǒng)的接聽頁進行音視頻通話。目前市面上使用該方案的的APP不是很多张弛,所有中國區(qū)在App Store上架的App都不能支持CallKit功能,官方文檔和網(wǎng)上資料對相關(guān)功能的細節(jié)介紹都很有限灯荧。

為什么CallKit被禁用纹蝴?因為蘋果動了不該動的蛋糕!

講CallKit之前不得不先說一下VoIP迹恐,VoIP是什么挣惰?

VoIP(<PushKit/PushKit.h>)是一種新的push通知類型,是蘋果在iOS8中新引入的PushKit框架殴边。

VoIP push和普通APNS push有什么區(qū)別憎茂?

最明顯的區(qū)別就是:APP收到VoIP push消息時會直接將已經(jīng)殺掉的APP激活!

<CallKit/CallKit.h>與<PushKit/PushKit.h>這兩個庫配合使用锤岸,即可形成了一套APP在殺死的情況下竖幔,收到音視頻邀請時持續(xù)響鈴的完整解決方案。

PushKit

PushKit的使用有3步操作是偷,首先遵守<PKPushRegistryDelegate>協(xié)議:

1.注冊拳氢, 在APP啟動代碼里,通過PKPushRegistry注冊VoIP服務(wù)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    PKPushRegistry *pushRegistry = [[PKPushRegistry alloc]  initWithQueue:dispatch_get_main_queue()];
    pushRegistry.delegate = self;
    pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
    return YES;
}
2. 獲取token蛋铆,協(xié)議方法里面獲取token并上傳給對應的服務(wù)馋评,通過Token來進行個推的
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
   // 一般做法
   // NSString *str = [NSString stringWithFormat:@"%@",credentials.token];
   // NSString *tokenStr = [[[str stringByReplacingOccurrencesOfString:@"<" withString:@""]
                           stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""];
}
3. 接收VoIP消息,收到VoIP消息刺啦,調(diào)用CallKit留特,做剩余的通訊邏輯處理
// iOS11之前收到VoIP推送后執(zhí)行的回調(diào) 
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
    [self handleVoipPushMessageWithPayload:payload forType:type];
}

// iOS11之后收到VoIP推送后執(zhí)行的回調(diào) 
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
    [self handleVoipPushMessageWithPayload:payload forType:type];
    if (completion) {
        completion();
    }
}
其他...
// token失效時回調(diào),一般只做打印處理
- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type {
    NSLog(@"之前提供的token失效洪燥,則調(diào)用此方法");
}

- (void)handleVoipPushMessageWithPayload:(PKPushPayload *)payload forType:(PKPushType)type {
    //開啟后臺任務(wù)(實踐發(fā)現(xiàn)如果不開啟后臺任務(wù)磕秤,調(diào)不起系統(tǒng)的CallKit接聽界面)
    [self startBgTask];
    NSDictionary *dic = payload.dictionaryPayload;
   // 這里調(diào)用CallKit
}

// 開啟后臺延時
- (void)startBgTask {
    UIApplication *application = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask;
    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:bgTask];
    }];
}

CallKit

鎖屏狀態(tài)下樣式
未鎖屏狀態(tài)下樣式

CallKit主要有:CXProvider、CXCallController 2個核心類
CXProvider類用于被叫流程捧韵,主要負責系統(tǒng)-->APP的信息市咆、狀態(tài)傳遞
CXCallController類用于主叫流程,主要負責APP-->系統(tǒng)的信息再来、狀態(tài)傳遞

因為APP業(yè)務(wù)只用到被叫功能蒙兰,所以下面只講被叫流程磷瘤。

CXProvider

主要作用有三個:

  • 調(diào)起系統(tǒng)的電話接聽頁面
  • 銷毀系統(tǒng)的電話接聽頁面
  • 代理方法中接收用戶的操作事件,如接聽搜变、掛斷..

APP內(nèi)是如何調(diào)起系統(tǒng)的接聽頁面的采缚?

    self.callUpdate.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:self.channelId];;
    self.callUpdate.hasVideo = NO;
    self.callUpdate.localizedCallerName = self.netCallDict[SFIMVoip_FromName];
    __weak __typeof(self) wself = self;
    [self.provider reportNewIncomingCallWithUUID:[NSUUID UUID]
                                          update:self.callUpdate
                                      completion:^(NSError *_Nullable error) {
        if (error) {
            NSLog(@"通話創(chuàng)建失敗  current error %@", error.userInfo);
            //通話創(chuàng)建失敗
            [wself resetVariableData];
        }
    }];

調(diào)起CallKit接聽頁面過程中,用到了CXHandle挠他、CXCallUpdate扳抽、CXProvider、CXProviderConfiguration四個類

CXProvider的初始化及代理設(shè)置

        self.provider = [[CXProvider alloc] initWithConfiguration:self.configuration];
        [self.provider setDelegate:self queue:nil];

CXProvider的詳細用法

//初始化方法 使用CXProviderConfiguration來進行配置
- (instancetype)initWithConfiguration:(CXProviderConfiguration *)configuration;

//設(shè)置代理與代理函數(shù)所工作的線程
- (void)setDelegate:(nullable id)delegate queue:(nullable dispatch_queue_t)queue;

//向系統(tǒng)發(fā)起一個新的通話請求
/*
UUID為此通話請求的標識 可以使用它來關(guān)閉通話
update設(shè)置界面的更新參數(shù)
*/
- (void)reportNewIncomingCallWithUUID:(NSUUID *)UUID update:(CXCallUpdate *)update completion:(void (^)(NSError *_Nullable error))completion;

//結(jié)束某個通話 使用上面的UUID作為標識
- (void)reportCallWithUUID:(NSUUID *)UUID endedAtDate:(nullable NSDate *)dateEnded reason:(CXCallEndedReason)endedReason;

CXProviderConfiguration

Provider的配置殖侵,例如設(shè)置通訊服務(wù)名稱贸呢,鈴聲,圖標

//設(shè)置服務(wù)名稱
@property (nonatomic, readonly, copy) NSString *localizedName;
//設(shè)置鈴聲  資源必須在 app的 bundle里
@property (nonatomic, strong, nullable) NSString *ringtoneSound;
//設(shè)置應用圖標
@property (nonatomic, copy, nullable) NSData *iconTemplateImageData;
//設(shè)置最大支持的組數(shù) 默認為2
@property (nonatomic) NSUInteger maximumCallGroups;
//設(shè)置最大的每組人數(shù) 默認為5
@property (nonatomic) NSUInteger maximumCallsPerCallGroup;
//設(shè)置是否將通話記錄保存進最近通話列表
@property (nonatomic) BOOL includesCallsInRecents;
//設(shè)置是否支持視頻通話
@property (nonatomic) BOOL supportsVideo;
//設(shè)置支持的操作類型
@property (nonatomic, copy) NSSet *supportedHandleTypes;

CXHandle中來定義操作的類型拢军,通話對方的信息

//類型
/*
typedef NS_ENUM(NSInteger, CXHandleType) {
    CXHandleTypeGeneric = 1,//通用
    CXHandleTypePhoneNumber = 2,//電話
    CXHandleTypeEmailAddress = 3,//郵箱地址
} API_AVAILABLE(ios(10.0));
*/
@property (nonatomic, readonly) CXHandleType type;
//值
@property (nonatomic, readonly, copy) NSString *value;

- (instancetype)initWithType:(CXHandleType)type value:(NSString *)value 

CXCallUpdate類

有點類似CXProviderConfiguration,也是一些配置信息

//遠程操作對象 如果是接收方 則此為呼叫方
@property (nonatomic, copy, nullable) CXHandle *remoteHandle;
//名稱
@property (nonatomic, copy, nullable) NSString *localizedCallerName;
//是否支持暫時掛起
@property (nonatomic) BOOL supportsHolding;
//是否支持組
@property (nonatomic) BOOL supportsGrouping;
//是否支持非組通話
@property (nonatomic) BOOL supportsUngrouping;
//是否支持DTMF
@property (nonatomic) BOOL supportsDTMF;
//是否包含視頻
@property (nonatomic) BOOL hasVideo;

可以動態(tài)更改provider的配置信息

- (void)reportCallWithUUID:(NSUUID *)UUID updated:(CXCallUpdate *)update;

CXProviderDelegate

按鈕的回調(diào)方法(每個回調(diào)結(jié)束的時候要執(zhí)行[action fulfill]楞陷,如果邏輯處理異常則調(diào)用failtimeout函數(shù)提示通話失敗)

// 點擊接聽按鈕的回調(diào)
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action;
// 點擊結(jié)束按鈕的回調(diào)(結(jié)束或拒絕通話)
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action;

結(jié)束通話茉唉,銷毀CallKit

[self.provider reportCallWithUUID:self.currentUUID endedAtDate:nil reason:CXCallEndedReasonRemoteEnded];

CallKit和VoIP的技術(shù)并不難固蛾,只是開發(fā)過程中調(diào)試比較麻煩、浪費時間度陆。因為涉及到推送沒法在模擬器上斷點調(diào)試艾凯,只能打包真機安裝驗證,所以建議開發(fā)過程中一定要多加打印日志坚芜,因為后期只能通過日志觀察览芳、解決問題斜姥。

歡迎留言交流....

參考資料:
iOS10適配之 CallKit

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸿竖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铸敏,更是在濱河造成了極大的恐慌缚忧,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杈笔,死亡現(xiàn)場離奇詭異闪水,居然都是意外死亡,警方通過查閱死者的電腦和手機蒙具,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門球榆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人禁筏,你說我怎么就攤上這事持钉。” “怎么了篱昔?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵每强,是天一觀的道長始腾。 經(jīng)常有香客問我,道長空执,這世上最難降的妖魔是什么浪箭? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮辨绊,結(jié)果婚禮上奶栖,老公的妹妹穿的比我還像新娘。我一直安慰自己门坷,他們只是感情好驼抹,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拜鹤,像睡著了一般框冀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敏簿,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天明也,我揣著相機與錄音,去河邊找鬼惯裕。 笑死温数,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蜻势。 我是一名探鬼主播撑刺,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼握玛!你這毒婦竟也來了够傍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挠铲,失蹤者是張志新(化名)和其女友劉穎冕屯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拂苹,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡安聘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓢棒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浴韭。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖脯宿,靈堂內(nèi)的尸體忽然破棺而出念颈,到底是詐尸還是另有隱情,我是刑警寧澤嗅绰,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布舍肠,位于F島的核電站搀继,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏翠语。R本人自食惡果不足惜叽躯,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肌括。 院中可真熱鬧点骑,春花似錦、人聲如沸谍夭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽紧索。三九已至袁辈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間珠漂,已是汗流浹背晚缩。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留媳危,地道東北人荞彼。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像待笑,于是被迫代替她去往敵國和親鸣皂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容