前言:
說到這個遠程推送,大家知道的應該都挺多的,但用到的估計極光和個推要占一很大部分,這篇博客重點說的就是個推的使用,個推官網的鏈接在這里,它的集成是比較方便的,你可以直接使用Cocoapods集成,待會再下面命令行也會給大家分享出來,這我們還會提到的有它的一個推送流程,還有SDK的一些使用以及在使用的過程中我們需要注意的地方:
先看看個推的推送流程圖:
集成中建議利用Cocoapods集成,建議還是集成這個無IDFA版本,下面是命令行,至於為什么建議集成這個版本的,個推的文檔中也有這樣一段話:“在 App 內無廣告情況下還是建議開發者使用獲取 IDFA 版本,並提交 AppStore 審核。 集成 IDFA 而未集成任何廣告服務可能會遭到 Apple 拒絕。”。
platform :ios pod 'GTSDK', '1.5.3-noidfa'
推送需要注意點:
一:在 Xcode 8.0 以上,必須開啟Push Notification能力,操作看下圖:
二:為了更好支持消息推送,SDK可定期抓取離線消息,提高消息到達率,需要配置后台運行權限,操作如下:
個推把你需要勾選的這兩個選項也作出了解釋:
Background fetch
: 后台定期獲取權限
Remote notifications
:APNs靜默推送權限
代碼使用說明:
還是建議大家給個推創建一個APPDelegate的類別,如下圖所示:
下一步就是注冊遠程通知 即用戶是否同意接收通知,源代碼如下:
/** 注冊遠程通知 即用戶是否同意接收通知 */ - (void)registerRemoteNotification { /* Xcode8的需要手動開啟“TARGETS -> Capabilities -> Push Notifications” */ /* 下面的方法區分10.0之后版本和之前版本 該項目的最低適配版本是8.0之后的,所以放棄8.0之前注冊遠程通知方法 */ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8編譯會調用 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) { if (!error) { // NSLog(@"request authorization succeeded!"); } }]; [[UIApplication sharedApplication] registerForRemoteNotifications]; #else // Xcode 7編譯會調用 UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; #endif // 大於等於8.0系統的就用這個方法注冊遠程通知 }else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){ UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } } #pragma mark - 遠程通知(推送)回調 /** 遠程通知注冊成功委托 */ -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; token = [token stringByReplacingOccurrencesOfString:@" " withString:@""]; // 獲取到的Token // NSLog(@"\n>>>[DeviceToken Success]:%@\n\n", token); // [ GTSdk ]:向個推服務器注冊deviceToken,這個方法寫在類別里面! [self registerDeviceTokenToGeTuiSDK:token]; } /** 遠程通知注冊失敗委托 */ -(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { // NSLog(@"\n>>>[DeviceToken Error]:%@\n\n", error.description); }
原本想着把SDK的方法一個一個寫出來解讀的,不過那樣子感覺就像官方文檔了,沒什么意思了,在這里我直接把AppDelegate+getui.m這整個文件的代碼寫出來,每一個方法都是有說明的,里面很多點也是寫在了注釋當中,這樣就覺得更完整,可讀性更高一點:
@implementation AppDelegate (getui) // 初始化個推SDK -(void)initGeTuiSDK{ // [ GTSdk ]:使用APPID/APPKEY/APPSECRENT創建個推實例 // 通過個推平台分配的appId、 appKey 、appSecret 啟動SDK, // 注:該方法需要在主線程中調用 [GeTuiSdk startSdkWithAppId:GTAPPID appKey:GTAPPKEY appSecret:GTAPPSECRET delegate:self]; } // Background Fetch 恢復SDK 運行 -(void)BackgroundFetchGeTuiSdk{ // Background Fetch 恢復SDK 運行 [GeTuiSdk resume]; } // 同步本地角標值到服務器 -(void)setBadgeGeTuiSdk:(NSInteger)badge{ [GeTuiSdk setBadge:badge]; } // 重置角標計數 -(void)resetBadgeGeTuiSdk{
[GeTuiSdk resetBadge]; } /** 向個推注冊deviceToken @param deviceToken deviceToken */ -(void)registerDeviceTokenToGeTuiSDK:(NSString *)deviceToken{ // 向個推服務器注冊deviceToken [GeTuiSdk registerDeviceToken:deviceToken]; } /* 將收到的APNs信息傳給個推統計 @param userInfo 獲取到的消息 */ -(void)handleRemoteNotificationToGrTuiSDK:(NSDictionary *)userInfo{ // 將收到的APNs信息傳給個推統計 [GeTuiSdk handleRemoteNotification:userInfo]; } #pragma mark - GeTuiSdkDelegate /** SDK啟動成功返回cid */ - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId { // [4-EXT-1]: 個推SDK已注冊,返回clientId // NSLog(@"\n>>[GTSdk RegisterClient]:%@\n\n", clientId); WRITEUSERDEFAULTS(clientId, ClientId); } /** SDK遇到錯誤回調 */ - (void)GeTuiSdkDidOccurError:(NSError *)error { // [EXT]:個推錯誤報告,集成步驟發生的任何錯誤都在這里通知,如果集成后,無法正常收到消息,查看這里的通知。 //NSLog(@"\n>>[GTSdk error]:%@\n\n", [error localizedDescription]); } /* SDK收到透傳消息回調 SDK 在線狀態時( App 在前台運行),個推服務器會直接給 App 發送透傳消息,不發送蘋果APNS消息,可以更快的把消息發送到手機端;SDK 離線狀態時 (停止 SDK 或 App 后台運行 或 App 停止),個推服務器會給 App 發送蘋果 APNs 消息,同時保存個推的離線消息,當 SDK 在線后,SDK 會獲取所有的個推透傳消息,offLine 字段就是表明該條消息是否為離線消息。 注意:這里是否能收到推送消息也是有在線時間限制的,最長是72小時之前的在線過的用戶、 也就是說能收到消息的就是在72小時內在線過的,超過這個時間的是收不到推送消息的,這也就解決好長時間不在線,已在線會收到很多推送消息的困擾 **/ - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId { /** *匯報個推自定義事件 *actionId:用戶自定義的actionid,int類型,取值90001-90999。 *taskId: 下發任務的任務ID。 *msgId: 下發任務的消息ID。 *返回值: BOOL,YES表示該命令已經提交,NO表示該命令未提交成功。注:該結果不代表服務器收到該條命令 **/ //[GeTuiSdk sendFeedbackMessage:90001 andTaskId:taskId andMsgId:msgId]; // 數據轉換 NSString *payloadMsg = nil; if (payloadData) { payloadMsg = [[NSString alloc] initWithBytes:payloadData.bytes length:payloadData.length encoding:NSUTF8StringEncoding]; } // 解析拿到的數據 if (payloadMsg != nil) { NSData * data = [payloadMsg dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary * JSONresponseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; } UIAlertController * GeTuiAlertController=[[NotificationHandleObject sharedInstance]addBaseViewNotificationAlertViewWithMessage:JSONresponseObject[@"title"] andConfirmTitle:@"確定"]; [self.window.rootViewController presentViewController:GeTuiAlertController animated:YES completion:nil]; } } } /** SDK收到sendMessage消息回調 */ - (void)GeTuiSdkDidSendMessage:(NSString *)messageId result:(int)result{ // 發送上行消息結果反饋 // NSString *msg = [NSString stringWithFormat:@"sendmessage=%@,result=%d", messageId, result]; // NSLog(@"\n>>[GTSdk DidSendMessage]:%@\n\n", msg); } /** SDK運行狀態通知 */ - (void)GeTuiSDkDidNotifySdkState:(SdkStatus)aStatus { // 通知SDK運行狀態 // NSLog(@"\n>>[GTSdk SdkState]:%u\n\n", aStatus); } /** SDK設置推送模式回調 */ - (void)GeTuiSdkDidSetPushMode:(BOOL)isModeOff error:(NSError *)error { if (error) { // NSLog(@"\n>>[GTSdk SetModeOff Error]:%@\n\n", [error localizedDescription]); return; } // NSLog(@"\n>>[GTSdk SetModeOff]:%@\n\n", isModeOff ? @"開啟" : @"關閉"); } // 別名推送 // 綁定別名是否成功 // 處理 綁定/解綁 delegate返回結果: - (void)GeTuiSdkDidAliasAction:(NSString *)action result:(BOOL)isSuccess sequenceNum:(NSString *)aSn error:(NSError *)aError { if ([kGtResponseBindType isEqualToString:action]) { //NSLog(@"綁定結果 :%@ !, sn : %@", isSuccess ? @"成功" : @"失敗", aSn); if (!isSuccess) { //NSLog(@"失敗原因: %@", aError); } } else if ([kGtResponseUnBindType isEqualToString:action]) { //NSLog(@"綁定結果 :%@ !, sn : %@", isSuccess ? @"成功" : @"失敗", aSn); if (!isSuccess) { //NSLog(@"失敗原因: %@", aError); } } }