iOS:PushKit的使用

由于最近項目要做關(guān)于voip業(yè)務(wù),所以在此做個記錄:我們都知道當(dāng)應(yīng)用程序退出到后臺時,socket是會斷開連接,程序是被掛起的。我們現(xiàn)在要做的就是在這種情況下直接喚醒APP。

PushKit背景

PushKit是蘋果在ios8蘋果新引入的框架,一種新的push通知類型,被稱作voip push.該push方式旨在提供區(qū)別于普通APNs push的能力,PushKit區(qū)別與普通APNS的地方是,它不會彈出通知,而是直接喚醒你的APP,進入回調(diào),也就是說,可以在沒點擊APP啟動的情況下,就運行我們自己寫的代碼.

PushKit官方介紹:(https://developer.apple.com/documentation/pushkit?language=objc)

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

PushKit通知與您使用UserNotifications框架處理的通知不同。具體來說,PushKit通知從不顯示警報,標(biāo)記應(yīng)用程序的圖標(biāo)或播放聲音。與用戶通知相比,它們還具有以下優(yōu)勢:

  • 設(shè)備僅在收到PushKit通知時才會喚醒,這可以延長電池壽命。
  • 收到PushKit通知后,如果應(yīng)用程序未運行,系統(tǒng)會自動啟動它。相比之下,用戶通知無法保證啟動您的應(yīng)用。
  • 系統(tǒng)會為您的應(yīng)用執(zhí)行時間(可能在后臺)處理PushKit通知。
  • PushKit通知可包含比用戶通知更多的數(shù)據(jù)。

在PushKit中最主要用到的就是PKPushRegistey這個類,首先我們來分析一下這個類里面的內(nèi)容:

/* 目標(biāo)推送類型 */
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執(zhí)行回調(diào)后 這個方法可以直接獲取緩存
- (nullable NSData *)pushTokenForType:(PKPushType)type;

//初始化,并設(shè)置工作線程
- (instancetype)initWithQueue:(nullable dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;

@end

@protocol PKPushRegistryDelegate <NSObject>

@required

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

@optional

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

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

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

@end

NS_ASSUME_NONNULL_END

PushKit證書申請

跟APNs push類似,PushKit的voip push也需要申請證書的,申請證書步驟如下:


申請.png

按申請步驟操作就可以完成,相信大家都有申請證書的經(jīng)驗,在這里就不多嘴了。
生成正式之后把它下載,雙擊安裝到KeyChain中即可,這里需要在KeyChain里把VoIP證書的密鑰導(dǎo)出成.p12格式,發(fā)給你的后臺人員。(這里關(guān)于后臺具體使用的證書格式,根據(jù)情況而定,我們通常是把.p12文件經(jīng)過nodes命令生成.pem文件給后臺使用)

項目配置

和APNS一樣,需要在Project-> Capabilities里打開推送開關(guān)和配置后臺,Background Modes里把Voice over IP選項打開,同時把Background fetch ,Remote notification選項一起打開,并在Build Phases中加入PushKit.framework。

VoIP.png

據(jù)說Xcode9的Background Modes中是沒有Voice over IP這個選項的,(我用的是Xcode10.2,還是有這個選項的)如果沒有的話,可以手動在info.plist文件中加入,在Required background modes里面添加一項 App provides Voice over IP services。

簡單代碼實現(xiàn)

在AppDelagate中需要導(dǎo)入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];
        }

實現(xiàn)獲取token的代理方法:

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

設(shè)備從蘋果服務(wù)器獲取到了VoIP token,這個token與APNs是不一樣的。app將收到的token傳遞給push服務(wù)器。(流程和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是使用上面這個代理方法來實現(xiàn)喚醒后的操作,但在iOS11.0之后,系統(tǒng)也提供了另外一個方法:

//iOS 11.0之后
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void(^)(void))completion

如果一切正常,就算程序殺掉進程,重啟,退到后臺,服務(wù)器推送過來的消息都會走這個代理方法,在這里為了能看到推送的內(nèi)容,這里我是把接收到的內(nèi)容生成一個本地的推送發(fā)出來了,并且播放聲音,實際上在這個方法里面應(yīng)該處理喚醒APP之后的操作。

推送測試

在這里我在做推送測試的時候使用的是Easy APNs Provider這個應(yīng)用,使用起來還是很方便的。 附上下載地址
1.首先要添加所要發(fā)送的Token值,這里有三種添加方式:

添加Token

2.然后并選擇之前創(chuàng)建好的voip_services.cer證書,

3.連接至服務(wù)器,Debug模式選擇sandbox,Release模式選擇push,
連接至服務(wù)器.png

之后點擊“連接至”按鈕,查看是否連接成功。
成功

4.設(shè)置發(fā)送的內(nèi)容(推送負(fù)載)
5.點擊“發(fā)送推送”。


Easy APNs Provider.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容