はじめに
サイレントプッシュ通知というものが、iOS7から出来るようになっていて、これを利用した情報の更新を考えました、大体の仕様は色々サイトを巡ったらわかったのですが、アプリケーションが完全に起動していない時は、結局来るのか来ないのかわからなくて困ったので、もうサーバから作ったほうが今後のテストもできるし早い、と思い作ったので、今回はその手順と結果を書きました。
プッシュ通知サーバの準備
APNSを利用して通知を送るためにnode.jsでサーバを建てます。
node.jsをインストールするために、homebrewでnodeとnpmをインストールします。※ターミナルを使って下さい。
1 |
$ brew install node |
続いて、nodeのapnsモジュールを入れます。
1 |
$ npm install -g apn |
好きな場所にサーバ用のディレクトリを切ります。
1 2 |
$ mkdir apns_server $ cd apns_server |
作成したディレクトリにapp.jsファイルを作り、下記のソースコードを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
var http = require('http'); var server = http.createServer(); var apns = require('apn'); var options = { cert : './apns-dev-cert.pem', key : './apns-dev-key-noenc.pem', gateway : 'gateway.sandbox.push.apple.com', port : 2195, }; // 送信先のデバイストークンを設定 var token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; var myDevice = apns.Device(token); server.on('request', function(req, res) { // リクエストが来るとここの処理が実行される var apnsConnection = new apns.Connection(options); var note = new apns.Notification(); // 通知の設定 // note.badge = 2; // note.alert = 'test message'; // サイレントプッシュ通知の場合は、下記設定にする note.device = myDevice; note.contentAvailable = 1; note.priority = 10; note.sound = ''; // 送信 apnsConnection.sendNotification(note); // 表示 res.writeHead(200, {'Content-Type': 'text/html'}); res.write('送信しました。'); res.end(); }); server.listen(3000, '127.0.0.1'); console.log('start server'); |
このままでは、apns-dev-cert.pemとapns-dev-key-noenc.pemとデバイストークンが足りないので準備します。
まずpemです。iOS Developer Centerにて色々しなければならないのですが、長くなるので下記を参考にして、証明書を作るまでやって下さい。
Apple Push Notification Serviceを使ってiOSにプッシュ通知をするために必要な証明書の準備方法
下記スクリーンショットのようにキーチェインに入ったら、右クリックして証明書をapns-dev-cert.p12、秘密鍵をapns-dev-key.p12という名前で書き出しします。
書き出したら、書きだしたディレクトリで下記コマンドを叩きます、書きだした時のパスワードがいるので気をつけて下さい。
1 2 3 |
$ openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12 $ openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12 $ openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem |
これが成功するとapns-dev-cert.pemとapns-dev-key-noenc.pemが生成されるので、先ほど実装していたapp.jsと同じディレクトリに入れてください。
続いてデバイストークンを取得します。
XCodeでSingle View Applicationを作り、プロジェクトのCapabilitiesを開き、Remote notificationsにチェックを入れます。
プッシュ通知の許可をユーザに求めるため、AppDelegateのdidFinishLaunchingWithOptionsに追加します。
1 2 3 4 5 6 7 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 通知許可 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; [application registerForRemoteNotifications]; [application registerUserNotificationSettings:settings]; } |
下記をAppDelegateに実装することで、デバイストークンの取得ができます。
1 2 3 4 5 6 |
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *deviceTokenString = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; deviceTokenString = [deviceTokenString stringByReplacingOccurrencesOfString:@" " withString:@""]; NSLog(@"%@", deviceTokenString); } |
この状態で実機デバックをするとログにデバイストークンが表示されますので、app.jsの下記を書き換えます。
1 |
var token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; |
また、下記をAppDelegateに実装することで通知が届いた時に、ログが出るようになります。
1 2 3 4 |
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { NSLog(@"didReceiveRemoteNotification"); } |
起動、そしてプッシュ通知送信
長くなってしまいましたが、これで準備が整ったので、ターミナルでapp.jsがあるディレクトリまで移動して、下記コマンドを叩きます。
1 |
$ node app.js |
そうすると「start-server」と表示されるので、ブラウザで「http://localhost:3000/」にアクセスし、送信しました。と出たら成功で、端末のログを見ると「didReceiveRemoteNotification」と表示されます。
これでいつでもプッシュのテストができるようになりました。
まとめ
・プッシュ通知に「content-available」が1と設定されているとサイレントプッシュ通知になるが、結構高い確率で届かない、「priority」と「sound」を追加するとかなりの確率で届くようになった。
・サイレントプッシュ通知は端末上に表示されない。
・アプリが完全に起動していない時は届かない。
・ユーザがそもそも通知の許可をしてない場合は届かない。