LoginSignup
32
35

More than 5 years have passed since last update.

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

Posted at

背景

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);

以上、ご参考までに

32
35
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
32
35