KotlinでAndroidとMQTTを連携

![AndroidとMQTT: ステップ・バイ・ステップ ガイド](https://assets.emqx.com/images/blog_bg_en/android.png?imageMogr2/thumbnail/1520x684)

[MQTT](https://www.emqx.com/en/blog/the-easiest-guide-to-getting-started-with-mqtt)は、IoTメッセージの交換とデータ配信を実現するための軽量かつ柔軟なプロトコルです。IoT開発者にとって、柔軟性とハードウェア/インターネットリソースのバランスをとるのに役立ちます。

[Kotlin](https://kotlinlang.org/)はJetBrainsによって開発されたプログラミング言語です。KotlinはJVMベースなので、開発者はAndroid開発に簡単に使用でき、KotlinとJavaの混合記述もサポートしています。

この記事では、主にAndroidプラットフォームでのKotlinの使用方法を紹介し、MQTTの利用方法を説明します。

## プロジェクトの初期化

Android Studioを開き、新しいプロジェクトを作成し、言語としてKotlinを選択すると、Android Studioは自動的にKotlin関連の設定を作成します。既存のプロジェクトの設定が必要な場合は、[既存のアプリにKotlinを追加](https://developer.android.com/kotlin/add-kotlin)を参照できます。

### 依存関係の追加 

プロジェクトの`build.gradle`を開き、セクション`dependencies`に[Eclipse Paho Java Client](https://www.eclipse.org/paho/clients/java/)および[Eclipse Paho Android Service](https://www.eclipse.org/paho/clients/android/)の依存関係を追加します。

```groovy
dependencies {
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.4' 
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}
```

### `AndroidManifest.xml`の設定

Android ServiceはAndroidベースでEclipseによって開発されたバックエンドサービスです。AndroidManifest.xmlファイルに登録する必要があります。同時に、パーミッションの登録も必要です。

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
   ...
   <service android:name="org.eclipse.paho.android.service.MqttService" /> 
</application>
```

## MQTTの使用

### MQTTクライアントの作成

```kotlin
private lateinit var mqttClient: MqttAndroidClient
// タグ
companion object {
    const val TAG = "AndroidMqttClient" 
}
```

### MQTTブローカーへの接続

この記事では、EMQXが運用・管理する[MQTTブローカー](https://www.emqx.com/en/mqtt/public-mqtt5-broker)を使用します。EMQX [MQTT Cloud](https://www.emqx.com/en/cloud)は、[EMQ](https://www.emqx.com/en)がリリースしたMQTT IoTクラウドサービスプラットフォームで、オールインワンの運用・保守とユニークな分離環境を提供します。

- ブローカー: **broker.emqx.io**  
- TCPポート: **1883**
- Websocketポート: **8083**

```kotlin
fun connect(context: Context) {
        val serverURI = "tcp://broker.emqx.io:1883"
        mqttClient = MqttAndroidClient(context, serverURI, "kotlin_client") 
        mqttClient.setCallback(object : MqttCallback {
            override fun messageArrived(topic: String?, message: MqttMessage?) {
                Log.d(TAG, "Receive message: ${message.toString()} from topic: $topic")
            }

            override fun connectionLost(cause: Throwable?) {
                Log.d(TAG, "Connection lost ${cause.toString()}") 
            }

            override fun deliveryComplete(token: IMqttDeliveryToken?) {

            }
        })
        val options = MqttConnectOptions()
        try {
            mqttClient.connect(options, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Connection success")
                }

                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.d(TAG, "Connection failure")
                }
            })
        } catch (e: MqttException) {
            e.printStackTrace()
        }

    }
```

`MqttCallback` インターフェースには3つのメソッドが含まれています。

1. messageArrived: ブローカーからの新しいメッセージを受信
2. connectionLost: ブローカーへの接続が途絶えた
3. deliveryComplete: ブローカーへのメッセージ配信が完了

`MqttConnectOptions` は、ユーザーパスワード、タイムアウト設定などの接続設定を構成するために使用されます。詳細は関数をご覧ください。

### MQTTサブスクリプションの作成

トピックのサブスクライブ

```kotlin
fun subscribe(topic: String, qos: Int = 1) {
        try {
            mqttClient.subscribe(topic, qos, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Subscribed to $topic")
                }

                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.d(TAG, "Failed to subscribe $topic")
                }
           })
        } catch (e: MqttException) {
            e.printStackTrace()
        }
    }
```

### サブスクリプションの解除

```kotlin
fun unsubscribe(topic: String) {
        try {
            mqttClient.unsubscribe(topic, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Unsubscribed to $topic")
                }

                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.d(TAG, "Failed to unsubscribe $topic")
                }
            })
        } catch (e: MqttException) {
            e.printStackTrace()
        }
    }
```

### メッセージのパブリッシュ

```kotlin
fun publish(topic: String, msg: String, qos: Int = 1, retained: Boolean = false) {
        try {
            val message = MqttMessage()
            message.payload = msg.toByteArray()
            message.qos = qos
            message.isRetained = retained
            mqttClient.publish(topic, message, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "$msg published to $topic")
                }

                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.d(TAG, "Failed to publish $msg to $topic")
                }
            })
        } catch (e: MqttException) {
					e.printStackTrace()
			}
}
```

### MQTTブローカーからの切断

```kotlin
fun disconnect() {
        try {
            mqttClient.disconnect(null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken?) {
                    Log.d(TAG, "Disconnected")
                }

                override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                    Log.d(TAG, "Failed to disconnect")
                }
            })
        } catch (e: MqttException) {
            e.printStackTrace()
        }
    }
```

## テスト

まず、AndroidクライアントをMQTTブローカーに接続し、トピック`a/b`をサブスクライブします。すると、接続とサブスクライブが成功したログが確認できます。

![MQTTの接続とサブスクライブ](https://assets.emqx.com/images/7711763b664ee9c6f0860b50bb0934c4.png?imageMogr2/thumbnail/1520x)

[MQTT 5.0クライアントツール - MQTTX](https://mqttx.app/)を使用して、トピック`a/b`にメッセージをパブリッシュすると、クライアント側にメッセージ受信のログが表示されます。

![MQTT 5.0 クライアントツール MQTTX](https://assets.emqx.com/images/041917427b461f7d633faf3ff205b69d.png?imageMogr2/thumbnail/1520x)

![MQTTメッセージの受信](https://assets.emqx.com/images/8451743b47f3e31fbb87377dcc0111d5.png?imageMogr2/thumbnail/1520x)

クライアントからトピック`a/b`にメッセージをパブリッシュします。このトピックをサブスクライブしているため、メッセージは送信と同時に受信されます。 最後に、クライアントをMQTTブローカーから切断します。ログは以下のとおりです。

![MQTTメッセージのパブリッシュと切断](https://assets.emqx.com/images/150e861f4c2375ab938adf4dd01e7ab6.png?imageMogr2/thumbnail/1520x)

## まとめ

これまで、Android上での[MQTTクライアント](https://www.emqx.com/en/mqtt-client-sdk)の構築と、クライアントとMQTTブローカーの接続、トピックのサブスクライブ、メッセージングなどの実装を行ってきました。

MQTTは、限られた帯域幅でリモートデバイスをリアルタイムかつ信頼性高くメッセージングできるようにします。 コストが低く、帯域幅の使用量も少ないため、IoT、小型機器、モバイルアプリケーションなどで幅広く利用されています。

次は、EMQXが提供する[MQTTプロトコルのわかりやすいガイド](https://www.emqx.com/en/mqtt-guide)シリーズの記事をチェックして、MQTTプロトコルの機能を学習し、MQTTのより高度なアプリケーションを探求して、MQTTアプリケーションとサービスの開発を開始してください。

</document>

この文書の内容を日本語に翻訳することで、原文の正確性を保ちながら、MQTTの概要とAndroidでの実装方法が分かりやすく翻訳されていると思います。技術文書の翻訳では、原文の技術用語や内容構成をできるだけ保持しつつ、平易な日本語表現を用いることが重要です。今回の翻訳は MQTTの基本的な概念とAndroidでの実践方法が適切に伝わる内容になっていると考えます。