iOS遠(yuǎn)程推送詳解

Paste_Image.png

從上圖我們可以看到:
1、應(yīng)用程序注冊消息推送。
2、iOS從APNS Server獲取device token,應(yīng)用程序接收device token。
3、應(yīng)用程序?qū)evice token發(fā)送給PUSH服務(wù)端程序。
4、服務(wù)端程序向APNS服務(wù)發(fā)送消息。
5、APNS服務(wù)將消息發(fā)送給iPhone應(yīng)用程序。

關(guān)于deviceToken:

deviceToken生成:

遠(yuǎn)程通知首先要向蘋果APNs服務(wù)器注冊并且生成一個唯一的deviceToken(每個設(shè)備的客戶端都獨(dú)一無二)。根據(jù)向APNs服務(wù)器發(fā)送的Token key(包含了設(shè)備的UUID和App的Bundle Identifier)。deviceToken將會以NSData對象發(fā)送到對應(yīng)請求的App上。然后App把此deviceToken發(fā)送給我們自己的服務(wù)器,就是所謂的Provider。Provider收到deviceToken以后進(jìn)行儲存等相關(guān)處理,以后Provider根據(jù)這個deviceToken來進(jìn)行消息推送。

deviceToken用處:

deviceToken是推送服務(wù)器(Provider)在向應(yīng)用推送消息時,找到對應(yīng)的設(shè)備以及該設(shè)備上對應(yīng)的應(yīng)用,從而把此推送消息推送給此應(yīng)用。

deviceToken唯一性:

deviceToken根據(jù)設(shè)備唯一標(biāo)識和客戶端唯一標(biāo)識生成。確保了deviceToken唯一。唯一性并不是說一臺設(shè)備上的一個應(yīng)用程序永遠(yuǎn)只有一個deviceToken,當(dāng)用戶升級系統(tǒng)的時候deviceToken是會變化的。

注冊遠(yuǎn)程通知(獲取deviceToken)

注冊遠(yuǎn)程通知的方法

一般都是在App啟動完成的時候去注冊遠(yuǎn)程通知注冊方法調(diào)用一般都在didFinishLaunchingWithOptions:方法中

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

// 在iOS8之前注冊遠(yuǎn)程通知的方法,如果項(xiàng)目要支持iOS8以前的版本,必須要寫此方法
UIRemoteNotificationTypetypes=UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert;   

[[UIApplicationsharedApplication] registerForRemoteNotificationTypes:types];

// iOS8之后注冊遠(yuǎn)程通知的方法
UIUserNotificationTypetypes=UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
UIUserNotificationSettings*mySettings =[UIUserNotificationSettingssettingsForTypes:types categories:nil];    
[[UIApplicationsharedApplication] registerUserNotificationSettings:mySettings];
}

處理注冊遠(yuǎn)程通知的回調(diào)方法

// 注冊成功回調(diào)方法,其中deviceToken即為APNs返回的token

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {  

 [self sendProviderDeviceToken:deviceToken];// 將此deviceToken發(fā)送給Provider

}

// 注冊失敗回調(diào)方法,處理失敗情況

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {}

處理接收到遠(yuǎn)程通知消息分兩種情況:前臺和后臺
application: didFinishLaunchingWithOptions:此方法在程序在第一次啟動時調(diào)用,根據(jù)方法內(nèi)代碼判斷是否有推送消息。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 // userInfo為收到遠(yuǎn)程通知的內(nèi)容 
NSDictionary*userInfo=launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
 if (userInfo) { 
// 有推送的消息,處理推送的消息
 } 
return YES;
}

各種狀態(tài)下APP收到消息以及處理:

首先不管在前臺還是在后臺,如果設(shè)置后臺模式為Remote Notifications
具體設(shè)置方式(或者在info.plist中配置了UIBackgroundModes):如圖
TARGETS-Capabilities-Background Modes-Remote Notifications



此時不論App處于Foreground狀態(tài)還是處于Background狀態(tài),收到遠(yuǎn)程推送消息的時候都會立即調(diào)用此方法。

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ }

這里引入一個概念:
**推送喚醒(remote notifications)
**iOS7以前,當(dāng)你收到推送消息時,你需要先打開應(yīng)用,等待應(yīng)用從網(wǎng)絡(luò)上獲取推送的信息之后,才能將信息呈現(xiàn)出來。而iOS7改變了這一過程。當(dāng)系統(tǒng)收到推送消息時,不是首先提醒用戶,而是喚醒對應(yīng)的應(yīng)用,讓應(yīng)用在后臺獲取對應(yīng)的信息。當(dāng)信息處理完成后,再提醒用戶。一個很小的改變,但是可以很大的提升用戶體驗(yàn)。同樣,iOS系統(tǒng)也會限制這種推送消息的頻率,防止系統(tǒng)被頻繁喚醒影響續(xù)航。

此時需要更改推送的payload,如果想要使用推送來喚醒應(yīng)用運(yùn)行代碼的話,需要在payload中加入content-available,并設(shè)置為1。

aps {
     content-available: 1  
     alert: {...}
 }

1.程序在前臺(Foreground)時收到推送:
如果設(shè)置remote notifications,那么先執(zhí)行相對應(yīng)的方法,在后臺收到推送也是如此。
在前臺收到通知時,會調(diào)用下面這個方法,可以在這個方法里面實(shí)現(xiàn)收到通知時刷新或跳轉(zhuǎn)界面的功能;程序在前臺收到推送時通知欄不會彈出推送信息

-(void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo{}

2.程序在后臺時收到推送:
如果設(shè)置remote notifications,那么先執(zhí)行相對應(yīng)的方法,在前臺收到推送也是如此。
如果用戶點(diǎn)擊通知欄信息進(jìn)入程序會調(diào)用情況1中的方法,所以在情況1的方法里面需要根據(jù)程序在前臺還是后臺來執(zhí)行不同操application.applicationState

3.當(dāng)程序關(guān)閉時收到推送:程序關(guān)閉時收到推送時,用戶點(diǎn)擊通知欄信息進(jìn)入應(yīng)用的時會調(diào)用

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 // 在此方法中一定要調(diào)用completionHandler這個回調(diào),告訴系統(tǒng)是否處理成功
 UIBackgroundFetchResultNewData, // 成功接收到數(shù)據(jù) UIBackgroundFetchResultNoData, // 沒有接收到數(shù)據(jù) UIBackgroundFetchResultFailed // 接受失敗
 if (userInfo) { 
completionHandler(UIBackgroundFetchResultNewData);
 } else {
 completionHandler(UIBackgroundFetchResultNoData); 
}
}

可操作通知類型收到推送消息時回調(diào)方法

// 此兩個回調(diào)方法對應(yīng)可操作通知類型,具體使用方法參考以上方法很容易理解,不在詳細(xì)敘述
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {


}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler {


}

未讀消息數(shù)量角標(biāo)設(shè)置
設(shè)置角標(biāo)

[UIApplication sharedApplication].applicationIconBadgeNumber=badgeNum;

這個方法可以設(shè)置應(yīng)用程序的角標(biāo)的數(shù)值。但是當(dāng)程序關(guān)閉時,收到推送后我們就不能改變角標(biāo)數(shù)值了。所以建議讓服務(wù)端推送過來的信息里加上'badge' = 88這個鍵值對來確定角標(biāo)的顯示數(shù)值。這樣程序在后臺還是關(guān)閉,只要顯示服務(wù)端傳給我們的角標(biāo)值就好了。
不過當(dāng)我們閱讀完一條消息的時需要告訴服務(wù)器,并且將[UIApplication sharedApplication].applicationIconBadgeNumber減一。

當(dāng)客戶端殺死情況走本地推送(當(dāng)客戶端開啟走—(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)。

 if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        
        // 當(dāng)被殺死狀態(tài)收到本地通知時執(zhí)行的跳轉(zhuǎn)代碼
        UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
        NSDictionary *infoDict = [mnResource parseJSONStringToNSDictionary:notification.userInfo[@"info"]];

            [self.delegate diaplayAlertWhenReceivePushInfo:infoDict];
     
  }

到現(xiàn)在為止做iOS 推送也差不多算入行了吧(都是用的個推)
昨天調(diào)試個推送也讓我蛋疼,調(diào)試了一晚上,其他系統(tǒng)的沒什么問題,就有個手機(jī)是iOS 10.0.2的系統(tǒng),不知道為什么走不通apns。

遇到這些問題不要慌,先定為到問題。下面列舉自己踩過的個推方面的坑:

1.打包的證書與個推后臺的證書環(huán)境不一致,導(dǎo)致推送失敗。
2.服務(wù)端忘記設(shè)置了個推安卓和ios的key,沒有區(qū)分,所以會向客戶端下發(fā)兩條推送,那是我解析的時候是蒙蔽的,json解析出來怎么會有兩種key完全不同的字典。這時候alert很大幾率顯示null且不能跳轉(zhuǎn),因?yàn)槟憬馕霾怀鰜怼?br> 3.上面那種講到的情況,自己分析應(yīng)該是

這里在說明一點(diǎn)在使用個推的時候上傳個推平臺的.p12要和打包的證書環(huán)境一致哦(生產(chǎn)環(huán)境和調(diào)試環(huán)境)
參考:http://www.itdecent.cn/p/4b947569a548

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

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

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