CocoaMQTT v2.0: iOSで最初のMQTT 5.0クライアント

![CocoaMQTT v2.0: 最初のiOS MQTT 5.0クライアント](https://assets.emqx.com/images/7af9820fbbb364bca0d1dc46830371d5.png?imageMogr2/thumbnail/1520x684)

2017年8月、MQTT 5.0のドラフトがOASIS MQTT技術委員会によって公開レビューのために公式にリリースされました。2018年に、MQTT 5.0の公式バージョンがリリースされました。しかし、Appleのエコシステムにおいて、[MQTT 5.0](https://www.emqx.com/ja/blog/introduction-to-mqtt-5) を完全にサポートするクライアントSDKはまだありません。

[CocoaMQTT](https://github.com/emqx/CocoaMQTT)は、現在iOS開発者に広く使用されているEMQがiOS開発者のために提供するMQTTクライアントSDKです。AppleのエコシステムにおけるMQTT 5.0サポートのギャップを埋めるために、**EMQチームは最近新しいCocoaMQTT v2.0を公式にリリースしました。** CocoaMQTT v2.0はMQTT 5.0をサポートしており、バージョン3.1.1と互換性があり、iOS、tvOS、OSXオペレーティングシステムをサポートしています。ユーザーは今、CocoaMQTTを通じてiOSシステムデバイスをMQTT 5.0クラウドサービスに接続し、MQTT5.0が提供する強力な機能を楽しむことができます。

CocoaMQTTは、Objective-CではなくSwift言語で開発されています。これは、Swiftが型安全な言語で、プロトコルのサポートが豊富だからです。拡張機能、汎用機能、アソシエーション型と組み合わせたプロトコル指向プログラミングにより、コードの柔軟性が大幅に向上します。

さらに、WWDC 2021カンファレンスで、AppleはSwift言語の並列モデルの大幅な更新を発表しました: コンパイラによって実装されたアクター並列モデルと、新しいアクター参照型は、開発者がデータ競合の問題を回避するのに役立ちます。 したがって、私たちはまた、MQTT関連のI/O集中型並列アプリケーションにおいて、SwiftのパフォーマンスがObjective-Cよりも期待できると信じています。

## MQTT 5.0 vs MQTT 3.1.1

MQTT 3.1.1にはまだ多くの不備があります。 たとえば、接続が異常に切断された場合、相手側は理由を通知できません。 MQTT 5.0では、MQTT 3.1.1をベースに多くの変更が加えられていますが、下位互換性はありません。 MQTT 5.0は、セッション/メッセージ遅延、理由コード、トピックエイリアス、飛行中ストリーム制御、[ユーザープロパティ](https://www.emqx.com/ja/blog/mqtt5-user-properties)、[共有サブスクリプション](https://www.emqx.com/ja/blog/introduction-to-mqtt5-protocol-shared-subscription)などの新機能を追加するとともに、認証セキュリティを強化するためのAUTHパケットを追加しています。 理由コードとユーザープロパティフィールドにより、MQTT 5.0は、バージョン3.1.1では不完全なプロトコルのために対処が難しい問題に、より多くのコンテキスト情報を運ぶことができます。

MQTT 5.0の主な機能上の利点は以下のとおりです。

- より大規模な拡張可能なシステムのさらなるサポート
- より詳細なエラー報告と処理メカニズム
- 容量探索および要求-応答などの一般モードの標準化された操作
- 拡張可能なユーザープロパティ
- パフォーマンスの改善と小さいクライアントのサポート
- セッションの保持とメッセージのタイムアウト設定
- 要求/応答メッセージモードの新しいサポート

## iOSクライアントでのMQTTの使い方 - CocoaMQTT

この記事では、EMQが提供する[Free Public MQTT Broker](https://www.emqx.com/ja/mqtt/public-mqtt5-broker)を使用して、CocoaMQTTの機能を紹介します。このサービスは、[MQTTクラウドサービス - EMQX Cloud](https://www.emqx.com/ja/cloud)に基づいて作成されています。

ブローカーへのアクセス情報は以下のとおりです。

- ブローカー: **broker.emqx.io**  
- TCPポート: **1883**
- Websocketポート: **8083**
- TCP/TLSポート: **8883**  
- Websocket/TLSポート:**8084**

### MQTTサービスへの接続

MQTT 5.0では多くのプロパティが追加されたことがわかります。その中で、`Property` フィールドを使用することで、ユーザーは自身の状況に応じてより詳細な要件を満たすことができます。

```swift
///MQTT 5.0
let clientID = "CocoaMQTT-" + String(ProcessInfo().processIdentifier)
let mqtt5 = CocoaMQTT5(clientID: clientID, host: "broker.emqx.io", port: 1883)

let connectProperties = MqttConnectProperties()
connectProperties.topicAliasMaximum = 0
connectProperties.sessionExpiryInterval = 0
connectProperties.receiveMaximum = 100
connectProperties.maximumPacketSize = 500
mqtt5.connectProperties = connectProperties

mqtt5.username = "test"
mqtt5.password = "public"
mqtt5.willMessage = CocoaMQTTWill(topic: "/will", message: "dieout")
mqtt5.keepAlive = 60
mqtt5.delegate = self
mqtt5.connect()

///MQTT 3.1.1
let clientID = "CocoaMQTT-" + String(ProcessInfo().processIdentifier)
let mqtt = CocoaMQTT(clientID: clientID, host: "broker.emqx.io", port: 1883)
mqtt.username = "test"
mqtt.password = "public"
mqtt.willMessage = CocoaMQTTWill(topic: "/will", message: "dieout") 
mqtt.keepAlive = 60
mqtt.delegate = self
mqtt.connect()
```

 ### サブスクライブ

MQTT 5.0には、MQTT 3.1.1よりも[サブスクリプションオプション](https://www.emqx.com/ja/blog/subscription-identifier-and-subscription-options)などの操作が多くあります。

```swift
///MQTT 5.0
mqtt5.subscribe("chat/room/animals/client/+", qos: CocoaMQTTQoS.qos1)
//または
//let subscriptions : [MqttSubscription] = [MqttSubscription(topic: "chat/room/animals/client/+"),MqttSubscription(topic: "chat/room/foods/client/+"),MqttSubscription(topic: "chat/room/trees/client/+")]
//mqtt.subscribe(subscriptions)

///MQTT 3.1.1
mqtt.subscribe("chat/room/animals/client/+", qos: CocoaMQTTQoS.qos1)  
//または
//let subscriptions : [(String, CocoaMQTTQoS)] = [("chat/room/animals/client/+", qos: CocoaMQTTQoS.qos1),("chat/room/foods/client/+", qos: CocoaMQTTQoS.qos1),("chat/room/trees/client/+", qos: CocoaMQTTQoS.qos1)]
//mqtt.subscribe(subscriptions)
```

### パブリッシュ

```swift
///MQTT 5.0
mqtt5!.publish("chat/room/animals/client/" + animal!, withString: message!, qos: .qos1, DUP: false, retained: false, properties: publishProperties)

///MQTT 3.1.1  
mqtt!.publish("chat/room/animals/client/" + animal!, withString: message!, qos: .qos1)
```

### 自動再接続

MQTTはTCP長接続に基づくプロトコルです。実際のシナリオでは、ネットワーク障害や信号の問題による接続の中断は一般的な問題です。多くの開発者は、SDKが自動的に再接続する便利な方法を提供してほしいと考えています。

```swift
///MQTT 5.0
mqtt5!.autoReconnect = true  

///MQTT 3.1.1
mqtt!.autoReconnect = true
```

### 単方向および双方向SSL

```swift
///MQTT 5.0
mqtt5!.enableSSL = true

///MQTT 3.1.1
mqtt!.enableSSL = true

let clientCertArray = getClientCertFromP12File(certName: "client-keycert", certPassword: "MySecretPassword")
var sslSettings: [String: NSObject] = [:]
sslSettings[kCFStreamSSLCertificates as String] = clientCertArray

///MQTT 5.0
mqtt5!.sslSettings = sslSettings

///MQTT 3.1.1
mqtt!.sslSettings = sslSettings
```

`.p12`ファイルが必要な場合は、ターミナルで次のステートメントを使用して生成できます。

```bash
openssl pkcs12 -export -clcerts -in client-cert.pem -inkey client-key.pem -out client.p12
```

### Retained MessageとWill Messageの設定

MQTT 3.1.1と比較して、MQTT 5.0にはユーザーが使用できるプロパティ設定がより多くあります。

```swift
///MQTT 5.0
let lastWillMessage = CocoaMQTTMessage(topic: "/chat/room/animals/client/Sheep", string: "dieout")
lastWillMessage.retained = true  
lastWillMessage.qos = .qos1
mqtt5!.willMessage = lastWillMessage

///MQTT 3.1.1
mqtt!.willMessage = CocoaMQTTMessage(topic: "/will", string: "dieout")
```

### AUTHパケット

MQTTは、`CONNECT`だけで認証を実行するのに十分な情報をサーバーに提供していない場合があります。このため、MQTT 5.0では、クライアントとサーバー間の認証を強化するためにこの機能が追加されています。

```swift
let authProperties = MqttAuthProperties()
        mqtt5!.auth(reasonCode: CocoaMQTTAUTHReasonCode.continueAuthentication, authProperties: authProperties)
```

### バックグラウンドで実行されるiOSアプリケーション

「Background fetch」モードまたはiOS 13で新しく追加された「Background processing」モードを使用することをお勧めします。

![バックグラウンドで実行されるiOSアプリケーション](https://assets.emqx.com/images/7d487fe5022b5c2785c4df43adf9f983.png?imageMogr2/thumbnail/1520x)

`beginBackgroundTaskWithName` と `endBackgroundTask` に関連するAPIを使用する場合、アプリを30秒間バックグラウンドで実行し続けることができます。

## まとめ

これまで、CocoaMQTTクライアントをパブリックMQTTブローカーに接続し、クライアントと[MQTTブローカー](https://www.emqx.io/)間の接続、メッセージ送信、サブスクリプションを実現してきました。

> コードは https://github.com/emqx/CocoaMQTT/tree/master/Example から入手できます。

EMQは、ユーザーがIoTビジネスを行うためにMQTTを簡単かつ便利に使用できるよう支えています。一連のクライアントSDKは継続的に開発されており、引き続きご期待ください。