CocoaMQTT Documentation

repository·release/2.x·Indexed 23 days ago

https://github.com/emqx/cocoamqtt

A Swift-based MQTT client library supporting MQTT v3.1.1 and v5.0 for Apple platforms, including iOS, macOS, tvOS, and visionOS. It provides support for TCP and WebSocket transports, TLS configuration (including mutual TLS), and integration via Swift Package Manager and CocoaPods.

Tokens
4.1K
Snippets
12
Records
13
Agent score
33%

What's inside CocoaMQTT

  1. Configure Mutual TLS (mTLS)

    release/2.x

    Mutual TLS allows the client to present its own certificate to the broker.

    Transport Support

    • TCP: Use CocoaMQTT or CocoaMQTT5.
    • WSS (WebSockets): CocoaMQTTWebSocket automatically uses Apple's URLSessionWebSocketTask on modern OS versions (macOS 10.15+, iOS 13+, tvOS 13+, visionOS 1+). On older versions, it falls back to Starscream, which does not support client identities.

    Configuration Methods

    You can configure client identity using either PEM/DER or PKCS#12 formats before calling connect():

    1. PEM/DER: certificateData accepts a DER certificate, a single PEM certificate, or a PEM bundle (leaf first, then intermediates). privateKeyData accepts RSA PKCS#1 (RSA PRIVATE KEY) or unencrypted RSA PKCS#8 (PRIVATE KEY).
    2. PKCS#12: A password-protected identity container supported by Apple's SecPKCS12Import.

    Security Best Practices

    • Do not ship unencrypted PEM private keys in your application bundle.
    • Do not embed PKCS#12 files with their passwords in the bundle.
    • Use secure provisioning, user input, or Keychain-backed storage for long-lived secrets.

    Key Properties

    • tlsServerName: Use this when the connection host differs from the DNS name in the broker certificate.
    • clientIdentity: Configures the client's identity (certificate and private key).
    • trustedServerCertificates and usesSystemTrustStore: Configure how the client validates the broker.
  2. Configure TLS with a Private or Self-Signed CA

    release/2.x

    To use a private CA, load your DER or PEM encoded CA certificate and assign it to trustedServerCertificates.

    If you want to trust only this CA and ignore the system trust store, set usesSystemTrustStore to false.

    For advanced pinning or enterprise policies, set manuallyEvaluateTrust = true and implement the trust delegate method or the didReceiveTrust closure. Note that enabling manual evaluation without a trust callback or custom CA certificates will cause the connection to be rejected.

    let data = try Data(contentsOf: Bundle.main.url(forResource: "broker-ca", withExtension: "crt")!)
    guard let certificate = CocoaMQTTSocket.serverCertificate(from: data) else {
        fatalError("Invalid CA certificate")
    }
    
    mqtt.trustedServerCertificates = [certificate]
    mqtt.usesSystemTrustStore = false // Trust only this CA.
    mqtt.enableSSL = true
  3. Configure TLS with a publicly trusted server certificate

    release/2.x

    To enable TLS for a broker whose certificate is rooted in the Apple system trust store, set enableSSL to true.

    If you are connecting via an IP address but the certificate is issued to a DNS name, you must set tlsServerName explicitly to match the certificate.

    mqtt.enableSSL = true
    
    // If connecting via IP, specify the expected DNS name
    mqtt.tlsServerName = "broker.example.com"
  4. Install CocoaMQTT via CocoaPods

    release/2.x

    To integrate CocoaMQTT using CocoaPods, add the following to your Podfile.

    Note for visionOS: CocoaPods installation is not currently supported for visionOS due to transitive dependency limitations. Use Swift Package Manager for visionOS applications.

    use_frameworks!
    
    target 'Example' do
        pod 'CocoaMQTT'
    end

    Then, run the installation command:

    $ pod install

    Finally, import the module in your Swift code:

    import CocoaMQTT
  5. Connect to MQTT via WebSocket

    release/2.x

    CocoaMQTT supports connecting to MQTT brokers over WebSocket. To use this feature, you must include both the CocoaMQTT and CocoaMQTTWebSocket products in your project.

    Swift Package Manager Integration

    1. In Xcode, go to File > Swift Packages > Add Package Dependency.
    2. Use the URL: https://github.com/emqx/CocoaMQTT.git.
    3. Add both CocoaMQTT and CocoaMQTTWebSocket products to your target.
    4. Import them in your code:
    import CocoaMQTT
    import CocoaMQTTWebSocket

    CocoaPods Integration

    Update your Podfile with pod 'CocoaMQTT/WebSockets' and run pod install.

    If you are building a module (e.g., for React Native) using a .podspec instead of a Podfile, add the following dependency:

    s.dependency "CocoaMQTT/WebSockets"
    import CocoaMQTT
    import CocoaMQTTWebSocket
  6. Install CocoaMQTT via Swift Package Manager

    release/2.x

    To integrate CocoaMQTT into your Xcode project using Swift Package Manager:

    1. Open your project in Xcode.
    2. Go to File > Swift Packages > Add Package Dependency.
    3. Enter the repository URL: https://github.com/emqx/CocoaMQTT.git.
    4. Choose the latest version or specify a version range.
    5. Add the package to your target.

    Swift Package Manager supports iOS, macOS, tvOS, and visionOS. Both the CocoaMQTT and CocoaMQTTWebSocket products are available. After installation, import the module:

    import CocoaMQTT
  7. Handle incoming messages using closures

    release/2.x

    Instead of implementing the CocoaMQTTDelegate protocol, you can use the didReceiveMessage closure to handle incoming messages.

    mqtt.didReceiveMessage = { mqtt, message, id in
        print("Message received in topic \(message.topic) with payload \(message.string!)")           
    }
  8. Create an MQTT instance over WebSocket

    release/2.x

    To establish a connection using WebSockets, initialize a CocoaMQTTWebSocket with the desired URI and pass it as the socket parameter to the CocoaMQTT (MQTT 3.1.1) or CocoaMQTT5 (MQTT 5.0) constructor.

    MQTT 5.0 Example

    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    let mqtt5 = CocoaMQTT5(clientID: clientID, host: host, port: 8083, socket: websocket)
    let connectProperties = MqttConnectProperties()
    connectProperties.topicAliasMaximum = 0
    mqtt5.connectProperties = connectProperties
    _ = mqtt5.connect()

    MQTT 3.1.1 Example

    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    let mqtt = CocoaMQTT(clientID: clientID, host: host, port: 8083, socket: websocket)
    _ = mqtt.connect()
    ///MQTT 5.0
    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    let mqtt5 = CocoaMQTT5(clientID: clientID, host: host, port: 8083, socket: websocket)
    let connectProperties = MqttConnectProperties()
    connectProperties.topicAliasMaximum = 0
    // ...
    mqtt5.connectProperties = connectProperties
    // ...
    
    _ = mqtt5.connect()
    
    ///MQTT 3.1.1
    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    let mqtt = CocoaMQTT(clientID: clientID, host: host, port: 8083, socket: websocket)
    
    // ...
    
    _ = mqtt.connect()
  9. Connect using MQTT 3.1.1

    release/2.x

    To use the MQTT 3.1.1 protocol, instantiate CocoaMQTT.

    ///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 = CocoaMQTTMessage(topic: "/will", string: "dieout")
    mqtt.keepAlive = 60
    mqtt.delegate = self
    mqtt.connect()
  10. Connect using MQTT 5.0

    release/2.x

    To use the MQTT 5.0 protocol, instantiate CocoaMQTT5. You can configure MqttConnectProperties to set parameters like topicAliasMaximum, sessionExpiryInterval, receiveMaximum, and maximumPacketSize.

    ///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 = CocoaMQTTMessage(topic: "/will", string: "dieout")
    mqtt5.keepAlive = 60
    mqtt5.delegate = self
    mqtt5.connect()
  11. Implement CocoaMQTTDelegate for WebSocket connections

    release/2.x

    To react to MQTT events (connection, publishing, receiving messages, etc.) when using WebSockets, implement the CocoaMQTTDelegate protocol.

    Key delegate methods include:

    • mqtt(_:didConnectAck:): Called when connection is acknowledged.
    • mqtt(_:didReceiveMessage:id:): Called when a message is received.
    • mqtt(_:didPublishMessage:id:): Called when a message is successfully published.
    • mqtt(_:didSubscribeTopics:failed:): Called after subscription attempts.
    • mqttDidDisconnect(_:): Called when the client disconnects.
    import CocoaMQTT
    import CocoaMQTTWebSocket
    
    class WebSocketManager {
        
        private var mqttClient: CocoaMQTT?
        var message: String = ""
        var token: String = ""
    
        func setupMQTTClient(with token: String) {
            let socket = CocoaMQTTWebSocket(uri: "/mqtt")
            socket.enableSSL = true
            mqttClient = CocoaMQTT(clientID: token, host: "host", port: 443, socket: socket)
            mqttClient?.delegate = self
        }
    
        func connect() {
            guard let mqttClient = mqttClient else { return }
            mqttClient.connect()
        }
        
    }
    
    extension WebSocketManager: CocoaMQTTDelegate {
    
        func mqtt(_ mqtt: CocoaMQTT, didPublishAck id: UInt16) {
            print("Published message with ID: \(id)")
        }
        
        func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopics topics: [String]) {
            print("Unsubscribed from topics: \(topics)")
        }
        
        func mqttDidPing(_ mqtt: CocoaMQTT) {
            print("MQTT did ping")
        }
        
        func mqttDidReceivePong(_ mqtt: CocoaMQTT) {
            print("MQTT did receive pong")
        }
        
        func mqtt(_ mqtt: CocoaMQTT, didDisconnectAck ack: CocoaMQTTConnAck) {
            print("Connected to MQTT broker with acknowledgment: \(ack)")
        }
    
        func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
            if let messageString = message.string {
                DispatchQueue.main.async {
                    self.message = messageString
                }
                print("Received message: \(messageString) on topic: \(message.topic)")
            }
        }
        
        func mqtt(_ mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
            print("Published message: \(message.string ?? "") with ID: \(id)")
        }
    
        func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
            print("Subscribed to topics: \(success), failed to subscribe to: \(failed)")
        }
    
        func mqtt(_ mqtt: CocoaMQTT, didDisconnectWithError err: Error?) {
            print("Disconnected from MQTT broker with error: \(String(describing: err))")
        }
        
    }
  12. Configure WebSocket message size and headers

    release/2.x

    When using the built-in Apple URLSessionWebSocketTask transport, there is a 1 MiB buffering limit. To handle larger messages, set maximumMessageSize on the CocoaMQTTWebSocket instance. Setting it to 0 removes the limit entirely (use with caution as it allows unbounded buffering).

    You can also provide custom HTTP headers for the WebSocket connection.

    Configuration Example

    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    // Set limit to 10 MiB
    websocket.maximumMessageSize = 10 * 1024 * 1024 + 1 
    
    // Add custom headers
    websocket.headers = [
        "x-api-key": "value"
    ]
    
    // Enable SSL (WSS)
    websocket.enableSSL = true
    
    let mqtt = CocoaMQTT(clientID: clientID, host: host, port: 8083, socket: websocket)
    _ = mqtt.connect()
    let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
    websocket.maximumMessageSize = 10 * 1024 * 1024 + 1 // Accept up to 10 MiB.
    
    websocket.headers = [
                "x-api-key": "value"
            ]
            websocket.enableSSL = true
    
    let mqtt = CocoaMQTT(clientID: clientID, host: host, port: 8083, socket: websocket)
    
    _ = mqtt.connect()