2015年10月21日 星期三

iOS : Remote Push Notification

其實,從 iOS8 以後,最大的改變是推播訊加了選項 (官方定義名稱為: Action 動作) 可以選擇,App 可以不需要在前景;使用者可以直接在推播訊息上,選擇你所定義好的選項,當使用者點擊了選項,系統會直接呼叫程式內的 handleActionWithIdentifier: 處理,即使 App 完全沒有在執行也可以。

在 iOS7 的 Remote Notification 如何工作。

首先,註冊直接呼叫指令 [UIApplication registerForRemoteNotificationTypes:]

//註冊
- (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types;

//Delegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;

當註冊後,推播用的 token會經由 didRegisterForRemoteNotificationsWithDeviceToken: 傳送給手機內; 但若註冊失敗,則會由 didFailToRegisterForRemoteNotificationsWithError: 回報錯誤訊息。

再如何接收推播訊息呢?第一件必需清楚的是,若開啟 App 不是透過點擊推播訊息,才開啟App,App是收不到推播訊息的。

  1. 當App不在背景時,點擊推播訊息去開啟 App。推播訊息會分別由 didFinishLaunchingWithOptions:didReceiveRemoteNotification: 帶入。
  2. 當App在背景時,點擊推播訊息去開啟 App。推播訊息只會由 didReceiveRemoteNotification: 帶入。
  3. 當App在前景時,此時推播訊息送達,推播訊息只會由 didReceiveRemoteNotification: 帶入。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;

iOS8 多了Action 和 background handle

文章前頭有提到播推訊多了動作,可提供給使用者選擇。而這些動作就必需在程式內去定義好它們。另外一個功能,每次推播訊息需要提供的選項,不一定都是一致的。於是我們可以將動作分類,並將分類後,各個類別給與一個識別 (id)。推播伺服器推送訊息時,可以設定使用那個動作類別。

單純的呼叫 registerForRemoteNotificationTypes: 取得Token的方式將無法使用了。將拆解為

定義動作 (Action)
區分類別 (Category)
註冊 (若Location Notification 需要額外的 Core Location 註冊,在另外一篇討論)

定義動作 Action

新建一個使用者選項按鈕方法如下:

    //來產生一個動作
    UIMutableUserNotificationAction *actionLike = [[UIMutableUserNotificationAction alloc]init];    

    //決定這個動作,需不需要開啟App
    actionLike.activationMode = UIUserNotificationActivationModeBackground;

    //這個動作是否對資料或App會有破壞的程序。
    actionLike.destructive = NO;

    //這個動作是否需要使用者驗證。
    actionLike.authenticationRequired = NO;

    //動作的 id 
    actionLike.identifier = @"idLIKE";

    //動作所顯示的文字
    actionLike.title = @"喜歡";

區分類別

首先,先注意推播訊息會出現的四個位置,分別為 Lock screen、Notification center、Banner、和 Modal view。除了 Modal view 可以放三個動作外,其它位置僅能放二個動作。

    //產生一個類別,並且給這個類別一個 id。
    UIMutableUserNotificationCategory *catLike = [[UIMutableUserNotificationCategory alloc]init];
    cat.identifier = @"LikeCategory";

    //UIUserNotificationActionContextDefault,目前可放三個動作,而目前也只有給 Model view 用。
    [cat setAction:@[actionLike, actionNoLike, actionHate] forContext:UIUserNotificationActionContextDefault];

    //UIUserNotificationActionContextMinimal,目前可放二個動作,是較常使用的,除了 Modal view。
    [cat setAction:@[actionLike, actionNoLike] forContext:UIUserNotificationActionContextMinimal];

可以註冊了。

    //將所有的類別 category放在一個集合 (set),以產生一個UIUserNotificationSettings
    NSSet *categories = [NSSet setWithArray:@[catLike, catAccept,...]];
    UIUserNotificationSettings *settings = 
                [UIUserNotificationSettings 
                        settingsForTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)
                        categories:categories];

    //註冊,完成。結果依舊由 didRegisterForRemoteNotificationsWithDeviceToken 和 didFailToRegisterForRemoteNotificationsWithError 取得。
    UIApplication *app = [UIApplication sharedApplication];
    [app registerUserNotificationSettings:settings];

推播內容和處理

若推播訊息需要有提供選項給使用者,則在推播內容內,就需要指定 category。

{"aps":
    {
        "alert":"Do you like iPhone",
        "category":"LikeCategory"  //指定使用那個類別。
    }
}

接收訊息和 iOS7 一樣,另外新增 handleActionWithIdentifier 函式,讓 App 不需要在前景,使用者點擊了動作,系統會呼叫這個函式。

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler;