Menu

Category

Archive

logo


Amazon Device Messagingの実装

2014-10-17 21:30:00 +0900
  • このエントリーをはてなブックマークに追加

ここ最近、既存の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 ?