Android
Node.js
mqtt
sango

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


以上、ご参考までに