前言:
說到這個遠程推送,大家知道的應該都挺多的,但用到的估計極光和個推要占一很大部分,這篇博客重點說的就是個推的使用,個推官網的鏈接在這里,它的集成是比較方便的,你可以直接使用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);
}
}
}
