まずPodfileです。
platform :ios, '11.0'
target 'YourProject' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for YourProject
pod 'Moscapsule', :git => 'https://github.com/flightonary/Moscapsule.git', :branch => 'swift4'
pod 'OpenSSL-Universal'
end
次に実装を示します。
import Moscapsule した上で、以下のようにFirstViewController等に記述して下さい。
{
...
private var _timer: Timer?
private var mqttConfig: MQTTConfig!
private var mqttClient: MQTTClient!
// MARK: - オーバーライド
override func viewDidLoad() {
super.viewDidLoad()
//MQTTコールバック登録
moscapsule_init()
mqttConfig = MQTTConfig(clientId: NSUUID().uuidString, host: "ホスト名", port: ポート番号, keepAlive: 60)
mqttConfig.mqttAuthOpts = MQTTAuthOpts(username: "", password: "")
mqttConfig.cleanSession = true
if let path = Bundle.main.path(forResource: "ファイル名", ofType: "crt") {
mqttConfig.mqttServerCert = MQTTServerCert(cafile: path, capath: nil)
}
mqttConfig.onMessageCallback = { mqttMessage in
if mqttMessage.topic == "トピック" {
if let msg = mqttMessage.payloadString {
DispatchQueue.main.async { self.onMQTT(msg: msg) }
}
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//MQTT接続、一定時間毎にsubscribe発行したいため、タイマーを用いる
wakeupTimer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
mqttClient.unsubscribe("トピック", requestCompletion: nil)
sleepTimer()
}
// MARK: - MQTT発行、受信
func wakeupTimer() {
mqttClient = MQTT.newConnection(mqttConfig)
_timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(onTimer), userInfo: nil, repeats: true)
_timer?.fire()
}
func sleepTimer() {
mqttClient.disconnect()
_timer?.invalidate()
}
@objc func onTimer() {
if mqttClient.isConnected {
mqttClient.subscribe("トピック", qos: 0)
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
self._timer?.fire()
})
print("1秒タイマー動作")
}
}
func onMQTT(msg m: String) {
mqttClient.unsubscribe("トピック", requestCompletion: nil)
let ary: [String] = m.components(separatedBy: "}")
for item in ary {
let data: [String] = item.components(separatedBy: ",")
if (data.count > 個数) {
お好きなように!
}
}
}
}
1. 概要
すでにサーバーでbroker(mosquitto)が動作していることが前提となります。
通信が途切れた場合は、1秒後に再接続を試みます。
2. セキュリティ
平文を避けるため、brokerではTLSを動作させるものとします。
たぶんmosquittoの仕様だと思うのですが、TLSでアクセスするには、サーバー証明書が要るようです。moscapsuleを使った本実装例は、コマンドラインからの
mosquitto_sub -h ホスト -p ポート -t トピック --cafile ファイル
の実行と、等価なはずです。
3. さらなるセキュリティ
やってないですが、mqttClientCertで、クライアント証明書を指定すればいいようです。mosquitto_subのオプション--certと--keyを使うことと、等価なはずです。
4. 受信文字列
文字列はカンマ区切りの羅列を想定しています。JSONを使うのが一般的なようですが、オレオレサーバー<=>アプリ間なら、単なるカンマ区切りがおすすめです。
5. タイマー
別にタイマーである必要はないのですが、iOSアプリでMQTTを受信して何かさせたいとなると、こうする以外ないような気がします。アプリがバックグラウンドに隠れたり、アプリ内でタブを切り替えたりすることに備えて、AppDelegateに以下の実装も加えて下さい。
func applicationDidEnterBackground(_ application: UIApplication) {
デリゲート.sleepTimer()
}
func applicationWillEnterForeground(_ application: UIApplication) {
デリゲート.wakeupTimer()
}
6. 謝辞
@fuku2014さんの記事を参考にさせていただきました。https://qiita.com/fuku2014/items/2b8f76c6e60bc9ff14db
なお、brokerの立て方、証明書の作り方等は、以下に詳しいです。
https://ficus-forum.myvnc.com/t/mosquitto-tls-ssl/154
https://qiita.com/udai1532/items/c0f58e73f76900a8469f
久々にpod installしたら、Moscapsuleのところでエラーが出ました。
返信削除とりあえずswift4のbranchを指定すること(赤字)で、回避できました。
iOS Simulator向けにビルドできないという致命的な問題が発生しました。
返信削除OpenSSL-Universalの中にあるライブラリがx86_64であることが原因のようです。
とりあえずXcodeをRossetaモードで動かし、一度ビルドするとpod類のリンクに成功し、回避できましたが、恒久対応とは言えませんね…