ここ最近、既存のAndroidプロジェクトをKindleに対応させています。主に、GoogleのサービスをAmazonのものに取り替えるということをしています。この記事は、その過程で学んだ、Google Cloud Messaging を Amazon Device Messagingに切り替える方法の記事です。
Obtaining Amazon Device Messaging Credentials
ADMでは、デバッグ時にAPIキーが必要です。基本的にプロダクションの際には必要ないようです。
まずは、Amazon Apps & Games Developer Portal にてアプリを新規作成。作成されたアプリのメニューの Device Messaging を選択し、Security Profile を作成。この Security Profileは、いくつかのアプリで共有することもできます。もし、この Profileを共有した場合には、データもそのいくつかのアプリ内でシェアされます。
Amazon Apps & Games Developer Portal の Apps & Services > My Apps にて、アプリを既に登録している場合は、そのアプリを選択し、登録していない場合は登録してください。このアプリを選択して、Device Messagingを選択して、Security profile を作成します。
このSecurity Profileを作成したら、View Security Profileをクリックし、Kindle/Android Settingsタブを表示します。ここでやってAPIキーを作成できます。必要な情報は、パッケージ名
、signature(後述)
、APIキーへの名前
。APIキーの名前は、任意です。パッケージ名もAndroidのマニフェストファイル等に書いてあるでしょう。signature
は、少し操作が必要です。私が実際に試した方法は、APKファイルを用意し、ターミナルで下記のコマンドを実行しました。
1 | $ unzip -p {your-app.apk} META-INF/CERT.RSA | keytool -printcert | grep MD5 |
これで、MD5: 2E:0B:46:F8:D0:4A:06:AC:18:7A:2E:B0:42:95:58:FE のようなアウトプットがあるはずです。この 2EからFEまでをコピペすればAPIキーを作成されます。
このAPIキーは先程の、Amazon Apps & Games Developer Portalで確認することができます。しかし、ページをリロードするたびにこのAPIキーは変更されます。これらの複数のAPIキーはどれもvalidらしいので、あまり気にしなくて良いようです。私は、ADMが上手く動かなく、自分のAPIキーの作り方が悪かったのかと、これを疑って時間を潰してしまいました。(ソース)
Setting Up Amazon Device Messaging
ここからはEclipseにて既にAndroidのプロジェクトがあるという前提で話を進めていきます。ここでは、ADMを使用するのに必要なファイルをプロジェクトに追加します。
まずは、Eclipseでプロジェクトのルートディレクトリを右クリック等して、Properties
を選択します。Java Built Path
の中の、Libraries
タブを選択。Add External JARs…
を選択して、SDKの Android/DeviceMessaging/lib
の中の amazon-device-messaging.jar
を選択。SDKは、ここでダウンロードできます。下記の参考リンクにあるSDKへのリンクが異なるので注意です。
これで完了です。一応、Package ExploreのReferenced Libraries の中に、amazon-device-message-**.jar というのが発見できることを確認してください。
Integrating Your App with Amazon Device Messaging
次に、マニフェストファイルの設定、assetへapi_key.txt
の追加、ReceiverとHandler(broadcast receiver)の実装です。
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:amazon="http://schemas.amazon.com/apk/res/android" package="[YOUR PACKAGE NAME]" android:versionCode="1" android:versionName="1.0" > <!-- Because the Fire <span id="XinhaEditingPostion"></span>devices that support ADM are based on Android API level 15, your minSdkVersion must be NO GREATER THAN 15 (<=15). You may have a lower SDK version, if that is appropriate for your app. --> <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" /> <!-- This permission ensures that no other application can intercept your ADM messages. "[YOUR PACKAGE NAME]" is your package name as defined in your <manifest> tag. --> <permission android:name="[YOUR PACKAGE NAME].permission.RECEIVE_ADM_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="[YOUR PACKAGE NAME].permission.RECEIVE_ADM_MESSAGE" /> <!-- This permission allows your app access to receive push notifications from ADM. --> <uses-permission android:name="com.amazon.device.messaging.permission.RECEIVE" /> <!-- ADM uses WAKE_LOCK to keep the processor from sleeping when a message is received. --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- You must explicitly enable ADM and declare whether your app cannot work without ADM (android:required="true") or can work without ADM (android:required="false"). If you specify android:required="false", your app must degrade gracefully if ADM is unavailable. --> <amazon:enable-feature android:name="com.amazon.device.messaging" android:required="true"/> <!-- Provide references to the message handler and broadcast receiver for your app here. Replace the names in the service and receiver tags with names appropriate to your package. --> <service android:name="[YOUR SERVICE NAME]" android:exported="false" /> <!-- This permission ensures that only ADM can send your app registration broadcasts. --> <receiver android:name="[YOUR RECEIVER NAME]" android:permission="com.amazon.device.messaging.permission.SEND" > <!-- To interact with ADM, your app must listen for the following intents. --> <intent-filter> <action android:name="com.amazon.device.messaging.intent.REGISTRATION" /> <action android:name="com.amazon.device.messaging.intent.RECEIVE" /> <!-- You must replace the name in the category tag with your app's package name. --> <category android:name="[YOUR PACKAGE NAME]" /> </intent-filter> </receiver> </application> </manifest> |
このようにpermission等を追加します。
そして、api_key.txt
という名前でファイルをassetsフォルダに置かなければなりません。このファイルには、先ほどのAPIキーをスペース等なくコピペします。
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | public class MyADMMessageHandler extends ADMMessageHandlerBase { public static class Receiver extends ADMMessageReceiver { public Receiver() { super(MyADMMessageHandler.class); } // Nothing else is required here; your broadcast receiver automatically // forwards intents to your service for processing. } @Override protected void onRegistered(final String newRegistrationId) { // You start the registration process by calling startRegister() in your Main // Activity. When the registration ID is ready, ADM calls onRegistered() on // your app. Transmit the passed-in registration ID to your server, so your // server can send messages to this app instance. onRegistered() is also // called if your registration ID is rotated or changed for any reason; your // app should pass the new registration ID to your server if this occurs. // Your server needs to be able to handle a registration ID up to 1536 characters // in length. // The following is an example of sending the registration ID to your // server via a header key/value pair over HTTP. URL url = new URL(YOUR_WEBSERVER_URL); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setDoInput(true); con.setUseCaches(false); con.setRequestMethod("POST"); con.setRequestProperty("RegistrationId", newRegistrationId); con.getResponse(); } @Override protected void onUnregistered(final String registrationId) { // If your app is unregistered on this device, inform your server that // this app instance is no longer a valid target for messages. } @Override protected void onRegistrationError(final String errorId) { // You should consider a registration error fatal. In response, your app may // degrade gracefully, or you may wish to notify the user that this part of // your app's functionality is not available. } @Override protected void onMessage(final Intent intent) { // Extract the message content from the set of extras attached to // the com.amazon.device.messaging.intent.RECEIVE intent. // Create strings to access the message and timeStamp fields from the JSON data. final String msgKey = getString(R.string.json_data_msg_key); final String timeKey = getString(R.string.json_data_time_key); // Obtain the intent action that will be triggered in onMessage() callback. final String intentAction = getString(R.string.intent_msg_action); // Obtain the extras that were included in the intent. final Bundle extras = intent.getExtras(); // Extract the message and time from the extras in the intent. // ADM makes no guarantees about delivery or the order of messages. // Due to varying network conditions, messages may be delivered more than once. // Your app must be able to handle instances of duplicate messages. final String msg = extras.getString(msgKey); final String time = extras.getString(timeKey); } } |
そして、遂にRegistrationId(デバイストークン)を取得し、それを適宜サーバーへ送信です。後は、サーバー側からメッセージをこのトークンを使用して送ることができます。
雑ですが以上です。
参考
Obtaining Amazon Device Messaging Credentials
Setting Up Amazon Device Messaging
Integrating Your App with Amazon Device Messaging
Requesting an Access Token for Amazon Device Messaging
Thread: why do API keys of game circle keep changing when refreshing the web page ?