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にしとく。