LoginSignup
18
13

More than 5 years have passed since last update.

MQTTでAWS IoTやSORACOM beamにAndroidから接続する

Posted at

概要

MQTTをお試しするためにAndroidからAWS IoTやSORACOM beamに接続してみました。
AWS IoTとの接続はMQTTクライアントのPahoを使おうと思ったのですが、AWS SDK for Androidのjavadocを読んでみるとAWS IoT関連のクラスがあったので使ってみました。

※ここではブローカー側の設定については触れません。クライアント側の実装に絞って説明します。

準備

まずは依存関係にAWS SDKを追加。

dependencies {
    compile 'com.amazonaws:aws-android-sdk-core:2.+'
    compile 'com.amazonaws:aws-android-sdk-iot:2.+'
} 

ビルドすると、Pahoのライブラリも追加されるので、AWS SDKのMQTT関連の実装はPahoのラッパーになっているようです。

ServiceへのAWS IoTの実装

AndroidのサービスクラスにAWS IoTとの通信をおこなう処理を実装しました。

接続開始

AWS ConsoleでAWS IoTのセットアップをおこなうとエンドポイント、証明書と秘密鍵が生成されます。
(参考: AWS IoTとRuby製MQTTクライアントでPub/Subしてみた

生成された情報を使って接続を行います。
接続にはキーストアが必要となるため、アセットに格納しておいた証明書と秘密鍵を読み出しキーストアに格納することにしました。 (証明書と秘密鍵の扱いは本番運用ではちゃんと考えないといけないです。)

ACCOUNT_ENDPOINT_PREFIXは、XXXXXXXXXXX.iot.REGION.amazonaws.comの先頭 (XXXXXXXXXXX) の部分です。
CLIENT_ID、CERT_ID、KEY_STORE_NAME、KEY_STORE_PASSWORDは適当に決めます。

public class MqttService extends Service {
    private AWSIotMqttManager mqttManager;
    private static final String CLIENT_ID = "xxxxx";
    private static final String ACCOUNT_ENDPOINT_PREFIX = "xxxxx";
    private static final String CERT_ID = "xxxxx";
    private static final String KEY_STORE_NAME = "xxxxx.jks";
    private static final String KEY_STORE_PASSWORD = "xxxxx";
    private static final String CERT_FILE = "xxxxx-certificate.pem.crt";
    private static final String PRIVATE_KEY_FILE = "xxxxx-private.pem.key";
    private String keyStorePath;
    private KeyStore keyStore;

    @Override
    public void onCreate() {
        super.onCreate();
        mqttManager = new AWSIotMqttManager(CLIENT_ID, Region.getRegion(Regions.AP_NORTHEAST_1), ACCOUNT_ENDPOINT_PREFIX);
        keyStorePath = getFilesDir().getAbsolutePath();
        boolean isPresent = AWSIotKeystoreHelper.isKeystorePresent(keyStorePath, KEY_STORE_NAME);
        if (isPresent) {
            keyStore = AWSIotKeystoreHelper.getIotKeystore(CERT_ID, keyStorePath, KEY_STORE_NAME, KEY_STORE_PASSWORD);
        } else {
            saveCertificateAndPrivateKey(keyStorePath);
            keyStore = AWSIotKeystoreHelper.getIotKeystore(CERT_ID, keyStorePath, KEY_STORE_NAME, KEY_STORE_PASSWORD);
        }
        mqttManager.connect(keyStore, new AWSIotMqttClientStatusCallback() {
            @Override
            public void onStatusChanged(AWSIotMqttClientStatus status, Throwable throwable) {
                Log.d(TAG, "AWSIotMqttClientStatus changed.");
            }
        });
    }
    private void saveCertificateAndPrivateKey(String keyStorePath) {
        String cert = assetsFileToString(CERT_FILE);
        String priv = assetsFileToString(PRIVATE_KEY_FILE);
        AWSIotKeystoreHelper.saveCertificateAndPrivateKey(CERT_ID, cert, priv, keyStorePath, KEY_STORE_NAME, KEY_STORE_PASSWORD);
    }

    private String assetsFileToString(String file) {
        // 省略: アセットのファイルを読みだし文字列として返す。
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mqttManager != null) {
            mqttManager.disconnect();
        }
    }
}

メッセージの送信 (Pub)

JSONメッセージを引数にpublishStringメッセージを叩くだけです。
トピックは適当に決めます。

if (mqttManager != null) {
    mqttManager.publishString(msg, TOPIC, AWSIotMqttQos.QOS0);
}

メッセージの受信 (Sub)

すみません、、、試してません。subscribeToTopicメソッドでSubscribeしてコールバックを受け取るだけと思います。

接続先をSORACOM beamに変更する

AWS IoTのラッパーを使わずに、Pahoのライブラリを直接実行します。

接続開始

キーストアが要らないのでとてもシンプルになります。

    private MqttClient mqttClient;
    private static final String BROKER_ENDPOINT = "tcp://beam.soracom.io:xxxx";

   @Override
    public void onCreate() {
        super.onCreate();
        try {
            mqttClient = new MqttClient(BROKER_ENDPOINT, CLIENT_ID, new MemoryPersistence());
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(true);
            mqttClient.connect(connOpts);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mqttClient != null) {
            try {
                mqttClient.disconnect();
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

メッセージの送信 (Pub)

こちらはJSONを一旦MqttMessageに格納してやる必要があります。

if (mqttClient != null) {
    MqttMessage sendMessage = new MqttMessage(msg.getBytes());
    sendMessage.setQos(0);
    mqttClient.publish(TOPIC, sendMessage);
}

メッセージの受信 (Sub)

すみません、、、こちらも試してません。subscribeメソッドとsetCallbackメソッドで実現できるはず。

参考情報

18
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13