[iOS] APNs測試心得

這是一份簡單紀錄我第一次測試APNs的心得,更多的大概也沒有了,大概寫完的當下還不太能為人解惑吧?

產生.cer檔案

首先,你要產生一份.cer或是.p12檔案。這可以參考iOS開發網站上面的說明:
由於我權限不足,是拿到別人幫我產生好的.p12檔案,然後使用此檔案續進行之後的步驟。
首先我要生成一份.pem檔案,我先開啟終端機,cd到該.p12檔案所在的目錄,然後輸入以下指令(注意,PKey.p12是你的.p12名稱,然後PCKey.pem表示你想要輸出的.pem檔案名稱):
openssl pkcs12 -in PKey.p12 -out PCKey.pem -nodes
該指令的說明可以參考此連結,連結中市使用該指令取代另一個指令,所以你也會看到有人使用此指令:
openssl pkcs12 -nocerts -out PushChatKey.pem -in PushChatKey.p12
我是使用前者,不含-nocerts的(這會把certification給去除)。
我參考的教學是這一篇,裡面有他提供的php檔案。
然後得到.pem檔案後,將該檔案放到他的php檔案的目錄內,這樣就算是準備完前面的階段了。

設定App ID

在APP開發網站上面你要針對你的App id能否使用Push進行設定,由於我正開發的App是已經設定過的,僅需更新Provisioning Profile就好,所以這邊我就略過,網路上都有很多教學,比方說這篇教學
在Xcode裡面打開Preferences,點選Accounts的Tab,然後選擇你使用的Apple ID。選擇後,點選右邊欄位下方的View Details...按鈕,然後更新。基本上這樣就完成大半了,剩下是程式碼的部份。

AppDelegate設定Push

接下來是程式碼的部份,你要作的事情是,設定使用者接受的通知方法,基本上全部都會在AppDelegate.m裡面完成,技術文件可以參考這一篇
基本上Push有分local和remote,然後根據iOS版本不同,code有點差別,我會分別說明。
首先是啟動App後就詢問使用者可否接受推播:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Do something else....

    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]){
        UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        [application registerUserNotificationSettings:mySettings];
        [application registerForRemoteNotifications];
    }else { // Before iOS 8:
        NSUInteger notifTypes = UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeNewsstandContentAvailability;
        [application registerForRemoteNotificationTypes:notifTypes];
    }
}
兩個版本主要差異是有沒有registerUserNotificationSettings這個方法,所以會以此寫法判斷版本。
首先選擇你欲支援的通知類型:Alert、Badge、Sound三種。然後封裝到UIUserNotificationSettings物件裡面,該物件還可以定義與這些notification相關連的Action,因為目前沒有特別的Actions,所以Categories的參數是nil。
最後,用此設定來註冊使用者的通知設定,以及註冊Remote通知。然後要注意,因為你呼叫了registerUserNotificationSettings:方法,所以你還要實作application:didRegisterUserNotificationSettings:方法去回應,有些人會在這裡面才註冊遠端通知:
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}
在iOS8之後,local和remote通知的類型設定是同時的,所以新方法registerUserNotificationSettings:其實也就代表了你同時設定了兩種通知的通知類型。在你第一次呼叫此方法時,使用者會看到對話框,詢問可否允許通知,同時,你的APP就會被加入到setting app裡面。如果你的iOS低於8,那需改用registerForRemoteNotificationTypes:方法來設定remote通知的方式。
然後要實作application:didRegisterUserNotificationSettings:方法。使用者設定完成後,系統會呼叫此方法,將UIUserNotificationType傳入(取出方法為,UIUserNotificationSettings的屬性types)。

註冊 Remote 通知

iOS8以上的版本,註冊步驟如下:
  1. 呼叫registerUserNotificationSettings:方法來註冊通知種類。
  2. 呼叫registerForRemoteNotifications方法來註冊接收APNs的push。
  3. 如果成功註冊,就將回傳的device token給儲存,反之,就處理失敗的情形。
  4. 將device token傳給provider。
如前面的程式碼所訴,步驟一二已經完成,接下來要處理步驟三四。需要實作下列兩個方法:
  • application:didRegisterForRemoteNotificationsWithDeviceToken:會接收到註冊成功後回傳的token。
  • application:didFailToRegisterForRemoteNotificationsWithError:註冊失敗時,你要在這方法裡面處理失敗的情況。比方說,你要確保失敗時,App內跟remote push有關的logic都會被關閉。你可以在這邊印出你的錯誤訊息。

建立Server

這邊我使用我前面提到的那一份教學提供的php server,你需要多設定幾件事情:
  • 啟動app,從NSLog輸出內容取得deviceToken
  • 將deviceToken的值貼到php裡面的變數deviceToken
  • 將php裡面的passphrase變數值改成你的.p12檔案的密碼
  • 將php裡面的ck.pem改成你的.pem的名稱
改完後,存檔,將你的.pem檔案放到該php檔案的目錄裡面,然後終端機切換到該目錄,輸入指令:
php simplepush.php
順利的話,訊息就送出了,你會看到:
Connected to APNS
Message successfully delivered

連線測試

這邊補充一個連線測試。可以參考官方文件裡面有一些說明,我這邊要做的是測試我能否連上主機,分成,如果要連到開發用主機,你可以開啟終端機,然後cd到.pem檔案目錄,輸入以下指令:
telnet gateway.sandbox.push.apple.com 2195
成功的話,你會看到以下回應:
Trying 17.172.xxx.xxx...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.

留言