iOS整合個推小結

躍然發表於2016-07-18
1、 Device token(裝置令牌)概念:

deviceToken

這周在學習蘋果的訊息推送(Apple Push Notification),官方畫的流程圖很清晰,但是對裡面的一個概念 device token 卻語焉不詳。
讀完冗長的文件,唯一有用的卻是一個注意事項:
An application should register [with APN servers] every time it launches and give its provider the current token.每次應用被開啟時,開發者都要重新收集當前裝置的 device token,因為它可能變了哦。
stackoverflow 針對Device token 什麼時候會發生變化有個很棒的解答。
在一臺裝置中, device token 是系統級別的,不同 App 獲得的 device token 是相同的。
假如我的手機安裝了 Angry Bird 和 Evernote ,這兩個應用獲得 device token 一模一樣。
device token 並不會因為單個 app 的更新而發生改變。
假如我的 iPhone 升級了最新版的憤怒的小鳥,這並不會導致我 device token 的改變。
假如我的 iPhone 從 backup 中恢復資料,device token 不會發生變化。
使用者抹除 iPhone 的資料時,意味著要與這臺手機撇清關係,比如出售或者送人。此時為了保護隱私,device token 會改變。
在需要傳送push時,我們的服務端就會取出要傳送的裝置的device token,然後以如下方式組成特定結構字串,然後傳送至APNs
toAPNs.png

2、以下為我整合時的問題與解決方案:

問題
1、iOS通知,在官網後臺怎麼推送,不能單獨推送通知?
iOS只能透傳訊息

2、如果應用在前臺處於執行狀態,是不是不走APNs
這個是怎麼實現的?實時監控應用是否線上?
判斷clientid和個推伺服器的連線狀態簡單說就是客戶端sdk和個推伺服器
是否是連線狀態的

3、字串 字典 遠端通知 區別 使用場景?
字串是apn的簡單推送,字典和遠端通知是apn的高階推送
字串和字典會有apn通知欄提示,遠端通知沒有

4、為了更好支援SDK推送,APP定期抓取離線資料,需要配置後臺執行許可權:Backgound fetch:後臺獲取
Remote notifications: 推送喚醒(靜默推送,Silent Remote Notifications)
這個設定與不設定的區別?
這個不設定也沒關係的

5、clientid(CID)與 devictoken
devictoken是向蘋果註冊的,clientid(CID)是個推這邊推送訊息用到的,
devicetoken是推送APNS訊息用到的,客戶端整合後會獲取clientid,我們
會判斷clientid和個推伺服器的連線狀態簡單說就是客戶端sdk和個推伺服器
是否是連線狀態的。客戶端clientid和devictoken會有一個繫結關係,我們
系統會維護這個繫結關係的

6、快取訊息存在問題(訊息中心)
如果快取apns通知,使用者點選icon進入應用獲取不到通知內容,這個時候會訊息丟失
如果快取透傳訊息內容,超出離線時間(最長可設定72小時),再開啟應用,這個時候也獲取不到透傳訊息
這樣就存在問題了,超出離線時間,無論快取透傳訊息內容還是apnst通知,都不會有可快取內容
個推個的解決方案:
收到的訊息儲存在資料庫裡,超過離線時間沒有下發的使用者,當他點選圖示開啟應用,或者進入歷史訊息頁面進行檢視時,客戶端可以主動的去向伺服器拉取資料,這些資料你們是會在伺服器中儲存的。就是你們客戶端向你們的伺服器上去獲取資料,不走推送了。客戶端向服務端傳送請求,然後服務端把資料返回給客戶端比如銀行賬單也是這樣的,使用者在頁面中進行下拉時,會去重新整理頁面,此時就是去伺服器上重新提取的資料。

7、問題:
程式第一次啟動的時候,即由死亡狀態進入啟用狀態,這個時候接收到通知,點選條幅通知,
要根據通知內容進行頁面跳轉,但這個時候專案檔案還沒載入完全,不能跳轉,之前我們的
實現方法是這樣的,在didFinishLaunchingWithOptions代理下面新增如下方法

// 程式在死亡狀態,再次啟動,收到推送通知,跳轉至對應頁面
if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
    NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    self.notificationUserInfo = userInfo;
    // 這裡延遲1秒 否則不執行跳轉
    [self performSelector:@selector(skipToMessageCenter) withObject:nil afterDelay:1];
}

現在換成個推後要5秒後才能跳轉

[self performSelector:@selector(skipToMessageCenter) withObject:nil afterDelay:5];

這個延遲時間無法準確計算,所以上面方法是有缺陷的,那麼有沒更好的解決方案呢?
答案是有的,以下為我優化方案。如果你有更好的方法,歡迎指正。

AppDelegate.m:

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

        // 程式在死亡狀態,再次啟動,收到推送通知,跳轉至對應頁面
    if ([launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
        NSDictionary * userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        self.notificationUserInfo = userInfo;
        // 快取apns通知內容到本地
        [[NSUserDefaults standardUserDefaults]setObject:self.notificationUserInfo forKey:KRemoteNotificationUserInfo];
        [[NSUserDefaults standardUserDefaults ]synchronize];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(skipToMessageCenter) name:KReciveRemoteNotificationUserInfo object:nil];
    }
}

-(void)skipToMessageCenter {

    dispatch_async(dispatch_get_main_queue(), ^{
        // 根據通知內容,跳轉至不同頁面
        MessageModel * messageModel = [[MessageModel alloc] initWithNoticeDic:self.notificationUserInfo];
        MessageToSpecificViewController * messageToSpecificViewController = [[MessageToSpecificViewController alloc] init];
        [messageToSpecificViewController messageFromViewController:update.mainViewController toSpecificViewControllerWithMessage:messageModel];
        self.notificationUserInfo = nil;
    });
}

CHMainViewController.m:

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];

    // 應用由死亡狀態進入啟用狀態,這個時候傳送通知,appdelegate接受通知,根據通知內容進行不同跳轉
    NSDictionary * notificationUserInfo =[[NSUserDefaults standardUserDefaults]valueForKey:KRemoteNotificationUserInfo];
    if (notificationUserInfo) {
        [[NSNotificationCenter defaultCenter] postNotificationName:KReciveremoteNotificationUserInfo object:nil];

        [[NSUserDefaults standardUserDefaults]setObject:nil forKey:KRemoteNotificationUserInfo];
        [[NSUserDefaults standardUserDefaults ]synchronize];
    }
}

8、設定別名

使用別名進行單點推送。
之前做極光推送的時候,我們別名使用的是[[UIDevice currentDevice] getCurrentDeviceUUID],這個Id不能直接使用,因為不符合格式,我把分隔符-換成了分隔符_,這樣是可以的。
原以為UUID全球唯一,請教了下同事,同事說這個id會變的,就是不同證照,即使同一臺裝置,UUID也會不一樣。
個推的小夥伴給的建議是,別名使用clientId,它是對應每臺裝置唯一的。

/** SDK啟動成功返回cid */
- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
    //個推SDK已註冊,返回clientId
    NSLog(@"\n>>>[GeTuiSdk RegisterClient]:%@\n\n", clientId);
    // 繫結別名
    [GeTuiSdk bindAlias:advertisingUUID];
    NSLog(@"個推別名======%@",advertisingUUID);
}

參考:
1、http://www.cnphp6.com/archives/50193
2、http://www.jianshu.com/p/c46b60f06880
3、http://www.jianshu.com/p/803bfaae989e
4、http://mednoter.com/device-token.html
5、http://www.360doc.com/content/12/1116/09/10941785_248142762.shtml

相關文章