Question:pushkit是什麼?
Answer:ios8蘋果新引入了名為pushkit的架構和一種新的push通知類型,被稱作voip push.該push方式旨在提供差別于普通apns push的能力,通過這種push方式可以使app執行制定的代碼(在彈出通知給使用者之前);而該通知的預設行為和apns通知有所差別,它的預設行為裡面是不會彈出通知的。目前來看push kit的用途還局限于voip push(根據筆者的實戰經驗來看,其他類型的push暫時不能夠起作用,sdk也正處于演進中)。
Question: pushkit能幫我們做什麼?
Answer:pushkit中的voippush,可以幫助我們提升voip應用的體驗,優化voip應用的開發實作,降低voip應用的電量消耗,它需要我們重新規劃和設計我們的voip應用,進而得到更好的體驗(voip push可以說是準實時的,實側延時1秒左右);蘋果的目的是提供這樣一種能力,可以讓我們抛棄背景長連接配接的方案,也就是說應用程式通常不用維持和voip伺服器的連接配接,在呼叫或者收到呼叫時,完成voip伺服器的注冊;當程式被殺死或者手機重新開機動時,都可以收到對方的來電,正常開展voip的業務。也就是說,我們目前可以利用它來優化voip的體驗,增加接通率;條件成熟時我們就可以完全放棄背景的長連接配接,走到蘋果為我們規劃的道路上。
對于pushkit,除了蘋果framework官方文檔:https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternet/Reference/PushKit_Framework/index.html#protocols 以外,能夠找到的幫助了解pushkit的莫過于wwdc的視訊:712_sd_writing_energy_efficient_code_part_2。該視訊也可以從蘋果官網下載下傳。
pushkit的局限:
在目前,pushkit僅支援ios8;且該功能正處于演進中,穩定性和在不同ios8小版本裝置上的表現也可能有差異,在蘋果開發者論壇上也有不少人回報問題;根據經驗,在下個大版本(也就是ios9)上可以期待該功能可以穩定下來。
如果需要在ios8之前的裝置上支援pushkit功能,那麼需要開發者付出很多額外的努力,這裡不展開,有興趣的同學可以到蘋果論壇的相關闆塊去了解,有一些開發者在這方面走的比較遠:
在下面的連結中搜尋pushkit關鍵字,可以查找到相關内容:https://devforums.apple.com/community/ios/connected/push
在簡單介紹了pushkit和它能做的事并且了解到它的局限以後,還對pushkit感興趣的童鞋可以往下繼續看了(:)為了避免浪費大家的寶貴時間)。
pushkit的voip功能的實作:
1.跟apns push類似,pushkit的voippush也需要申請證書(apns證書的申請流程參考:https://www.pushwoosh.com/programming-push-notification/ios/ios-configuration-guide/);voip push的證書申請步驟截圖如下:

2.使用該證書導出并加載到push伺服器上,伺服器側無需做改動,僅替換證書相關的東西即可(具體流程和此前apns證書的加載完全類同);伺服器和用戶端的互動流程也基本類似。
3.用戶端實作:
step1:在工程中添加pushkit;
step2:在工程設定裡面的backgroundmode裡面添加voip、backgroundfetch、remotenotifications的支援。
step3:保險起見,建議開發者使用最新版本的xcode和最新的sdk;也建議重新申請一個mobile provision檔案用于打包。
step4:類似apns通知的用戶端實作流程,voip push用戶端相關的流程也類似:注冊voip push通知,實作pushkit相關的代理。
貼出主要代碼:
在應用啟動(appdelegate的didfinishlaunchwithoptions)後或根控制器的初始化等方法内調用如下代碼:
PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
UIUserNotificationSettings *userNotifySetting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:userNotifySetting];
上面的代碼實作了在應用啟動時對voip push的注冊;
在appdelegate或架構viewcontroller類中實作voip push的代理:
@interface EPTabBarController : UITabBarController<PKPushRegistryDelegate>
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
{
if([credentials.token length] == 0)
{
NSLog(@"voip token NULL");
return;
}
ZeroPush * push = [[ZeroPush alloc] init];
// push.apiKey = @"iosdev_1Z6JR3PKBWrAWbuHLbLQ";
push.apiKey = @"iosprod_HZDimW5ssYsRQgaSaEoE";
// iosprod_HZDimW5ssYsRQgaSaEoE
[push registerDeviceToken:credentials.token channel:@"me"];
}
我們這裡對接的push伺服器是zeropush提供的服務;後面我們會大概介紹下該服務;上面的代理方法是裝置從蘋果伺服器擷取到了voip token,然後傳遞給應用程式;我們需要把這個token傳遞到push伺服器(和apns push類似,我們也是要傳遞apns token到push伺服器,但是這兩個token的擷取方式不同,分别在不同的代理方法中回調給應用,且這兩個token的内容也是不同的)。
push server在擷取到使用者的voip token之後,在一切正常的情況下,另外一個回調會在push server下發消息到對應token的裝置時被觸發。
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
NSLog(@"didReceiveIncomingPushWithPayload");
// 此時進行voip注冊
// write your voip related codes here
UIUserNotificationType theType = [UIApplication sharedApplication].currentUserNotificationSettings.types;
if (theType == UIUserNotificationTypeNone)
UIUserNotificationSettings *userNotifySetting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:userNotifySetting];
UILocalNotification *backgroudMsg = [[UILocalNotification alloc] init];
backgroudMsg.alertBody= NSInternationalString(@"You receive a new call",nil);
[[UIApplication sharedApplication] presentLocalNotificationNow:backgroudMsg];
上面的回調代碼裡僅僅列印了日志,觸發了一個本地通知;這個代理方法是收到voip push通知時觸發的;如果一切正常,該通知在手機重新開機、應用被系統回收、手動kill程式的情況下,依然能夠被觸發,且可以有一段時間用來執行自己的代碼(比如voip注冊等)。
我們這裡簡單設計一個業務供大家參考,主要是為了讓大家直覺的認識到pushkit的能力:
1.應用的voip長連接配接不保持,在收到呼叫或者發起呼叫時再連接配接;
2.當呼叫發送到voip 伺服器時,對端若不線上,通過voip 伺服器連接配接到pushserver向對端發push通知;
3.應用收到voip push通知時,迅速完成注冊;
4.呼叫方通過延時操作等邏輯(複雜一點對voip伺服器進行改造,被叫連接配接上來以後通知到主叫側),再次發起呼叫,通話即成功建立。
zero push的介紹:https://www.zeropush.com/
zero push的技術支援郵箱:[email protected]
筆者曾就一個證書相關的問題嘗試給該郵箱發信,很快得到了滿意的答複,非常棒!
zero push 提供了一個免費試用的服務,這讓我們體驗voip push非常友善;
按照它的提示,新增賬號,然後建立應用,上傳voip 證書,從網頁上擷取到它的apikey(這個key在上傳token之前要用到,在上面的代理方法中)。
下面是它對voip push的介紹文章,最後面是demo工程的github連結:
https://www.zeropush.com/guide/guide-to-pushkit-and-voip
需要注意的是,該工程使用swift語言編寫,如果你的證書和provision檔案等都是之前申請的,隻用于oc建立的工程,那麼該工程在真機運作時很可能會閃退;解決辦法是重新生成你的證書和provision檔案,并使用到工程中,然後重新打包,該問題即可得到解決了。
最後,歡迎大家任何形式的關于本課題的探讨~我留意到國内關于本課題的中文資料或者實踐總結非常少,絕大部分都是英文的,希望和大家一起多多積累,共同進步~
我的郵箱: [email protected]