Help us understand the problem. What is going on with this article?

MQTT クライアント を Android に実装する

More than 3 years have passed since last update.

背景

IoTと言う言葉が流行るにつれて、MQTTという言葉も注目されている。

来月、おきなわマラソンで、お友達との距離をリアルタイムに把握するシステムを開発しようと思っています。

双方向の通信と言えば、WebSocketでやればいいじゃんという話もありますが、MQTTの特徴であるRetain機能を使えば、アプリ起動時に、お友達の最新の位置情報をすぐ取得できるのではないか?ということで、Android端末でMQTTのクライアント実装を行ってみました。

一応、覚え書きです。

環境

MQTTのサーバとして、時雨堂さんが提供しているsangoのライトプラン
開発環境は、Android Studio 1.5.1 (OSX版)

Android端末は
Google Nexus 5X (Android 6.0.1)
Sony Xperia Z3 (Android 5.0.2)

必要なライブラリ

Android MQTTで検索してみたところ、Paho Android Service が良さそうだったので、これを利用しました。

私は、下記のバイナリファイル

org.eclipse.paho.client.mqttv3-1.0.2.jar
org.eclipse.paho.android.service-1.0.2.jar

をapp/libs フォルダに放りこみました。

このまま、コンパイルすると、リンク時にエラーが発生するので、

build.gradle
android {

... 省略

    packagingOptions {
        exclude 'META-INF/ECLIPSE_.SF'
        exclude 'META-INF/ECLIPSE_.RSA'
    }
}

を追記することで、apkファイルがビルド出来ました。

160119-0001.png

Android Manifestの設定

パーミションとサービスの追記が必要になります

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

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

... 省略 

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

コード例 (subscribe)

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private final String TAG = "Debug";
    private MqttAndroidClient mqttAndroidClient;

    private String ID = "hoge@github";
    private String PASS = "sango";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mqttAndroidClient = new MqttAndroidClient(this, "tcp://lite.mqtt.shiguredo.jp:1883", "d:lite:test:") {
            @Override
            public void onReceive(Context context, Intent intent) {
                super.onReceive(context, intent);

                Bundle data = intent.getExtras();

                String action = data.getString("MqttService.callbackAction");
                Object parcel = data.get("MqttService.PARCEL");
                String destinationName = data.getString("MqttService.destinationName");

                if(action.equals("messageArrived"))
                {
                    Log.d(TAG,destinationName + " " + parcel.toString());
                }

            }
        };

        try {
            MqttConnectOptions options = new MqttConnectOptions();
            options.setUserName(ID);
            options.setPassword(PASS.toCharArray());

            mqttAndroidClient.connect(options, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken iMqttToken) {
                    Log.d(TAG, "onSuccess");

                    try {
                        mqttAndroidClient.subscribe("hoge@github/#", 0);
                        Log.d(TAG, "subscribe");
                    } catch (MqttException e) {
                        Log.d(TAG, e.toString());
                    }
                }

                @Override
                public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
                    Log.d(TAG, "onFailure");
                }
            });

        } catch (MqttException e) {
            Log.d(TAG, e.toString());
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        try {

            if(mqttAndroidClient.isConnected()) {
                mqttAndroidClient.disconnect();
                Log.d(TAG,"disconnect");
            }

            mqttAndroidClient.unregisterResources();

        } catch (MqttException e) {
            Log.d(TAG,e.toString());
        }

    }
}

コード例 (publish)

MainActivity.java
    btn01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if(mqttAndroidClient == null)
                    return;

                try {
                    if(mqttAndroidClient.isConnected()) {
                        IMqttDeliveryToken token = mqttAndroidClient.publish("hoge@github/test", "hello world".getBytes(), 0, true);
                    }
                } catch (MqttPersistenceException e) {
                    Log.d(TAG,e.toString());
                } catch (MqttException e) {
                    Log.d(TAG,e.toString());
                }
            }
        });

動作検証用 (node.jsコード)

これは必要か?わかりませんが、開発中にちょっとしたnode.js向けのコードも書いたので、これも参考までに

共通設定ファイル

config.json
{
  "host": "lite.mqtt.shiguredo.jp",
  "port": 1883,
  "options": {
    "username": "hoge@github",
    "password": "sango",
    "keepalive": 10000
  },
  "topic": "hoge@github"
}

subscribe用

sub.js
var mqtt = require("mqtt"),
    config = require("./config.json"),
    client = mqtt.createClient(config.port, config.host, config.options);

client.subscribe(config.topic + "/#");

client.on("message", function(topic, message) {
  console.log(topic, message.toString());
});

publish用

pub.js
var mqtt = require("mqtt"),
    config = require("./config.json"),
    client = mqtt.createClient(config.port, config.host, config.options);

setInterval(function() {
    client.publish(config.topic + "/test", "abc");
    }, 30000);

以上、ご参考までに

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away