極光推送的使用
蘋果的APNS

- 用戶的應用注冊了
APNS
消息推送功能 - 用戶
iOS
設備通過SSL長連接到APNS蘋果服務器,收到設備應用的注冊信息后,下發給設備一個DeviceToken
給 應用 - 應用收到這個
DeviceToken
然后推送給 自己應用的服務器 (應用到推送服務器的流程完畢) - 推送服務器 發送消息到一個用戶的時候, 會首先查找到
DeviceToken
,然后將消息和DeviceToken
發送給 蘋果的 APNS 服務器 - 蘋果根據
DeviceToken
找到唯一的那台設備, 然后將消息 傳遞過去 - 設備收到了消息后, 會根據
DeviceToken
找到應用 (推送服務器到設備應用的流程完畢)
極光推送的流程

這里和上面唯一不同的就是, 應用的服務器改為了 極光的服務器
- 設備獲取到
DeviceToken
后 需要將這個 信息 上傳到 極光的 服務器上面 - 然后 極光的服務器會 生成一個
registrationID
給應用 - 這個時候, 我們可以給應用注冊一個別名, 就相當於一個 鍵值對, 極光服務器根據這個別名查找到
registrationID
, 然后又根據registrationID
找到DeviceToken
, 這樣 發送消息的時候 , 就可以將DeviceToken
和 信息一起發送給 蘋果的APNS服務器
了.
實際編程的注意點

1、極光后台的生成環境和發布環境證書必須有效

2、 應用需要先注冊和激活極光服務

- 應用獲取到APNS下發的
DeviceToken
后,需要上傳到極光服務器 - 應用的極光登錄成功方法回調,說明服務器已經收到的應用的設備信息,並且返回了
registrationID
- 只有在
registrationID
返回之后,才可以設置別名
補充信息
kJPFNetworkDidLoginNotification
uid:939xxx3544
registrationID:141fe1daxxx927a72d
代碼中方法的調用順序 , 一定要嚴格按照如下的順序
1、添加初始化APNs代碼添加初始化APNs代碼
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //Required //notice: 3.0.0及以后版本注冊可以這樣寫,也可以繼續用之前的注冊方式 JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init]; entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound; if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { // 可以添加自定義categories // NSSet<UNNotificationCategory *> *categories for iOS10 or later // NSSet<UIUserNotificationCategory *> *categories for iOS8 and iOS9 } [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
2、 APNS后 啟動極光服務
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Required // init Push // notice: 2.1.5版本的SDK新增的注冊方法,改成可上報IDFA,如果沒有使用IDFA直接傳nil // 如需繼續使用pushConfig.plist文件聲明appKey等配置內容,請依舊使用[JPUSHService setupWithOption:launchOptions]方式初始化。 [JPUSHService setupWithOption:launchOptions appKey:appKey channel:channel apsForProduction:isProduction advertisingIdentifier:advertisingId]; }
2、 注冊APNs成功並上報DeviceToken 到極光的后台
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [JPUSHService registerDeviceToken:deviceToken]; }
2.5 、 實現注冊APNs失敗接口(可選)
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { //Optional NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error); }
3 、 添加處理APNs通知回調方法
請在AppDelegate.m實現該回調方法並添加回調方法中的代碼
下面的回調方法,其實就是上面注冊極光時的JPUSHRegisterDelegate
代理方法
#pragma mark- JPUSHRegisterDelegate // iOS 10 Support // 展示推送之前觸發,可以在此替換推送內容,更改展示效果:內容、聲音、角標。 - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler { // Required NSDictionary * userInfo = notification.request.content.userInfo; if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { [JPUSHService handleRemoteNotification:userInfo]; } completionHandler(UNNotificationPresentationOptionAlert); // 需要執行這個方法,選擇是否提醒用戶,有Badge、Sound、Alert三種類型可以選擇設置 } // iOS 10 Support // 在收到推送后觸發 - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { // Required NSDictionary * userInfo = response.notification.request.content.userInfo; if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { [JPUSHService handleRemoteNotification:userInfo]; } completionHandler(); // 系統要求執行這個方法 } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // Required, iOS 7 Support [JPUSHService handleRemoteNotification:userInfo]; completionHandler(UIBackgroundFetchResultNewData); } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { // Required,For systems with less than or equal to iOS6 [JPUSHService handleRemoteNotification:userInfo]; }
關於極光 代理的兩個方法調用順序
關於極光推送 iOS 兩個方法什么時候走的問題
官方說明
4、如果項目中需要接收自定義信息的功能, 則需要添加監聽自定義消息的方法 (可選)
只有在前端運行的時候才能收到自定義消息的推送。
從jpush服務器獲取用戶推送的自定義消息內容和標題以及附加字段等
獲取iOS的推送內容需要在delegate類中注冊通知並實現回調方法。 在方法didFinishLaunchingWithOptions 加入下面的代碼:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions { NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; [defaultCenter addObserver:self selector:@selector(networkDidReceiveMessage:) name:kJPFNetworkDidReceiveMessageNotification object:nil]; } 並且實現通知的回調方法 networkDidReceiveMessage - (void)networkDidReceiveMessage:(NSNotification *)notification { NSDictionary * userInfo = [notification userInfo]; NSString *content = [userInfo valueForKey:@"content"]; NSDictionary *extras = [userInfo valueForKey:@"extras"]; NSString *customizeField1 = [extras valueForKey:@"customizeField1"]; //服務端傳遞的Extras附加字段,key是自己定義的 }
5、 監聽極光登錄成功的通知,查看是否入庫極光成功, 在這個方法中可以 設置別名; 不過應用的邏輯 是 用戶登錄成功后才可以推送,所以在這里增加了判斷用戶是否登錄的方法。
(void)networkDidLogin:(NSNotification *)notification { DDLog(@"jpush已登錄,通知詳情為%@",notification.userInfo); //向極光注冊別名 User *user = [UserManager sharedInstace].usr; if( user.isLogin && user.device.tmpPushAliasName ){ user.device.pushAliasName = user.device.tmpPushAliasName; } }
6、真機調試該項目,如果控制台輸出以下日志則代表您已經集成成功。
2017-05-17 11:24:05.968565+0800 DDRide[22015:4672102] | JIGUANG | I - [JIGUANGRegistration] ----- register result ----- uid: 942xxxx1223 registrationID:13165fxxxx97541104 2017-05-17 11:24:05.970270+0800 DDRide[22015:4671830] [函數名:-[JpushManager networkDidRegister:]]----[行號:74] jpush已注冊 2017-05-17 11:24:06.108945+0800 DDRide[22015:4672119] | JIGUANG | I - [JIGUANGLogin] ----- login result ----- uid:942xx61223 registrationID:13165ffxxxx7541104 2017-05-17 11:24:06.112224+0800 DDRide[22015:4671830] [函數名:-[JpushManager networkDidLogin:]]----[行號:78] jpush已登錄,通知詳情-(null) 2017-05-17 11:24:06.266877+0800 DDRide[22015:4672102] | JIGUANG | I - [JIGUANGDeviceTokenReport] try to upload device token:152ff6a08ec7927xxxxxxxxxxxe603cd642f5f4cab8cae10ab8e 2017-05-17 11:24:06.437331+0800 DDRide[22015:4672102] | JIGUANG | I - [JIGUANGBadgeNumberReport] set badge:0 succeed 2017-05-17 11:24:06.535148+0800 DDRide[22015:4672119] | JIGUANG | I - [JIGUANGDeviceTokenReport] upload device token success
7、 新增功能 接收本地通知 , 該代理方法已經適配iOS10
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^) (NSInteger))completionHandler; // if (![notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { // 本地通知為notification // } - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler: (void (^)())completionHandler; // if (![response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { // 本地通知為response.notification // }
測試結果
- 模擬器不能測試極光推送,因為只有真機具備
UDID
, 才能夠生成DeviceToken
- 生產環境證書失效,測試失敗
- 登錄成功后,查看
registrationID
為141fe1dxxxx7a72d
,入庫極光成功,馬上測試別名推送(前台),成功 - 后面等待一段時間后,進入后台測試根據
registrationID
推送成功, 推送別名149498xxxx0546
成功. - 更換設備后, 沒有登錄的情況下,
registrationID
變化為13165ffxxxx7541104
- 測試 沒有登錄的時候 后台
registrationID
推送成功 , 別名14949xxxx12183516
- 這里有個需要注意的地方是,如果服務器是根據別名推送,且每次登錄會產生新的別名,那么情況就比較麻煩.
對於單點登錄的問題,
環境: 設備A已經登錄, 設備B同賬戶登錄, 更新了別名, 服務器根據同用戶的舊別名發送一個通知, 設備A接收到通知后,退出登錄.
可以這樣處理.服務器保留上一次的別名和最新的別名.
如果自己的服務器保存的是最新的別名, 根據最新的別名推送,則最新登錄的設備是能夠收到消息,而使用舊的別名,新設備不會接受到, 只有上一個登錄的設備會接收.
因為一個別名對於一個注冊ID, 一個注冊ID則對於一個 DeviceToken
,而一個DeviceToken
則能夠尋找到唯一設備的唯一應用, 這種一一對應的關系,只要某一環出了問題,推送就不可以送達,更不要說設備如果網絡環境差的話,同樣APNS不會推送到設備應用上.
常見問題
1、 iOS 9系統,應用卸載重裝,APNs返回的devicetoken會發生變化,開發者需要獲取設備最新的Registration id。請在kJPFNetworkDidLoginNotification的實現方法里面調用"RegistrationID"這個接口來獲取 RegistrationID。
2、 為什么iOS收不到推送消息?
- iOS接受消息必要條件是:應用程序的證書要和你上傳到jpush portal上的證書對應,如果你的程序是直接在xcode上運行的,你的應用部署環境必須是開發狀態才能收到APNS消息。
- 確認 appKey 在 SDK 客戶端與 Portal 上設置是一致,其他環節也按照文檔正確地操作。
- 檢查 Portal 上上傳的證書,是 APNs (Push) 證書。
- 再次檢查證書選擇是否正確,參考iOS 證書設置指南89。
- 推送時選擇的環境與測試設備的打包環境必須一致。測試說明109
- 嚴肅說明:api推送的時候通過參數 apns_production 來指定推送環境,false為開發環境,true為生產環境。V3 api不帶此參數則默認為生產環境,V3 api封裝的 sdk 默認為開發環境。如果api有傳apns_production則以此值為准。
- 另外,請確認設備網絡是否正常,如果設備離線,期間推送多條,apns服務器只會離線保留一條
3、 應用產生的設備信息是否變化
自iOS9開始,卸載重裝、長時間關閉推送后又打開等情況 會產生新的token,因此有對應的新的registrationID。(如果用了idfa,在用戶沒有選擇限制廣告跟蹤,並且未點擊『還原廣告標識』時,這個值是不會變的,對應的token也不會改變。)
溫馨提示:
* Registration id 需要在執行到kJPFNetworkDidLoginNotification的方法里獲取 * extern NSString * const kJPFNetworkDidReceiveMessageNotification; // 收到自定義消息(非APNS) 其中,kJPFNetworkDidReceiveMessageNotification傳遞的數據可以通過NSNotification中的userInfo方法獲取,包括標題、內容、extras信息等 * 主要是在項目的登錄成功或者自動登錄后,使用用戶的唯一標示進行綁定,或者根據需求添加一些前綴 * 用戶進行退出登錄的方法里添加去除綁定即可,值得注意的是用到即時通訊的話,被擠下線也要去除綁定,已被坑,貼代碼: //沒有值就代表去除 [JPUSHService setTags:[NSSet set]callbackSelector:nil object:self]; [JPUSHService setAlias:@"" callbackSelector:nil object:self]; [JPUSHService setTags:[NSSet set] alias:@"" callbackSelector:nil target:self];