1. imamurh

    No comment

    imamurh
Changes in body
Source | HTML | Preview
@@ -1,126 +1,126 @@
# はじめに
本稿では、VoIPプッシュ通知を送って実機で受け取るまでの手順を紹介します。
VoIPプッシュ通知とはなんぞや?という方は、mgkdevさんの以下の投稿がとても参考になりましたので、ご覧になられると良いかと思います。
[VoIPプッシュ通知(PushKit)と標準プッシュ通知の違いについて](http://qiita.com/mgkdev/items/303b9015fabca4eb7fb7)
# 事前準備
## VoIP Services Certificate 作成
通常の Push Notification などの場合と同様に、Apple Developer サイトで VoIP Services Certificate を作成します。
![VoIP Services Certificate.png](https://qiita-image-store.s3.amazonaws.com/0/121719/b390b2fb-b5dd-faab-cc8b-121df7597054.png)
証明書と秘密鍵はキーチェーンアクセスで .p12 形式で書き出した後、.pem 形式に変換しておきます。
```
openssl pkcs12 -in voip_services.p12 -out voip_services.pem -nodes -clcerts
```
## HTTP/2 環境
APNs Provider API を利用するため、HTTP/2 環境が必要です。
itosho さんの以下の投稿を参考に curl をインストールしました。
[APNs Provider API(HTTP/2)をPHPで試してみる](http://qiita.com/itosho/items/2402df4de85b360d5bd9)
動作確認
```
curl --http2 https://http2bin.org/get
```
# アプリ側実装
大した実装はないのですが、一応今回作成したサンプルアプリを以下にアップロードしています。
https://github.com/imamurh/PushKitSample
## Background Modes
Voice over IP にチェックを入れます。
<img width="837" alt="VoIP Background Mode.png" src="https://qiita-image-store.s3.amazonaws.com/0/121719/5774beb5-55a9-a2c2-a8d7-40f5d61b9bf8.png">
## PushKit
PushKit を import し、必要なタイミングで PKPushRegistry を利用して登録を行います。
```swift
import PushKit
...
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [PKPushTypeVoIP]
```
## PKPushRegistryDelegate
PKPushRegistryDelegate を実装し、デバイストークンをプッシュ通知サーバに登録する処理や VoIP プッシュ通知を受けたときの処理を実装します。
```swift
// MARK:- PKPushRegistryDelegate
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
NSLog("didUpdatePushCredentials: \(credentials.token)")
// デバイストークンをプッシュ通知サーバに登録するなどの処理をここに書く
}
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
NSLog("didReceiveIncomingPushWithPayload: \(payload.dictionaryPayload)")
// VoIPプッシュ通知を受けたときの処理をここに書く
}
func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {
NSLog("didInvalidatePushTokenForType")
}
```
# 動作確認
## アプリ実行
```shell-session
2016-07-18 15:50:24.619 PushKitSample[834:84768] didFinishLaunchingWithOptions: Inactive
2016-07-18 15:50:24.665 PushKitSample[834:84794] didUpdatePushCredentials: <4cd8bbfa 847dcf0e 8a8b4911 ad8b6732 5111c14f 137f8f5d 66a1ce71 b549d524>
```
今回はプッシュ通知用のサーバを用意しているわけではないので、ログ出力されたデバイストークン (この例では4cd8bbfa847dcf0e8a8b4911ad8b67325111c14f137f8f5d66a1ce71b549d524) をメモしておく。
## curl コマンドで VoIP プッシュ通知リクエストを送る
```
curl --http2 \
-E voip_services.pem \
--header "apns-topic: com.example.imamurh.pushkitsample.voip" \
-d "{\"message\":\"Hello\"}" \
https://api.development.push.apple.com/3/device/4cd8bbfa847dcf0e8a8b4911ad8b67325111c14f137f8f5d66a1ce71b549d524
```
* --http2: HTTP/2 指定
* -E: 事前準備で用意した証明書 + 秘密鍵 .pem ファイルのパスを指定
-* apns-topic: 今回作成したサンプルアプリの Bundle Identifier は `com.example.imamurh.pushkitsample` ですが、VoIP プッシュでは `com.example.imamurh.pushkitsample.voip ` といったように `.voip` をつけたものを指定します
+* apns-topic: 今回作成したサンプルアプリの Bundle Identifier は `com.example.imamurh.pushkitsample` ですが、VoIP プッシュでは `com.example.imamurh.pushkitsample.voip ` といったように `.voip` をつけたものを指定
* -d: ペイロードに載せたいデータ (JSON形式)
-* sandbox 環境の場合は `api.development.push.apple.com` ですが、production 環境では `api.push.apple.com` を利用します。
+* sandbox 環境の場合は `api.development.push.apple.com` ですが、production 環境では `api.push.apple.com` を利用
## VoIP プッシュ通知受信
上記リクエストを送って成功するとデバイスに通知が届きます。dictionaryPayload でペイロードが取得できます。
```shell-session
2016-07-18 15:50:48.709 PushKitSample[834:84934] didReceiveIncomingPushWithPayload: [message: Hello]
```
## アプリプロセスを Kill して試す
```shell-session
Jul 18 15:55:29 iPhone-5 PushKitSample[844] <Warning>: didFinishLaunchingWithOptions: Background
Jul 18 15:55:29 iPhone-5 PushKitSample[844] <Warning>: didUpdatePushCredentials: <4cd8bbfa 847dcf0e 8a8b4911 ad8b6732 5111c14f 137f8f5d 66a1ce71 b549d524>
Jul 18 15:55:29 iPhone-5 PushKitSample[844] <Warning>: didReceiveIncomingPushWithPayload: [message: Hello]
```
didFinishLaunchingWithOptions が呼ばれアプリプロセスが起動されている。UIApplicationState が Background なので、VoIP プッシュ通知で起動した場合を判定して処理を分岐できそう。