AndroidでMQTT通信を実装する方法:接続手順とメッセージ送受信の基本

Published on: | Last updated:

最近、スマホアプリでMQTT使うことについて考えてる。IoTのイメージが強いけど、Androidアプリで直接使うのはどうなんだろう。軽量って聞くし。ちょっと整理してみるか。

MQTTとHTTP、ぶっちゃけ何が違うの?

まずこれだよね。だいたい比較されるのがHTTP。古き良き、っていうか、まあ今でも主役だけど。なんでMQTTを選ぶのか。正直、僕も最初は「別にHTTPで良くない?」って思ってた。

ざっくり言うと、MQTTは「軽くて、双方向で、状態を維持しやすい」プロトコル。HTTPは「リクエストして、レスポンスもらって、終わり」っていう一回一回のやりとり。この違いが結構大きい。

Publish/Subscribeモデルの概念図
Publish/Subscribeモデルの概念図

簡単な比較表を作ってみた。こんな感じの理解でいいと思う。

項目 MQTT HTTP
通信モデル Publish/Subscribe(Pub/Sub)。仲介役(Broker)がいる。多対多の通信が得意。 Client/Server。一対一のリクエスト/レスポンスが基本。
コネクション 貼りっぱなし。状態を保持するから、再接続のコストが低い。 基本的には一回ごと。Keep-Aliveもあるけど、思想が違う感じ。
ヘッダーサイズ めっちゃ小さい。最小2バイト。だから軽い。 比較的大きい。いろんな情報が入ってるから。
Push通知 得意。BrokerからSubscriberに送るのが基本動作だから。苦手。ロングポーリングとかWebSocketとか、別の工夫が必要になる。
向いてる用途センサーデータ、チャットアプリ、位置情報のリアルタイム共有とか。Webページの取得、APIの呼び出し。一般的なWebサービス全般。

要するに、常に接続していて、サーバー側から何かをきっかけにデータを送りたい(Pushしたい)なら、MQTTはかなり有力。逆に、ユーザーがボタンを押したときだけデータを取ってくる、みたいなアプリなら、HTTPで十分。…いや、HTTPのほうがシンプルでいいかも。

MQTTの基本的な考え方

Pub/Subモデルっていうのが核心。新聞の例えがよく使われるけど、今はYouTubeチャンネルの方が分かりやすいかな。

配信者(Publisher)は動画をYouTube(Broker)にアップするだけ。誰がチャンネル登録(Subscribe)してるかなんて気にしない。視聴者(Subscriber)はチャンネル登録しておけば、新しい動画がアップされたら通知が来る。配信者と視聴者は直接やりとりしない。全部YouTubeが仲介してる。MQTTもこれと全く同じ。

クライアントとサーバーっていう関係もある。この場合のサーバーはBrokerのこと。クライアントはBrokerに接続して、PublisherにもSubscriberにもなれる。どっちか片方だけでもいい。

実際に通信してみる:接続の流れ

じゃあ、どうやって通信を始めるか。クライアントがBrokerに「CONNECT」メッセージを送ることから始まる。自己紹介みたいなもんだね。ここにいくつか重要な情報が入ってる。

  • ClientID: クライアント固有のID。Brokerはこれでクライアントを識別する。空にすると匿名接続になるけど、まあ、普通はちゃんと付ける。
  • CleanSession: これが結構大事。trueだと、接続時に過去のセッション情報を全部消す。falseだと、前回の続きから再開しようとする。オフライン中に溜まってたメッセージを受け取りたい、とかそういう時にfalseにする。
  • KeepAlive: 接続を生きてることにするための間隔(秒)。この時間内に何も通信がないと、クライアントはPINGを送って「生きてますよ」ってアピールする必要がある。これをやらないとBrokerに切られる。
  • WillMessage(遺言): 面白いのがこれ。クライアントが不意に切断されたとき、Brokerが代わりに特定のメッセージをPublishしてくれる機能。「〇〇が退出しました」みたいなのを想像すると分かりやすい。

この辺の設定をBrokerに送って、OKが返ってきたら通信開始。

トピックの決め方、結構大事

Pub/Subの「カテゴリー」にあたるのがトピック。ただの文字列なんだけど、スラッシュ(/)で階層構造にできる。これがすごく便利。

例えば、スマートホームで家のセンサーデータを扱うなら、こんな感じ。

myhome/living/temperature
myhome/living/humidity
myhome/bedroom/light

こうしておくと、後でデータを購読(Subscribe)するときに「myhome/living/#」って指定すればリビングの全センサーデータをまとめて取れたり、「myhome/+/temperature」で家中の温度計のデータだけ取れたりする。この「#」とか「+」はワイルドカード。設計が超重要になる部分。

トピックは事前に作る必要はなくて、クライアントが使った時点でBrokerが勝手に認識してくれる。手軽でいいよね。

AndroidでのMQTTクライアントアプリの例
AndroidでのMQTTクライアントアプリの例

QoSって、結局どれ選べばいいの?

Quality of Service。メッセージの品質保証レベル。3段階ある。

  • 0 - At most once: 「多くても1回」。投げっぱなし。届けばラッキー。メッセージが消えてもいい、頻繁に送るセンサーデータとかで使う。一番速い。
  • 1 - At least once: 「少なくとも1回」。届いたことは保証する。けど、通信障害とかタイミングによっては同じメッセージが2回届く可能性はある。チャットのメッセージとか、消えたら困るけど重複は許せる場合に。一番よく使われるやつ。迷ったらこれ。
  • 2 - Exactly once: 「正確に1回」。絶対に1回だけ届くのを保証する。一番信頼性高いけど、その分やりとりが複雑で遅くなる。お金が絡む処理とか、超重要な制御命令とか。正直、これを必要とする場面は稀。

当然だけど、QoSレベルを上げると信頼性は上がるけど、パフォーマンスは落ちる。何でもかんでも「2」にすればいいって話じゃない。

QoSレベルによる速度と信頼性のトレードオフ
QoSレベルによる速度と信頼性のトレードオフ

AndroidでMQTTを触ってみる

さて、本題のAndroidでの実装。MQTTはTCP/IP上で動くから、ネットにさえ繋がればAndroidでも普通に使える。

ライブラリはいくつかあるけど、まあ、Eclipse Paho が一番情報多いし、無難かな。Javaで書かれてるけど、Kotlinからでも普通に使える。HiveMQもいいクライアントライブラリを出してるけど、歴史と実績でPahoを選ぶ人が多い印象。

海外のドキュメント、例えばEclipse Pahoの公式ガイドは理想的な使い方しか書いてないことが多い。でも、日本の技術ブログ、例えばQiitaとかで検索すると、Android特有の「ハマりどころ」がたくさん出てくる。特に、バックグラウンドでの接続維持とか、スレッド周りの問題とか。この辺は、公式ドキュメントより、むしろ日本の先人たちの知恵を借りたほうが早いかもしれない。

実装の流れはだいたいこんな感じ。

  1. Brokerを決める: まずは接続先のMQTT Brokerが必要。テスト用なら公開されてるものがいくつかある。HiveMQが提供してるパブリックBrokerとかが有名。
  2. クライアントのインスタンス化: Pahoライブラリを使って、MqttAndroidClientのインスタンスを作る。BrokerのURI(tcp://broker.hivemq.com:1883 みたいな)を指定する。
  3. 接続: connect()メソッドを呼ぶ。ここで、さっき話したCleanSessionとかを設定できる。非同期処理だから、コールバックで成功・失敗を受け取る。
  4. Publish/Subscribe: 接続できたら、publish()でメッセージを送信したり、subscribe()でトピックを購読したり。これも全部非同期。
  5. 切断: 使い終わったらdisconnect()。

コードそのものは、ライブラリのおかげで数行で書ける。重要なのは、何をしているか理解すること。特にコールバック地獄になりがちなので、KotlinならコルーチンとかRxJavaでうまくラップすると綺麗に書けるかも。

よくある失敗と勘違い

MQTTをAndroidで使うときに、僕がハマったこととか、よく聞く話。

  • AndroidManifestにパーミッション書き忘れ: 基本中の基本だけど、`` を忘れて「動かない…」ってなる。あるある。
  • メインスレッドでネットワーク処理: connect()とかpublish()とか、ネットワーク通信は全部別スreadでやらないと`NetworkOnMainThreadException`でクラッシュする。ライブラリがコールバック形式になってるのはそのため。
  • Brokerに繋がらない: URI、ポート番号の間違いとか。会社のWi-Fiだとファイアウォールで塞がれてることもある。まずはスマホの4G/5G回線で試してみるとか、原因の切り分けが大事。
  • CleanSession=falseの挙動: 再接続時に意図しないメッセージが大量に流れてきたりする。Brokerが何をどこまで覚えているか、ちゃんと仕様を理解しないと混乱する。ClientIDを固定しないと意味がないし。

…まあ、こんなところかな。軽い気持ちで触ると、案外落とし穴はある。

まとめというか、所感

結局、MQTTは銀の弾丸じゃない。HTTPと比べて軽いし、Push通知も得意だから、リアルタイム성이求められるチャットアプリや、位置情報共有アプリ、多数のデバイスからのデータを捌くIoTゲートウェイみたいなアプリには、すごく向いてると思う。

でも、ただサーバーからデータを取ってくるだけの、よくある情報取得系のアプリなら、わざわざMQTTを導入するメリットは薄いかな。既存のHTTPライブラリ(Retrofitとか)の方がエコシステムも大きいし、楽。適材適所、ってことだね。

あなたのアプリなら、MQTTとHTTPどっち使いますか? もしよかったら、どんなアプリで、どっちを選んだか(あるいは選ぶか)理由も教えてください。

Related to this topic:

Comments

  1. Guest 2025-10-23 Reply
    正直、今ちょっと言葉にしづらい感じなんだけど…MQTTで色々試したことはあるんだよね。でもさ、トピックの設計が想像してたよりずっと悩ましいって毎回思う。見た目はすごく単純そうなのに、いざ動かしてみると、「あれ、この区切り方であとから困らないかな?」とか、変な心配ばっかり頭に浮かぶんだよ。逆に粒度細かくしすぎて情報ごちゃごちゃになったりもするし。 そんでブローカーの接続方法も、一応ドキュメント読めば簡単じゃん?って思ってたけど実際やってみるとネットワーク環境が微妙だと全然事情違ったりして、本当に面倒くさいなーって…。こういう時こそ柔軟さ求められるけど、「これHTTPじゃまずいのかな」みたいな根本的な疑問にもつながっちゃうというか。結局、自分でもパブリッシュ・サブスクライブ方式だからできることをもう一回整理しようとして迷路にハマる。 ま、とにかく表面的になんとなく使ってOK!で済ますよりは、ひとつひとつちょっと突っ込んで考え直したほうが絶対あとから助かったなーと思うシーン多かった気がする。
  2. Guest 2025-08-03 Reply
    MQTTって、IoTデバイスでよく使われてるけど、具体的にどんな仕組みなの?通信の仕方とか、トピックの設定とかちょっと気になるんだけど…
  3. Guest 2025-07-19 Reply
    子供のIoTプロジェクトで、簡単で軽量な通信方式って聞いたんですけど、MQTTってやつ、うちの子供に教えられそうな感じですかね?詳しい資料とか、おすすめの学習リソースとかあれば…
  4. Guest 2025-06-29 Reply
    息子のプログラミング学習に、MQTTの資料があれば助かるな。うちの子、IoTに興味あるみたいで、これ知りたがってるんだよね。何か分かりやすい解説とか、参考になる本とか、あったら教えてほしいな。
  5. Guest 2025-05-21 Reply
    へえ、MQTTって結構複雑そうだけど、本当にこんなに難しいの?IoTプロジェクトでこれ使うメリットってあるの?正直よく分かんないんだけど、素人目線からするとちょっと難しすぎない?