iOS : PushKit的使用

因爲最近項目要作關於voip業務,因此在此作個記錄:咱們都知道當應用程序退出到後臺時,socket是會斷開鏈接,程序是被掛起的。咱們如今要作的就是在這種狀況下直接喚醒APP。node

PushKit背景

PushKit是蘋果在ios8蘋果新引入的框架,一種新的push通知類型,被稱做voip push.該push方式旨在提供區別於普通APNs push的能力,PushKit區別與普通APNS的地方是,它不會彈出通知,而是直接喚醒你的APP,進入回調,也就是說,能夠在沒點擊APP啓動的狀況下,就運行咱們本身寫的代碼.ios

PushKit官方介紹:(developer.apple.com/documentati…)

PushKit框架將特定類型的通知(例如VoIP邀請,watchOS複雜性更新和文件提供程序更改通知)直接發送到您的應用程序以進行處理。緩存

PushKit通知與您使用UserNotifications框架處理的通知不一樣。具體來講,PushKit通知從不顯示警報,標記應用程序的圖標或播放聲音。與用戶通知相比,它們還具備如下優點:bash

  • 設備僅在收到PushKit通知時纔會喚醒,這能夠延長電池壽命。
  • 收到PushKit通知後,若是應用程序未運行,系統會自動啓動它。相比之下,用戶通知沒法保證啓動您的應用。
  • 系統會爲您的應用執行時間(可能在後臺)處理PushKit通知。
  • PushKit通知可包含比用戶通知更多的數據。

在PushKit中最主要用到的就是PKPushRegistey這個類,首先咱們來分析一下這個類裏面的內容:服務器

/* 目標推送類型 */
PK_EXPORT PKPushType const PKPushTypeVoIP NS_AVAILABLE_IOS(8_0);  //VOIP推送
PK_EXPORT PKPushType const PKPushTypeComplication NS_AVAILABLE_IOS(9_0);   //Watch更新
PK_EXPORT PKPushType const PKPushTypeFileProvider NS_AVAILABLE_IOS(11_0);   //文件傳輸


NS_CLASS_AVAILABLE_IOS(8_0)
@interface PKPushRegistry : NSObject

@property (readwrite,weak,nullable) id<PKPushRegistryDelegate> delegate;    //代理對象

@property (readwrite,copy,nullable) NSSet<PKPushType> *desiredPushTypes;

//獲取本地緩存的Token  申請Token執行回調後 這個方法能夠直接獲取緩存
- (nullable NSData *)pushTokenForType:(PKPushType)type;

//初始化,並設置工做線程
- (instancetype)initWithQueue:(nullable dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;

@end

@protocol PKPushRegistryDelegate <NSObject>

@required

//申請Token更新後回調方法
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)pushCredentials forType:(PKPushType)type;

@optional

//收到推送後執行的回調方法
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type NS_DEPRECATED_IOS(8_0, 11_0);

//同上,收到推送後執行的回調方法,最後的block須要在邏輯處理完成後主動回調
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void(^)(void))completion NS_AVAILABLE_IOS(11_0);

//Token失效時的回調方法
- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type;

@end

NS_ASSUME_NONNULL_END

複製代碼

PushKit證書申請

跟APNs push相似,PushKit的voip push也須要申請證書的,申請證書步驟以下: app

申請.png

按申請步驟操做就能夠完成,相信你們都有申請證書的經驗,在這裏就很少嘴了。 生成證書以後把它下載,雙擊安裝到KeyChain中便可,這裏須要在KeyChain裏把VoIP證書的密鑰導出成.p12格式,發給你的後臺人員。(這裏關於後臺具體使用的證書格式,根據狀況而定,咱們一般是把.p12文件通過nodes命令生成.pem文件給後臺使用)框架

項目配置

和APNS同樣,須要在Project-> Capabilities裏打開推送開關和配置後臺,Background Modes裏把Voice over IP選項打開,同時把Background fetch ,Remote notification選項一塊兒打開,並在Build Phases中加入PushKit.framework。socket

VoIP.png

聽說Xcode9的Background Modes中是沒有Voice over IP這個選項的,(我用的是Xcode10.2,仍是有這個選項的)若是沒有的話,能夠手動在info.plist文件中加入,在Required background modes裏面添加一項 App provides Voice over IP services。ide

簡單代碼實現

在AppDelagate中須要導入PushKit框架#import <PushKit/PushKit.h> 註冊PushKit,注意PushKit要ios8 及之後纔可使用, 添加代理PKPushRegistryDelegate測試

if (CurrentSystemVersion.floatValue >= 8.0) {
    PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil];
    pushRegistry.delegate = self;
    pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
    }
複製代碼

實現獲取token的代理方法:

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
    NSString * tokenString = [[[[credentials.token description] stringByReplacingOccurrencesOfString: @"<" withString: @""] stringByReplacingOccurrencesOfString: @">" withString: @""] stringByReplacingOccurrencesOfString: @" " withString: @「"]; } 複製代碼

設備從蘋果服務器獲取到了VoIP token,這個token與APNs是不同的。app將收到的token傳遞給push服務器。(流程和APNs相似,可是接受的代理方法和token都是不同的)獲取到的token也是64位的,與APNs同樣,須要去掉<>和空格。

作接收到推送的處理

// iOS 8.0~11.0
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
    
    NSLog(@"收到push");
    
    NSDictionary *dic=payload.dictionaryPayload[@"aps"];
    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.timeZone = [NSTimeZone defaultTimeZone];
    backgroudMsg.alertBody= [dic  objectForKey:@"alert" ];
    backgroudMsg.soundName = [dic objectForKey:@"sound"];
    [[UIApplication sharedApplication] presentLocalNotificationNow:backgroudMsg];
    
}
複製代碼

查看PKPushRegistry.h的文件,在iOS8.0~iOS11.0是使用上面這個代理方法來實現喚醒後的操做,但在iOS11.0以後,系統也提供了另一個方法:

//iOS 11.0以後
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void(^)(void))completion
複製代碼

若是一切正常,就算程序殺掉進程,重啓,退到後臺,服務器推送過來的消息都會走這個代理方法,在這裏爲了能看到推送的內容,這裏我是把接收到的內容生成一個本地的推送發出來了,而且播放聲音,實際上在這個方法裏面應該處理喚醒APP以後的操做。

推送測試

在這裏我在作推送測試的時候使用的是Easy APNs Provider這個應用,使用起來仍是很方便的。 附上下載地址

1.首先要添加所要發送的Token值,這裏有三種添加方式:

添加Token

2.而後並選擇以前建立好的voip_services.cer證書,

3.鏈接至服務器,Debug模式選擇sandbox,Release模式選擇push,

鏈接至服務器.png
以後點擊「鏈接至」按鈕,查看是否鏈接成功。
成功

4.設置發送的內容(推送負載)

5.點擊「發送推送」。

Easy APNs Provider.png
相關文章
相關標籤/搜索