前言
開發iOS應用程式時,我們常常需要連上自己的平台或伺服器建立連線,取得資料。然而,當應用程式尚未開啟,或是已經被退到背景時,此時就無法讓使用者即時看到自己的伺服器送來的新資料了。
推播通知(Apple Push Notification Service, APNs)是當iOS應用程式不在前景時,使自己的平台或伺服器可以發送通知給iOS設備的一項技術。
以下是發送一則推播通知的流程示意圖:
Provider是iOS應用程式開發者自己所擁有的平台或伺服器,APNs Server則是Apple官方的推播通知服務伺服器。 Provider將推播通知的相關資訊依照規定的格式送給APNs Server,APNs Server即可依此資訊將通知傳送給指定的iOS設備。
因此,Provider需要準備以下幾項資料:
- APNs SSL Certificate(APNs SSL憑證檔):由於Provider發送推播通知訊息給APNs Server處理時需要進行SSL連線,進行此連線需要準備憑證檔。
- Device Token:識別iOS設備的唯一ID,表示需要送給哪一台iOS設備。
開發iOS應用程式時,我們常常需要連上自己的平台或伺服器建立連線,取得資料。然而,當應用程式尚未開啟,或是已經被退到背景時,此時就無法讓使用者即時看到自己的伺服器送來的新資料了。
推播通知(Apple Push Notification Service, APNs)是當iOS應用程式不在前景時,使自己的平台或伺服器可以發送通知給iOS設備的一項技術。
以下是發送一則推播通知的流程示意圖:
Provider是iOS應用程式開發者自己所擁有的平台或伺服器,APNs Server則是Apple官方的推播通知服務伺服器。 Provider將推播通知的相關資訊依照規定的格式送給APNs Server,APNs Server即可依此資訊將通知傳送給指定的iOS設備。
因此,Provider需要準備以下幾項資料:
- APNs SSL Certificate(APNs SSL憑證檔):由於Provider發送推播通知訊息給APNs Server處理時需要進行SSL連線,進行此連線需要準備憑證檔。
- Device Token:識別iOS設備的唯一ID,表示需要送給哪一台iOS設備。
Provider事前準備
在App ID設定中啟用推播通知,並建立APNs SSL憑證檔
當某個iOS應用程式需要使用推播通知時,需要先在其App ID設定中啟用此功能。
首先,登入iOS Dev Center, 點選App IDs, 展開該iOS應用程式,進行編輯。
點選編輯後,找到Push Notification項目,點選建立憑證檔(Create Certificate)。
APNs SSL憑證檔分為兩種:開發階段用的Development SSL Certificate與上架之後用的Production SSL Certificate。試此時你的情況與需求使用。
建立APNs SSL憑證檔,需要上傳CSR檔案(CertificateSigningRequest.certSigningRequest)。
完成後,點選下載即可。
下載憑證檔號,點擊兩下憑證檔,開啟鑰匙圈存取(keychain acess),右鍵點選憑證檔,選擇輸出。
至此,Provider需要的APNs SSL憑證檔已完成。
注意:編輯完App ID後,該App的Profitioning file需要重新產生。
當某個iOS應用程式需要使用推播通知時,需要先在其App ID設定中啟用此功能。
首先,登入iOS Dev Center, 點選App IDs, 展開該iOS應用程式,進行編輯。
點選編輯後,找到Push Notification項目,點選建立憑證檔(Create Certificate)。
APNs SSL憑證檔分為兩種:開發階段用的Development SSL Certificate與上架之後用的Production SSL Certificate。試此時你的情況與需求使用。
建立APNs SSL憑證檔,需要上傳CSR檔案(CertificateSigningRequest.certSigningRequest)。
完成後,點選下載即可。
下載憑證檔號,點擊兩下憑證檔,開啟鑰匙圈存取(keychain acess),右鍵點選憑證檔,選擇輸出。
至此,Provider需要的APNs SSL憑證檔已完成。
注意:編輯完App ID後,該App的Profitioning file需要重新產生。
取得Device Token
取得Device Token需要透過iOS設備來進行。
iOS設備使用UIApplication的registerForRemoteNotificationTypes方法, 來註冊使用推播通知, 並取得Device Token,範例如下:
//注意registerForRemoteNotificationType方法在iOS 8之後已經被宣告為deprecated了
//而registerUserNotificationSettings在iOS 10之後也已經被宣告為deprecated了
//因此需要針對不同版本的iOS來執行不同的程式
UIApplication* application = [UIApplication sharedApplication];
if(@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[application registerForRemoteNotifications];
}
}
//若iOS支援registerUserNotificationSettings方法
else if([application respondsToSelector:@selector(registerUserNotificationSettings:)]){
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
}
//若iOS為較舊的版本
else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert| UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}
此方法接收一個UIRemoteNotificationType參數,用以設定是否接收Badge, 使用提示聲音。
而在AppDelegate類別(專案中實作UIApplicationDelegate的類別)中,加入下列兩個方法,用以處理註冊成功或失敗
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken: (NSData *)deviceToken
{
//將Device Token由NSData轉換為字串
const unsigned *tokenBytes = [deviceToken bytes];
NSString *iOSDeviceToken =
[NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
//將Device Token傳給Provider...
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError: (NSError *)err {
//錯誤處理...
}
iOS設備取得Device Token後,iOS應用程式開發者再以任何方式(如:Web Service)將Device Token傳至Provider即可。
取得Device Token需要透過iOS設備來進行。
iOS設備使用UIApplication的registerForRemoteNotificationTypes方法, 來註冊使用推播通知, 並取得Device Token,範例如下:
//注意registerForRemoteNotificationType方法在iOS 8之後已經被宣告為deprecated了
//而registerUserNotificationSettings在iOS 10之後也已經被宣告為deprecated了
//因此需要針對不同版本的iOS來執行不同的程式
UIApplication* application = [UIApplication sharedApplication];
if(@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[application registerForRemoteNotifications];
}
}
//若iOS支援registerUserNotificationSettings方法
else if([application respondsToSelector:@selector(registerUserNotificationSettings:)]){
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
}
//若iOS為較舊的版本
else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert| UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}
此方法接收一個UIRemoteNotificationType參數,用以設定是否接收Badge, 使用提示聲音。
而在AppDelegate類別(專案中實作UIApplicationDelegate的類別)中,加入下列兩個方法,用以處理註冊成功或失敗
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken: (NSData *)deviceToken
{
//將Device Token由NSData轉換為字串
const unsigned *tokenBytes = [deviceToken bytes];
NSString *iOSDeviceToken =
[NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
//將Device Token傳給Provider...
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError: (NSError *)err {
//錯誤處理...
}
iOS設備取得Device Token後,iOS應用程式開發者再以任何方式(如:Web Service)將Device Token傳至Provider即可。
由Provider發送推播通知的相關資訊給APNs Server
先前提及,Provider需要將推播通知的相關資訊依照規定的格式送給APNs Server,此相關資訊稱為Notification Payload,其格式為JSON。範例如下:
{
"aps": {
"alert": "Alert Message",
"badge": 3,
"sound": "alarm"
},
"custom_key": "custom_value"
}
若使用開發中的憑證檔(Development SSL Certificate),則Payload要發給測試用的APSs Server,位址是:gateway.sandbox.push.apple.com,port為2195。
若使用上架用的憑證檔(production SSL Certificate),則Payload要發給正式用的APSs Server,位址是:gateway.push.apple.com,port為2195。
而如今,網路上也已經有眾多第三方程式實作Provider的範例可供參考。本文將以Java-apns為例。
先前提及,Provider需要將推播通知的相關資訊依照規定的格式送給APNs Server,此相關資訊稱為Notification Payload,其格式為JSON。範例如下:
{
"aps": {
"alert": "Alert Message",
"badge": 3,
"sound": "alarm"
},
"custom_key": "custom_value"
}
若使用開發中的憑證檔(Development SSL Certificate),則Payload要發給測試用的APSs Server,位址是:gateway.sandbox.push.apple.com,port為2195。
若使用上架用的憑證檔(production SSL Certificate),則Payload要發給正式用的APSs Server,位址是:gateway.push.apple.com,port為2195。
而如今,網路上也已經有眾多第三方程式實作Provider的範例可供參考。本文將以Java-apns為例。
使用Java-apns套件實作Provider
java-apns是以Java寫成的Provider套件,只要是可以安裝Java Virtual Machine的環境下都可以執行。
建立ApnsService物件,此時需要提供p12檔案的路徑,以及先前儲存p12檔案時,所使用的密碼。
然後,如果使用Development SSL憑證檔,請使用withSandboxDestination方法; 如果使用Production SSL憑證檔,請使用或是withProductionDestination方法。 如下範例:
String certPath = "<p12 File Path>";
String pwd = "<p12 File password>";
ApnsService service = APNS.newService()
.withCert(certPath, KokolaConstants.getApnsPwd())
.withSandboxDestination() // 或是withProductionDestination(), for 上架用
.build();
發送一個簡單的通知:
String payload = APNS.newPayload()
.alertBody("Hello")
.badge(badge).sound ("alert.wav").build();
service.push(id, payload);
更詳細的內容可以參考Notification Payload,Java-apns幾乎都有實作對應的Method可以使用。
java-apns是以Java寫成的Provider套件,只要是可以安裝Java Virtual Machine的環境下都可以執行。
建立ApnsService物件,此時需要提供p12檔案的路徑,以及先前儲存p12檔案時,所使用的密碼。
然後,如果使用Development SSL憑證檔,請使用withSandboxDestination方法; 如果使用Production SSL憑證檔,請使用或是withProductionDestination方法。 如下範例:
String certPath = "<p12 File Path>";
String pwd = "<p12 File password>";
ApnsService service = APNS.newService()
.withCert(certPath, KokolaConstants.getApnsPwd())
.withSandboxDestination() // 或是withProductionDestination(), for 上架用
.build();
發送一個簡單的通知:
String payload = APNS.newPayload()
.alertBody("Hello")
.badge(badge).sound ("alert.wav").build();
service.push(id, payload);
更詳細的內容可以參考Notification Payload,Java-apns幾乎都有實作對應的Method可以使用。
結語
推播通知是個在行動裝置上廣為使用的基本功能,尤其在背景執行程式限制重重的iOS環境下,善用推播通知更是重要。 在iOS下實作推播通知,只要對APNs Server發送正確格式的資料(Notification Payload)即可,因此網路上不難找到各種程式語言/平台實作的Provider,本篇文章僅以Java作為範例,供大家參考。
推播通知是個在行動裝置上廣為使用的基本功能,尤其在背景執行程式限制重重的iOS環境下,善用推播通知更是重要。 在iOS下實作推播通知,只要對APNs Server發送正確格式的資料(Notification Payload)即可,因此網路上不難找到各種程式語言/平台實作的Provider,本篇文章僅以Java作為範例,供大家參考。
沒有留言:
張貼留言