天天看點

iOS10 關于推送-b

正式開始之前的準備工作

我們先來從Apple Developer網站上建立一個關聯App ID和開發供應配置檔案的SSL證書,來開始這段美好的教程。接着,我們看看在iOS下是如何在解析網站(Parse website)配置解析程式(Parse app)的。最後,我們把這些理論付諸實踐,建立一個帶有推送功能的App,并且将消息推到使用者。

在開始這段美好旅程之前,大家一定要注意iOS模拟器是不支援推送的,因為模拟器暫時沒有devicetoken,是以你必須想辦法找一台真機過來。還有就是要有蘋果開發者協定,之後才能在真機上面進行開發和測試。

建立SSL證書

首先,需要在蘋果開發者網站上建立一個App ID以及關聯的SSL證書,有了這個證書,解析伺服器才能将找到你的App ID,繼而将通知推送到該應用。

建立一個證書請求

首先的首先,我們需要有一個證書簽名請求檔案,之後建立SSL證書才有意義。建立檔案的方法如下:

1.在Mac上運作鑰匙串通路(keychain)

2.選擇鑰匙串通路 > 證書助理 > 從證書頒發機構中請求一個證書

3.輸入你的名字和郵件位址,CA郵件位址預設就可以,不要試圖去進行任何改動。

4.選擇“儲存到硬碟”,這樣就會将剛建立的證書請求檔案下載下傳到電腦桌面上了。

建立并調教一個App ID

每個安裝在你開發者裝置上的iOS程式都需要一個獨有的App ID,友善起見,App ID以反向路徑規則命名,形如com.parseSampleApp,但是一定要注意App ID裡不能包含星号("*")。建立步驟如下:

1.登陸網站2.從左邊欄裡點選App IDs。

3.選擇New App ID,然後建立一個新的App ID。一定要確定Bundle Identifier一欄中沒有星号。

4.在你的App ID下面找到Configure,選中。

5.将“Enable for Apple Push Notification service”勾選上,然後點選Development Push SSL Certificate下面的Configure,然後會出現Apple Push Notification service SSL Certificate Assistant設定向導。

6.點選Continue繼續,然後點選Choose File,選中剛建立見的.certSigningRequest檔案。

7.點選Generate開始生成,然後點選Download下載下傳生成的SSL證書。

8.通過keychain程式來安裝下載下傳好的SSL證書。

9.接着在“我的證書”選項先面,找到你剛才安裝名稱形如“Apple Development IOS Push Services: xxx”的證書。

10.輕按兩下證書,選擇“導出”,導出後的檔案字尾名為.p12。這個時候千萬注意!出現密碼提示的時候一定不要添任何東西。

這裡值得注意的一點就是,至此我們隻是将應用的推送通知功能在開發模式中開啟了,是以應用開始正式釋出之前,一定記得要将第四步到第九步的流程重新走一遍,并将第五步中的“Development Push SSL Certificate”改成“Production Push SSL Certificate”。這樣就完美了。

建立一個Provisioning Profile(配置簡介)

Provisioning Profile會驗證運作所開發應用的裝置。而且不管你是建立一個App ID還是去修改現成的,都得重新生成并安裝一遍Provisioning Profile。步驟如下:

1.在iOS Provisioning Portal中選擇Provisioning變遷。

2.點選New Profile

3.填好對應的資訊,確定一下三項(developer certificate、上面剛建立好的App ID以及用于測試的裝置)都沒有遺漏,全都選中。

4.點選Actions一欄下面的Download按鈕下載下傳生成好的Provisioning Profile。

5.輕按兩下下載下傳好的檔案,預設是由iPhone Configuration Utility程式開。

配置Parse App

要想在推送通知中使用Parse功能,必須将此項特性設定成開啟狀态,然後将上面建立好的推送SSL證書上傳上去。步驟如下:

1.在Parse website上找到你的Parse app,然後選擇Settings标簽頁。

2.在iOS Push Notification Settings下面,點選Choose File,然後将之前用keychain導出的.p12檔案上傳上去。

3.如果希望使用者能夠發送推送通知,我們需要将Client push enabled?選項中的Yes勾選上。這個功能對于像即時聊天的軟體非常有用,我們現在将它勾選上,當然開發者需要自行決定是否要開啟這項功能。

4.點選Save儲存。

至此,所有的前提條件都搞完了,馬上進入最激動人心的建立一個具備推送通知應用的環節了,喝口水,開搞。

建立一個具備推送通知的應用

首先,我們需要先對Xcode項目進行一些設定,確定App ID和provisioning profile都被設定成良好的狀态。做開發嗎,

1.在Supporting Files檔案夾下選中ProjectName-Info.plist,對右側視圖中的Bundle Identifier選項進行修改,和你自己建立的App ID保持一緻(形如:com.parseSampleApp)。

2.在左側的菜單中選中剛建立的project檔案,在下面找到Build Settings然後搜尋Code Signing Identity。

3.将對應provisioning profile的所有的值全部設定好。

4.選擇左手邊Targets下面的項目名稱,再次找到Build Settings,來到Code Signing Identity區域,確定所有的值都和新的provisioning profile保持一緻。

代碼環節

接下來就開始進入程式設計模式了。我們需要對應用程式代理(app delegate)進行少量的修改,進而使得我們的應用可以接受到推送通知。步驟如下:

1.注冊裝置需要在app delegate的[application:didFinishLaunchingWithOptions:]方法中調用[application registerForRemoteNotificationTypes:]方法,代碼如下:

  1. - (BOOL)application:(UIApplication *)application 
  2.  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
  3.     ... 
  4.     // Register for push notifications 
  5.     [application registerForRemoteNotificationTypes:  
  6.                                  UIRemoteNotificationTypeBadge | 
  7.                                  UIRemoteNotificationTypeAlert |              
  8.                                  UIRemoteNotificationTypeSound]; 

2.一旦成功,以上方法會在app delegate中執行回調方法[application:didRegisterForRemoteNotificationsWithDeviceToken:] 。我們需要實作這個方法,用它來告知Parse我們的裝置資訊。代碼如下:

  1. - (void)application:(UIApplication *)application  
  2. didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)newDeviceToken 
  3.     [PFPush storeDeviceToken:newDeviceToken]; // Send parse the device token 
  4.     // Subscribe this user to the broadcast channel, ""  
  5.     [PFPush subscribeToChannelInBackground:@"" block:^(BOOL succeeded, NSError *error) { 
  6.         if (succeeded) { 
  7.             NSLog(@"Successfully subscribed to the broadcast channel."); 
  8.         } else { 
  9.             NSLog(@"Failed to subscribe to the broadcast channel."); 
  10.         } 
  11.     }]; 

3.廣播頻道(broadcast channel)用于同時聯系到所有使用者,是以很多時候開發者可能需要自己建立一些更精準化的頻道。一旦推送通知被接受但是應用不在前台,就會被顯示在iOS推送中心。反之如果應用剛好處于活動狀态,則交于應用去自行處理。具體我們可以在app delegate中實作[application:didReceiveRemoteNotification]方法。一下示例代碼隻是簡單的将這一需求交由Parse去處理,Parse會建立一個模态警報顯示推送内容。

  1. didReceiveRemoteNotification:(NSDictionary *)userInfo { 
  2.     [PFPush handlePush:userInfo]; 

好了,現在開始在你的iOS裝置上運作一下,一切順利的話,就可以看到從使用者到推送通知之間的一條模态警報請求許可。

發送推送通知

從Parse website發送

Parse允許你從Parse website發送推送通知,API和SDK均可。找到Parse app,選擇Push Notifications标簽,你可以在文本框裡添加一條消息,然後廣播給是以使用者。你可以使用Parse web API通過發送一個POST請求來發送推送到任何頻道。以下示例是一條廣播通知,内容是“Hello World”,使用curl進行發送。

  1. curl -X POST "https://api.parse.com/1/push" -H "Content-Type: application/json" \ 
  2. --data '{"key":"your_push_master_key", "channel":"", "type":"ios",\ 
  3. "data":{"alert":"Hello World!"}}' 

從應用發送

從應用發送需要開啟Parse app中的Client push enabled功能。實作從應用發送推送通知的方式多種多樣,你可以在中找到一切。

  1. // Broadcast "Hello World" 
  2. [PFPush sendPushMessageToChannelInBackground:@"" withMessage:@"Hello World!"]; 

iOS10關于推送的新特性, 相比之前确實做了很大的改變,總結起來主要是以下幾點:

  1. 推送内容更加豐富,由之前的alert 到現在的title, subtitle, body
  2. 推送統一由trigger觸發
  3. 可以為推送增加附件,如圖檔、音頻、視訊,這就使推送内容更加豐富多彩
  4. 可以友善的更新推送内容

import 新架構

添加新的架構 UserNotifications.framework 

iOS10 關于推送-b

​#import <UserNotifications/UserNotifications.h>​

注冊推送

在設定通知的時候,需要先進行注冊,擷取授權 

iOS10 所有通知都是通過UNUserNotificationCenter來管理,包括遠端通知和本地通知

//iOS8以下
   [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];

   //iOS8 - iOS10
   [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];

   //iOS10
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {

    }
      

擷取使用者設定

iOS10 提供了擷取使用者授權相關設定資訊的接口​​​​ 回調帶有一個UNNotificationSettings對象,它具有以下屬性,可以準确擷取各種授權資訊

authorizationStatus
soundSetting 
badgeSetting 
alertSetting 
notificationCenterSetting 
lockScreenSetting 
carPlaySetting
alertStyle
      

像下面的方法,點選allow 

iOS10 關于推送-b
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
          if (granted) {
                //點選允許
                NSLog(@"注冊通知成功");
                [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
                NSLog(@"%@", settings);
                }];
            } else {
                //點選不允許
                NSLog(@"注冊通知失敗");
            }
        }];

列印資訊:   *<UNNotificationSettings: 0x174090a90; authorizationStatus: Authorized, notificationCenterSetting: Enabled, soundSetting: Enabled, badgeSetting: Enabled, lockScreenSetting: Enabled, alertSetting: NotSupported, carPlaySetting: Enabled, alertStyle: Banner>*
      

注冊APNS, 擷取token

iOS10, 注冊APNS和擷取token的方法還和之前一樣 

在application: didFinishLaunchingWithOptions:調用 registerForRemoteNotifications方法

[[UIApplication sharedApplication] registerForRemoteNotifications];
      

在代理方法application: didRegisterForRemoteNotificationsWithDeviceToken:中擷取token

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken NS_AVAILABLE_IOS(3_0){
        NSLog(@"deviceToken:%@",deviceToken);
    }

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error NS_AVAILABLE_IOS(3_0){
        NSLog(@"didFailToRegisterForRemoteNotificationsWithError:%@",error);
    }
      

設定處理通知的action 和 category

在iOS8以前是沒有category這個屬性的; 

在iOS8注冊推送,擷取授權的時候,可以一并設定category, 注冊的方法直接帶有這個參數; 

在iOS10, 需要調用一個方法​​​​來為管理推送的UNUserNotificationCenter執行個體設定category, category又可以對應設定action;

//設定category
//UNNotificationActionOptionAuthenticationRequired 需要解鎖
//UNNotificationActionOptionDestructive  顯示為紅色
//UNNotificationActionOptionForeground   點選打開app

UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"action1" title:@"政策1行為1" options:UNNotificationActionOptionForeground]; 

UNTextInputNotificationAction *action2 = [UNTextInputNotificationAction actionWithIdentifier:@"action2" title:@"政策1行為2" options:UNNotificationActionOptionDestructive textInputButtonTitle:@"comment" textInputPlaceholder:@"reply"];

 //UNNotificationCategoryOptionNone
 //UNNotificationCategoryOptionCustomDismissAction  清除通知被觸發會走通知的代理方法
 //UNNotificationCategoryOptionAllowInCarPlay       适用于行車模式
UNNotificationCategory *category1 = [UNNotificationCategory categoryWithIdentifier:@"category1" actions:@[action2,action1]  minimalActions:@[action2,action1] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];

UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"action3" title:@"政策2行為1" options:UNNotificationActionOptionForeground];

UNNotificationAction *action4 = [UNNotificationAction actionWithIdentifier:@"action4" title:@"政策2行為2" options:UNNotificationActionOptionForeground];
UNNotificationCategory *category2 = [UNNotificationCategory categoryWithIdentifier:@"category2" actions:@[action3,action4]  minimalActions:@[action3,action4] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];

[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObjects:category1,category2, nil]];
      

設定通知内容

因為iOS10遠端通知與本地通知統一起來了,通知内容屬性是一緻的,不過遠端推送就需要在payload進行具體設定了,下面以本地通知為例,介紹關于​​UNNotificationContent​​的内容 

官網上明确說明了,我們是不能直接建立UNNotificationContent的執行個體的, 如果我們需要自己去配置内容的各個屬性,我們需要用到​​看一下它的一些屬性:

attachments          //附件
badge                //徽标
body                 //推送内容body
categoryIdentifier   //category辨別
launchImageName      //點選通知進入應用的啟動圖
sound               //聲音
subtitle            //推送内容子标題
title               //推送内容标題
userInfo           //遠端通知内容

UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = @"Test";
    content.subtitle = @"1234567890";
    content.body = @"Copyright © 2016年 jpush. All rights reserved.";
    content.badge = @1;
    NSError *error = nil;
    NSString *path = [[NSBundle mainBundle] pathForResource:@"718835727" ofType:@"png"];
    UNNotificationAttachment *att = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
    if (error) {
        NSLog(@"attachment error %@", error);
    }
    content.attachments = @[att];
    content.categoryIdentifier = @"category1”;  //這裡設定category1, 是與之前設定的category對應
    content.launchImageName = @"1-Eb_0OvtcxJXHZ7-IOoBsaQ";

UNNotificationSound *sound = [UNNotificationSound defaultSound];
content.sound = sound;
      
iOS10 關于推送-b
iOS10 關于推送-b
iOS10 關于推送-b

通知觸發器

iOS 10觸發器有4種

  • UNPushNotificationTrigger 觸發APNS服務,系統自動設定(這是區分本地通知和遠端通知的辨別)
  • UNTimeIntervalNotificationTrigger 一段時間後觸發
  • UNCalendarNotificationTrigger 指定日期觸發
  • UNLocationNotificationTrigger 根據位置觸發,支援進入某地或者離開某地或者都有

    //十秒後 UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO]; //每周日早上8:00 NSDateComponents *component = [[NSDateComponents alloc] init]; component.weekday = 1; component.hour = 8; UNCalendarNotificationTrigger *trigger2 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:component repeats:YES]; //圓形區域,進入時候進行通知 CLLocationCoordinate2D cen = CLLocationCoordinate2DMake(80.335400, -90.009201); CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:cen radius:500.0 identifier:@“center"]; region.notifyOnEntry = YES; //進入的時候 region.notifyOnExit = NO; //出去的時候 UNLocationNotificationTrigger *trigger3 = [UNLocationNotificationTrigger triggerWithRegion:region repeats:NO];

添加通知 / 更新通知

  1. 建立一個UNNotificationRequest類的執行個體,一定要為它設定identifier, 在後面的查找,更新, 删除通知,這個辨別是可以用來區分這個通知與其他通知
  2. 把request加到UNUserNotificationCenter, 并設定觸發器,等待觸發
  3. 如果另一個request具有和之前request相同的辨別,不同的内容, 可以達到更新通知的目的

    NSString *requestIdentifer = @"TestRequest"; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifer content:content trigger:trigger1]; //把通知加到UNUserNotificationCenter, 到指定觸發點會被觸發 [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { }]; //在另外需要更新通知的地方 UNMutableNotificationContent *newContent = [[UNMutableNotificationContent alloc] init]; newContent.title = @"Update"; newContent.subtitle = @"XXXXXXXXX"; newContent.body = @"Copyright © 2016年 jpush. All rights reserved."; UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:3 repeats:NO]; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"TestRequest" content:newContent trigger:trigger1]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { }];

iOS10 關于推送-b

擷取和删除通知

這裡通知是有兩種狀态

  • Pending 等待觸發的通知
  • Delivered 已經觸發展示在通知中心的通知

    //擷取未觸發的通知 [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) { NSLog(@"pending: %@", requests); }]; //擷取通知中心清單的通知 [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) { NSLog(@"Delivered: %@", notifications); }]; //清除某一個未觸發的通知 [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[@"TestRequest1"]]; //清除某一個通知中心的通知 [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[@"TestRequest2"]]; //對應的删除所有通知 [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests]; [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];

delegate

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    //應用在前台收到通知
    NSLog(@"========%@", notification);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    //點選通知進入應用
    NSLog(@"response:%@", response);
}