iOS10にしたらPush通知で「Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません」(TitaniumでiOSのAPNSプッシュ通知サンプル)

この記事はTitaniumでiOSのAPNSプッシュ通知を受けるためのnode.jsサーバーも使ったサンプルです。

TitaniumでAPNSプッシュ通知

iOSのリモートプッシュ通知(Apple Push Notification Service)は、サーバーを準備したりHTTPSの証明書が必要だったりとやや複雑な印象があります。

ここではnode.jsのapnsモジュールとTitaniumSDKを使ったプッシュ通知を行う最低限のコードと、証明書の登録の仕方を紹介します。

APNSへの登録と証明書の作成

1.AppleDeveloperのサイトでテスト用のAppIDを作ります。Explicit App IDを使う必要があります。この例ではcom.test.notificationtestとします。App ServicesでPush Notificationを選択しておきます。

2.出来たAppIDを開いてEdit。CreateCertificationで証明書を作ります。画面に従いMacのKeyChainAccessを使って要求証明書をつくりアップロードします。

3.証明書ができましたら同じところからDownload。出来たファイルをダブルクリックでKeyChainAccessに入ります。

4.MyCertificatesから該当の証明書をExportします。cert.p12とします。パスワードを設定した場合は覚えておきます。

5.出来たp12ファイルをmakecert.sh(下のソース)を使ってPEMファイルに変換します(例: ./makecert.sh cert.p12 cert.p12) Import用のパスワードは上記のものを、pemファイルとkey用のパスワードは2回聞かれるので同じものを入力します。)

6.これで準備完了です。apns-key-noenc.pemがkeyでapns-cert.pemが証明書です。

if [ $# != 2 ]
then
    echo 'makecert.sh <cert.p12> <key.p12>'
else
    openssl pkcs12 -clcerts -nokeys -out apns-cert.pem -in $1
    openssl pkcs12 -nocerts -out apns-key.pem -in $2
    openssl rsa -in apns-key.pem -out apns-key-noenc.pem
fi

Titaniumアプリ(Push通知を受ける最低限のコード)

下記のapp.jsを使ったTitaniumプロジェクトをつくりビルドしておきます。シミュレータではPush通知は受け取れないので実機でテストする必要があります。

ここで使うプロビジョニングプロファイルは必ず上のPushNotificationを有効にしたAppIDのものを使う必要があります。(「App の有効な "aps-environment" エンタイトルメント文字列が見つかりません」エラーになる)

Ti.App.iOS.registerUserNotificationSettings({
    types: [
        Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
        Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
        Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
    ]
});

var registerForPush=function(){
    Titanium.Network.registerForPushNotifications({
        success:function(e){
            var deviceToken = e.deviceToken;
            Ti.API.info("DeviceToken:"+deviceToken);
        },
        error:function(e){
            Ti.API.info("Error:"+e.error);
        },
        callback:function(e){
            Ti.API.info(JSON.stringify(e))
            var data=e.data
            var message = e.data&&e.data.server&&e.data.server.message;
            if(message){
                alert(message);
            }
        }
    }); 
    Ti.App.iOS.removeEventListener('usernotificationsettings', registerForPush); 
}

Ti.App.iOS.addEventListener('usernotificationsettings', registerForPush);
Ti.UI.createWindow().open();

上記Titaniumアプリを実機で起動するとログにDeviceIDが出力されますので、メモしておきます。

送信側Node.js(CoffeeScript)アプリ

下記のCoffeeScriptを実行します。DEVICEIDの所はは上記のものに書き換えます。

#!/usr/bin/env coffee

apns=require "apns"

options =
   keyFile : "apns-key-noenc.pem"
   certFile : "apns-cert.pem"
   gateway : "gateway.sandbox.push.apple.com"
   debug : true

connection=new apns.Connection(options)

notification=new apns.Notification()
notification.device = new apns.Device("DEVICEID")
notification.alert="Hello"
notification.payload=
    server:
        message:"World"

connection.sendNotification(notification)

注意とポイント

iOS8から通知の登録方法が変わっている為、この例はiOS8以前では対応していません。

デバイスIDは手動でコピーしましたが、実運用ではアプリ側からサーバー側にHTTP等で送信することになります。

iOS10にしたらPush通知で「Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません」

全く同じアプリのバイナリなのにiOS10上で上記のエラーが発生する場合があります。その場合はプロジェクトのルートに以下のファイルを作って再ビルドしてください。

ファイル名:Entitlements.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "h
ttp://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>aps-environment</key>
        <string>production</string>
</dict>
</plist>

これはiOS10ではプロダクション(もしくはアドホック)パッケージのデバイストークン取得時に上記の設定値をチェックする様になったからです。(プロビジョニングプロファイルで判断されます)

Titaniumではなくネイティブでのビルドの場合はXCODE8の

Target -> Capabilities -> Push Notifications

Add the Push Notifications entitlement to your entitlements file

に対するFix操作をすることで(プロジェクト名).entitlementsファイルに上の値が追加されます。

Titaniumの場合はプロジェクトルートのEntitlements.plistがビルド時に上記entitlementsファイルにコピーされる仕組みです。

ちなみに下記によればデベロップメント時はstringをdevelopmentにするべきなのでしょうが、iOS10現在では開発時productionのままでも問題なさそうです。(しかもXCODE8では反対にプロダクション時でもdevelpment固定で出力している模様)

この記事を見た人がよく読んでいる記事

カナシスコム > 節約テクノロジ > iOS10にしたらPush通知で「Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません」(TitaniumでiOSのAPNSプッシュ通知サンプル)