IoT用通信で利用されるMQTTですが、 iOS で適用する案件があり対応したので要点の覚え書きです。MQTT Broker が何なのかは知らされておりませんが、汎用的なものだと思います。
1.使用できるライブラリ
AWSでは各プロットフォーム毎にライブラリが提供されていました。汎用タイプのMQTTとなると使えるのは以下の2とおりでした。Get/Post methodのように、各プラットフォームで公式APIは未だ無いみたいです。いづれもOpenソースなので信頼性は要注意です。
ライブラリ | プラットフォーム | 公開URL | MQTTバージョン | 備考 |
MQTTnet | Xamarin / Visual Studio | https://github.com/dotnet/MQTTnet | 3.1.0、3.1.1、5.0指定可。 | .NetSockectがコアのためiOSでも動作する。 |
Xamarin.MQTT | Xamarin / Visual Studio | https://github.com/xamarin/mqtt | 指定不可。 | 開発止まっている。MQTTnetを簡易callしたもので利用価値低い。 |
CocoaMQTT | Swift / Xcode | https://github.com/emqx/CocoaMQTT | 3.1.1、5.0指定可。 | |
iOS, macOS, tvOS native ObjectiveC MQTT Client Framework | Swift / Xcode | https://github.com/novastone-media/MQTT-Client-Framework | 最終更新日が4年前 |
上記から現用と思われる2つを確認してみました。
2.Xamarin / MAUI の場合
最新 4.3.4.1xxx はConnectで落ちました。ここ一か月間で頻繁にコード更新がかかっています。怪しい。一つ前のリビジョンで一年前くらい 4.2.0.706 をchoiceし通過しました。.net 的なネーミングですが、Microsoftが管理しているわけでもなんでもないようです。
NuGetで「最新安定版」と記載されていても、だれも安定しているか確認していないのかもしれません。
尚、各クラスとmethod/propertyの使い方説明はなく、サンプルコード を見て理解してといった感じです。
3.SwiftUI on Xcode の場合
iPadOS16互換で、Xode 14.2互換でXcode 15.1です。こちらも最新は落ちました。Gitでバージョン切替えながら試すと、2.1.7 で落ち着きました。
BSD Socket は、CocoaAsyncSocket と MqttCocoaAsyncSocket の2つがあり指定できるのですが、後者でないと動きませんでした。下位ライブラリは、MqttCocoaAsyncSocket 1.0.8、Starscrem 4.0.4 でした。
こちらも各クラスとmethod/propertyの使い方説明はなく、Example をみる感じです。今回は他ライブラリが Swift でないとダメでしたので、CocoaMQTT を適用しました。MQTTnet より以下の機能メリットがみられました。
- サーバ自動接続モードあり。再接続インターバルの指定などもできる。ただ永遠ではない。
- デバッグモードあり。有効にすると Xcode コンソール に、JSON送信データなどがプリントされる。
- MQTTnet では未トライですが、SSLモードもすんなりOK。
すこしコードを紹介すると、
myMqtt = CocoaMQTT( clientID: クライアントID, host: ホスト名, port:ポート番号 )
if myMqtt == nil {
print( msg: "CocoaMQTT start error." )
return false
}
myMqtt!.logLevel = CocoaMQTTLoggerLevel.off // ConsoleへのTrace内容が変わる。
myMqtt.username = ユーザ名
myMqtt.password = ""
myMqtt.keepAlive = 30 // StartDelay、単位sec、Default=60
myMqtt.autoReconnect = true // 自動再接続する。
// 再接続間隔 autoReconnectTimeInterval は Default=30sec。
myMqtt.enableSSL = true // SSL、ローカルでは証明書を使用する場合
if myMqtt!.connect(timeout: 30000 /*単位msec*/ ) == false {
print( "CocoaMQTT connect error." )
return false
}
ただし接続できたかは、ステータスを監視する必要があります。送信時は、
if myMqtt.connState.description == "connected" { // 接続中
let ret = myMqtt.publish( トピック, withString: メッセージ,
qos: .qos1 /*at lastest once*/ )
if ret <= 0 { // Memo: 正常時はpublish実施回数が返る。
print( "CocoaMQTT publish error." )
return false // passed
}
}
4.課題
iOSからMQTTを使用した結果、以下の課題がありそうです。
- 端末起動直後、インターネットネットにつながっていない期間があるため、MQTT接続のリトライが必要です。 ラズパイ等の場合、shで自由にUNIXコマンドで監視管理できますが、iOS下では自由度がありません。iOSのインターネット接続状態の取得API NWPathMonitor も確実性がないようてす。
またMQTT全般的にいえることですが、
- サーバに Publish が未到達でも端末側では分からない。そもそも MQTT は高信頼性を目指したものではないのですが、実際に発生するとエンドユーザは怒ります。信頼性仕様の協議と取交わしが必要でしょう。再送やユーザに通知したい場合、サーバ側のカレントデータを読みだしてベリファイするインターフェイスを追加するとが必要だと思います(サーバ側の協力があれば)。もしくは最初からHTTPや独自protocolにしとく。
また標準ポート番号 SSL無し:1883、SSL有り:8883 は特に問題なく使えました。Appleゆえポートを開ける設定が必要かと思案していましたがそんなことはありませんでした。