Skip to content

MQTT 5.0 client library for iOS and macOS written in Swift

License

Notifications You must be signed in to change notification settings

RaziPour1993/CocoaMQTT

 
 

Repository files navigation

CocoaMQTT

PodVersion Platforms License Swift version

MQTT v3.1.1 and v5.0 client library for iOS/macOS/tvOS written with Swift 5

Build

Build with Xcode 11.1 / Swift 5.1

IOS Target: 12.0 or above OSX Target: 10.13 or above TVOS Target: 10.0 or above

xcode 14.3 issue:

File not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a

If you encounter the issue, Please update your project minimum depolyments to 11.0

Installation

Swift Package Manager

To integrate CocoaMQTT into your Xcode project using Swift Package Manager, follow these steps:

  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.

At last, import "CocoaMQTT" to your project:

import CocoaMQTT

CocoaPods

To integrate CocoaMQTT into your Xcode project using CocoaPods, you need to modify you Podfile like the followings:

use_frameworks!

target 'Example' do
    pod 'CocoaMQTT'
end

Then, run the following command:

$ pod install

At last, import "CocoaMQTT" to your project:

import CocoaMQTT

Carthage

Install using Carthage by adding the following lines to your Cartfile:

github "emqx/CocoaMQTT" "master"

Then, run the following command:

$ carthage update --platform iOS,macOS,tvOS --use-xcframeworks

At last:

On your application targets “General” settings tab, in the "Frameworks, Libraries, and Embedded content" section, drag and drop CocoaMQTT.xcframework, CocoaAsyncSocket.xcframework and Starscream.xcframework from the Carthage/Build folder on disk. Then select "Embed & Sign".

Usage

Create a client to connect MQTT broker:

///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()

///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()

Now you can use closures instead of CocoaMQTTDelegate:

mqtt.didReceiveMessage = { mqtt, message, id in
    print("Message received in topic \(message.topic) with payload \(message.string!)")           
}

SSL Secure

One-way certification

No certificate is required locally. If you want to trust all untrust CA certificates, you can do this:

mqtt.allowUntrustCACertificate = true

Two-way certification

Need a .p12 file which is generated by a public key file and a private key file. You can generate the p12 file in the terminal:

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

Note: Please use openssl version 1.1 (e.g. brew install openssl@1.1), otherwise you may not be able to import the generated .p12 file to the system correctly.

MQTT over Websocket

In the 1.3.0, The CocoaMQTT has supported to connect to MQTT Broker by Websocket.

If you integrated by Swift Package Manager, follow these steps:

  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.

At last, import "CocoaMQTT" and "Starscream" to your project:

import CocoaMQTT
import CocoaMQTTWebSocket
import Starscream

If you integrated by CocoaPods, you need to modify you Podfile like the followings and execute pod install again:

use_frameworks!

target 'Example' do
    pod 'CocoaMQTT/WebSockets'
end

If you're using CocoaMQTT in a project with only a .podspec and no Podfile, e.g. in a module for React Native, add this line to your .podspec:

Pod::Spec.new do |s|
  ...
  s.dependency "Starscream"
end

Then, Create a MQTT instance over Websocket:

///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()

If you want to add additional custom header to the connection, you can use the following:

let websocket = CocoaMQTTWebSocket(uri: "/mqtt")
websocket.headers = [
            "x-api-key": "value"
        ]
        websocket.enableSSL = true

let mqtt = CocoaMQTT(clientID: clientID, host: host, port: 8083, socket: websocket)

// ...

_ = mqtt.connect()

If you want to connect using WebSocket Secure (wss), you can use the following example:

import CocoaMQTT
import CocoaMQTTWebSocket
import Starscream

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, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) {
        // Implement your custom SSL validation logic here.
        // For example, you might want to always trust the certificate for testing purposes:
        completionHandler(true)
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            if let serverTrust = challenge.protectionSpace.serverTrust {
                completionHandler(.useCredential, URLCredential(trust: serverTrust))
                return
            }
        }
        completionHandler(.performDefaultHandling, nil)
    }
    
    func mqttUrlSession(_ mqtt: CocoaMQTT, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        print("\(#function), \n result:- \(challenge.debugDescription)")
    }
    
    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 mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: (any Error)?) {
        print("Disconnected from MQTT broker with error: \(String(describing: err))")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didConnectAck 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))")
    }
    
}

Example App

You can follow the Example App to learn how to use it. But we need to make the Example App works first:

$ cd Examples

Then, open the `Example.xcodeproj` by Xcode and start it!

## Dependencies


These third-party functions are used:

~~[GCDAsyncSocket](https://github.com/robbiehanson/CocoaAsyncSocket)~~
* [MqttCocoaAsyncSocket](https://github.com/leeway1208/MqttCocoaAsyncSocket)
* [Starscream](https://github.com/daltoniam/Starscream)


## LICENSE

MIT License (see `LICENSE`)

## Contributors

* [@andypiper](https://github.com/andypiper)
* [@turtleDeng](https://github.com/turtleDeng)
* [@jan-bednar](https://github.com/jan-bednar)
* [@jmiltner](https://github.com/jmiltner)
* [@manucheri](https://github.com/manucheri)
* [@Cyrus Ingraham](https://github.com/cyrusingraham)

## Author

- Feng Lee <feng@emqx.io>
- CrazyWisdom <zh.whong@gmail.com>
- Alex Yu <alexyu.dc@gmail.com>
- Leeway <leeway1208@gmail.com>


## Twitter

https://twitter.com/EMQTech

About

MQTT 5.0 client library for iOS and macOS written in Swift

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 99.4%
  • Other 0.6%