スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

iPhoneアプリでプッシュ通知(push notification)を実装する

[PR]
banner.png

※修正あり 2014/4/14

■はじめに


今回はiPhoneアプリ制作に利用できる機能の中でも特におさえておきたいプッシュ通知について説明します。
iPhoneアプリを制作して数年になりますが、実際のプログラミングよりも申請系の話がややこしく、個人的に非常に不満に思っています。
わからないことが出るとネットで調べるのですが、一部情報が抜け落ちていてたらい回しになったり、説明通りにやっても上手く行かなかったりで膨大な時間をロスしてきました。
この記事では「この記事さえ読めばプッシュ通知ができるようになる」ことを目標にしています。
とても長い記事ですがぜひこの通りに進んでみてください。
※なお、この記事は2013年12月24日時点の情報です

■目的


iPhoneアプリでプッシュ通知を実装します。
最終的にシンプルなメッセージを表示させるプッシュ通知を送れるようになります。

■準備


・iPhoneまたはiPadの実機・・・PUSH通知はシミュレータでは動かないのでテスト用のデバイスが必要
・iOSのディベロッパー登録(有料)・・・アプリ開発に必要
・XCODE・・・アプリ開発に必要
・インターネットにつながったサーバ・・・PUSH通知を送付するためのサーバ

■注意


一部英単語を日本語に訳さずに使っています。
iPhoneのディベロッパー用のページが英語なので日本語に訳すと逆にややこしくなる部分がある為です。
なお、この記事は下記の記事をベースに、著者が実際にステップを追って実施した内容に編成しています。
http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1

■開発を始める


プッシュ通知とは?


プッシュ通知を使えばサーバーを経由してアプリのユーザに下記のことを行うことができます。
・短いメッセージを表示
・効果音を鳴らす
・バッジに数字を表示

プッシュ通知のフロー


1. プッシュ通知をアプリが有効にするためにはユーザがプッシュ通知の受信を有効にしなければいけない
2. 各デバイスには固有のdevice tokenが存在する。アプリはdevice tokenをデバイスから取得する。
3. アプリがサーバにdevice tokenを伝えておく
4. お知らせを送りたいタイミングでサーバがプッシュ通知をApple Push Notification Service(APNS)に送る
5. APNSがユーザのデバイスにお知らせを送る

つまりアプリ開発側で必要なのは、プッシュ通知を送付したいデバイスのdevice tokenをあらかじめ取得しておいて、プッシュ通知を送るタイミングでdevice tokenを添えたメッセージをアップルが用意しているプッシュ通知用のサーバ(APNS)に送るとApple側でdevice tokenを持つデバイスあてにプッシュ通知を送ってくれるということです。


プッシュ通知の中身


プッシュ通知にはdevice tokenとペイロード(送りたいデータ)が入っています。
ペイロードはJSON形式で送られます。
シンプルな例

{
"aps":
{
"alert": "Hello, world!",
"sound": "default"
}
}

このJSONには少なくとも"aps"という要素が必要です。
とりあえずここではこういうものだ、くらいに思っておいてください。


プッシュ通知の信頼性とコスト


プッシュ通知は送ったら送りっぱなしなので、ユーザがきちんと受信したかどうかは考慮されません。
また、ユーザが多い場合やデータが多い場合はプッシュ通知がたくさん飛ぶ可能性があるのでデータ転送量によるコストに留意する必要があります。例えばチャットアプリであればユーザがユーザの好きなタイミングでプッシュ通知を飛ばすことになるので管理側ではコントロールできないため、想定以上のデータ転送によりネットワークコストがかかる可能性があります。

Appleへ申請


Provisioning ProfileとCertification


プッシュ通知を利用するためにはプッシュ通知を出すためのProvisioning Profileが必要です。
また、あなたのサーバがAPNSとSSLで通信するためのCertification(証明書)が必要です。
iOSのアプリはDevelopment(開発)とDistribution(配布)でそれぞれProvisioning Profileが必要ですが、プッシュ通知のサーバー証明書にも2種類あります。
1. 開発用:アプリがデバッグモードで実行されており、Development Provisioning Profileで(iPhone Developer)であるとき、サーバはDevelopment Certificationを利用します
2. 本番用:アプリがAd HocまたはApp Storeで配布されている(iPhone Distribution)とき、サーバは本番用のCertificationを利用します。
上記1、2においてミスマッチがあればプッシュ通知は送付されません。


Certificate Signing Request(CSR)を作成


プッシュ通知を実装する際に発生する失敗の多くは証明書取得のステップから間違っています。
下記のステップはよく確認するようにして下さい。
Certification(電子証明書)は「公開鍵ー秘密鍵」の暗号化によって形成されているため、これらがペアで動くことは覚えておく必要があります。Certificationは公開鍵なので他者に渡しても問題ないですが、秘密鍵は公開してはならず、秘密鍵がないとCertificationは利用できないことに注意が必要です。
CertificationにはCertificate Signing Request(CSR)が必要となります。CSRは作られるとあなたのキーチェーンに入れられます。そしてそのCSRを証明書発行者(ここではiOS Developer Portal)に渡すとCSRの情報に沿ったSSL証明書が発行されるというステップです。

まず、Macでキーチェーンアクセスを開き、Request a Certificate from a Certificate Authority ...を選びます。
もし、Request a Certificate from a Certificate Authority with keyがない場合は先にWWDR intermediate Certificateをダウンロードする必要があります。
https://developer.apple.com/certificationauthority/AppleWWDRCA.cer


Request a Certificate from a Certificate Authorit

main Keychain Accessウィンドウで秘密鍵が選択されていないことを確認します。
Certificate Assistantのウィンドウがでてくるのでメールアドレスを入れます。
iOS Developer Programで登録しているアドレスを入力したほうがいいという説もありますが、どんなアドレスでも特に問題無さそうです。Common Nameは好きな名前をいれて良いのですが、あとあとわかり易い名前にしておいてください。
Save to diskにチェックをいれてContinueを押します。
例では“PushNotif.certSigningRequest"
で保存。

screenshot_06.png

キーチェーンアクセスのKeysにいくと、新しい秘密鍵ができているので右クリックして書き出します。
PushNotifKey.p12で保存しますが、ここでパスワードを設定します。
パスワードは特定されにくいものを利用する必要がありますが、パスワードを忘れてしまうと後々使えなくなるので注意してください。

screenshot_09.png


App IDとSSL証明書を作成


iOS Dev Centerにログインして"Select the Certificates, Identifiers and Profiles"を選択します。
https://developer.apple.com/ios


screenshot_11.png


iOS AppsのCertificates を選択し、新しいApp IDを作成します。

screenshot_13.png

それぞれのプッシュ通知アプリは固有のIDが必要になります(通知は特定のアプリに送付されるため共有のAPP IDは使えないため)
APP IDs「+」を押す。

screenshot_12.png

App ID Description: PushNotif
App Services: Push Notificationにチェックを入れる
Explicit App ID: com.xxxxxx.PushNotif

※Explicit App IDには適当な値を入れて下さい。あなたがウェブサービスをしていてドメインを持っている場合は上記の例のように記載するのが便利です。これはIDをユニークなものにするためです。

これであなたのサーバがAPNSとセキュアなコネクションを作るための証明書ができました。
Push NotificationsのDevelopmentとDistributionがConfigurableになっているはず。
これでPush Notificationがつかえるようになりましたがまだ設定が必要になります。

Settingボタンを押します。
Push Notificationのセクションまでスクロールし、Development SSL CertificateのCreate Certificateボタンを押します。

Add iOS Certificateウィザードが立ち上がります。

はじめのステップでCertificate Signing Requestを作るか聞いてくるが、すでに作ってあるのでContinueを押します。
次のステップではCSRをアップロードするので、前のステップで作ったCSRファイルを選んでGenerateを押します。
SSL証明書を作成するのには数秒かかるのでしばらく待ちます。
終わったらContinueをクリックして証明書をダウンロードします。
ここではaps_development.cerという名前で保存します。

これでdevelopmentのプッシュ通知が有効になりました。
もし必要であればここから再度証明書をダウンロードすることもできます。
developmentの証明書は3ヶ月間しか有効ではないので注意してください。
アプリのリリース準備が済めば同じステップを本番環境用にも行う必要があります。ステップは上記と一緒です。
(本番環境用の証明書は1年間有効)

この証明書はキーチェーンアクセスに登録する必要はないですが、そうしたければダウンロードしたaps_development.cerファイルをダブルクリックすれば登録ができます。

PEMファイルを作る


ここまでのステップで3つのファイルを手に入れました。
1. CSR
2. 秘密鍵であるp12ファイル
3. SSL証明書であるaps_development.cer

これらのファイルは安全な場所に保存しましょう。
CSRは破棄してしまっても構いませんが、とっておけば証明書が無効になった際に同じCSRを利用して新しいファイルを作成することができます。
同じCSRを利用する場合において秘密鍵も同じものを使えますが、.cerファイルのみが更新が必要です。

さて、PHPでプッシュ通知をコントロールするためには証明書と秘密鍵を使いやすい形式に変更する必要があります。
PEM形式でCertificateと秘密鍵を1つにまとめます。
※もしPHP以外の言語を使う場合はこの後のステップは変わります

このステップの為にはコマンドラインのOpenSSLツールを利用します。
Macでターミナルを開いて次のステップを実行。
ターミナルが登場すると一気にハードルが高くなる感じがしますが実施することは単純です。

まず、ファイルが保存されているフォルダへ移動します。
下記の例ではデスクトップに移動しました。
※この時点で意味がわからない場合はとりあえず今まで作成したすべてのファイルをMacのデスクトップ上に置いておけば何も意識することなくステップを進むことができます。

$ cd ~/Desktop/

.cerファイルを.pemファイルに変更します。

$ openssl x509 -in aps_development.cer -inform der -out PushNotifCert.pem

.p12の秘密鍵を.pemに変更します。

$ openssl pkcs12 -nocerts -out PushNotifKey.pem -in PushNotif.p12
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

はじめにopensslが読めるように前のステップで入力した.p12用のパスワードを入力します。
その後PEMの暗号化の為のパスワードを入力します。

最後に証明書とキーを1つの.pemファイル(ck.pem)に纏める

$ cat PushNotifCert.pem PushNotifKey.pem > ck.pem

ここで、この証明書が上手く動作するかを確認してみます。
まずはターミナルに下記のように打ち込みます。

$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.172.232.226...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.

これは暗号化されていない通常の接続をAPNSサーバに対して行っています。
もし上記のような回答(Trying 17.172 ...)を得ていればあなたのMacはAPNSにたどり着けていることになるのでCtrl+Cをおして接続を切ります。
もしエラーメッセージがでたらあなたのファイアーウォールが2195ポートを許可しているか確認してみましょう。

次はSSL証明書と秘密鍵を利用して接続してみます。

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195
-cert PushNotifCert.pem -key PushNotifKey.pem
Enter pass phrase for PushNotifKey.pem:

もし接続がうまくいけば文字を打ち込むことができます。
エンターを押すとサーバとの接続が切れます。
接続の確立がうまくいかない場合、opensslはエラーメッセージを返します。

APNSには2つのサーバがあります。
sandboxはテスト用、liveは本番用で利用できます。
上の例ではテスト環境なのでsandboxへアクセスしました。


Provisioning Profileを作成


iOS Dev Centerはまだ終了していません。
サイドバーのProvisioning Profilesボタンをおして+を押すとウィザードが開かれます。

iOS App developmentオプションボタンを選択し、Continueボタンを押します。

前のセクションで作成したPushNotif appのidを選択します。
これでこのprovisioning profileはPushNotif appと紐付けられます。

次にどのCertificateをprovisioning profileに含ませるかを選択します。

次にどのデバイスをprovisioning profileに含みたいかを選択します。いまは開発用なので開発用のデバイスを選択します。

次にprovisioning profileに名前をつけます。ここではPushNotif Developmentと名付けます。


最後にDownloadボタンをおしてDevelopment provisioning profileをダウンロードします。
このファイルをダブルクリックすることでXcodeに追加できます。
アプリをリリースする準備ができたらAd HocまたはApp Store配布用のプロファイルで同じステップを踏めばOKです。


基本的なアプリ


プッシュ通知が送れるかを試してみましょう。
Xcodeを開き、File, New Project, Single View Applicationと選びます。


例として下記のように埋めました。
Product Name: PushNotif
Organization Name: test
Company Identifier: com.xxxxxx
Device Family: iPhone


Product NameとCompany IdentifierはBundle IDを形成します。
この例ではcom.xxxxx.PushNotifとなる。
Product NameとCompany IdentifierはProvisioning Portalで作成したApp ID(com.xxxxx.PushNotif)と一致させる必要があります。
“Use Storyboards"と“Use Automatic reference counting”にはチェックを入れます。

AppDelegate.mを下記のようにします。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

return YES;
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(@"My token is: %@", deviceToken);
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error);
}



registerForRemoteNotificationTypes:
はアプリに対してPush通知を利用することを明示します。
Build & Runを実行してみますが、シミュレータでは動かないため、このステップはデバイスで行う必要があります。
Xcodeは自動的に新しいprovisioning profileを選択します。
もしcode sign errorが返ったらCode Signing build setting できちんとprofileが選択されているかを確認しましょう。
上手く行った場合、アプリがプッシュ通知を受信することを確認するメッセージが表示されるはずです。
OKを選択すれば準備が整う。許可しないを選択する場合はプッシュ通知を受け取ることができませんが、iPhoneの設定から変更することも可能です。

さて、上記ではNSLogでtokenを出力しています。
デバッグのウィンドウを確認するとテストで利用している端末のtokenが確認できます。

My token is:
<740f4707 bebcf74f 9b7c25d4 8e335894 5f6aa01d a5ddb387 462c7eaf 61bb78ad>

このtokenとは、デバイスを識別する為のアドレスのようなものです。
手順としては
1. アプリをダウンロードさせる
2. アプリを起動してプッシュ通知を許可させる
3. デバイスのtokenを取得する
4. 取得したtokenを指定してプッシュ通知を送付する

ということになります。
なお、この後このtokenを利用しますが、<>や文字列の間の空白は削除して利用する必要があるので注意してください。

はじめてのプッシュ通知


前のステップで作成したck.pemをサーバーにアップします。
テキストエディタに下記のように記載し、pushnotif.phpという名前で保存し、ck.pemを保存した階層にアップします。
なお、deviceTokenにはテストで利用したデバイスのtokenを入れてください。
passphraseには前のステップで設定した秘密鍵のパスワードを入れます。


記載漏れのコメントを頂き2014/4/15追記


$deviceToken = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
$passphrase = 'xxxxxxxxxxxx';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS' . PHP_EOL;
$body['aps'] = array(
'alert' => 'hello',
'sound' => 'default'
);
$payload = json_encode($body);
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
fclose($fp);



ここまで


アップしたpushnotif.phpをブラウザで開けばテスト用のデバイスにプッシュ通知が送付されます。



いかがでしょうか?通知は届いたでしょうか?
ちょっと説明不足の部分があるかもしれませんので後ほどブラッシュアップしますが、とりあえず上記の内容でうまくいくはずです。
プッシュ通知を利用できるようになるとiOSのアプリがグッと強力なものになります。




[PR]
banner.png

コメント

No title

こんにちは、参考にさせてもらいました。ありがとうございます。

ただ、一部分かりにくいところがありました。
○途中でPushNotifCert.pem が突然でてきて説明がありません。
○まとめた ck.pem を phpスクリプトのどこで使うのか説明不足。というかスクリプト自体が一部しか提示されていません。

以上、気になったところです。しかし、全体的には良く出来てて大変参考になりました。ありがとうございます。

No title

あ、すいません。間違えました。PushNotifCert.pem の方じゃなくて PushNotif.pem ですね。この説明がないと思います。

このページを読んで、うまく実装することができました。ありがとうございます。

Re: No title

コメントありがとうございます。
とりあえず公開して少しでも早く役立てればと思っていましたがその後ちゃんと整理していませんでした。
phpの例文を追記しました。
少し前の投稿なので記憶が曖昧なのですが参考になればと思います。

コメントの投稿

非公開コメント

PR

PR

プロフィール

何でも書くman

Author:何でも書くman
思ったことや備忘録など、とりあえずなんでも書きます。IT系のことや趣味、生活に関わることなども。

ページの先頭へ戻る
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。