На данный момент у нас есть 2 приложения для iOS: одно разработано с помощью React-Native
, а другое — с помощью Swift
. Теперь проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда я пытаюсь подключиться к Cloud-MQTT через порт WebSocket/SSL с использованием мобильных данных, он автоматически отключается iOS
Swift APP
(Если устройство iPhone и устройство Raspberry подключены к одной и той же сети, то все работает нормально. ), приложение React-Native
работает нормально во всех сценариях.
А если я использую Plain MQTT Port
, то соединение с мобильными данными работает нормально. Но проблема в том, что устройство Raspberry предоставляет учетные данные для подключения во время входа в систему. А шлюз предоставляет только порт WebSocket и SSL устройства. И все устройства будут иметь разные учетные данные, поэтому применение статического значения для порта не будет работать.
MQTT Cloud Broker
Server driver.cloudmqtt.com
User : xxxxxx
Password: xxxxxx
Port: 18658 //Only this port is working
SSL Port: 28658
Websockets Port (TLS only): 38658
Mosquitto version: 1.5.7
func connect(host: String, port: Int, username: String?, password: String?, cleanSession: Bool) {
guard !host.isEmpty else {
delegate?.onMqttDisconnected()
return
}
status = .connecting
let clientId = "CONNECTED_GEAR-" + String(ProcessInfo().processIdentifier)
if NetworkMonitor.shared.connection == .wifi {
mqttClient = CocoaMQTT(clientID: clientId, host: host, port: UInt16(port))
if let mqttClient = mqttClient {
UserManager.shared.isConnected = true
mqttClient.username = username
mqttClient.password = password
mqttClient.keepAlive = UInt16(60)
mqttClient.cleanSession = cleanSession
mqttClient.backgroundOnSocket = true
mqttClient.delegate = self
_ = mqttClient.connect()
} else {
UserManager.shared.isConnected = false
delegate?.onMqttError(message: "Mqtt initialization error")
status = .error
}
} else {
let socket = CocoaMQTTWebSocket()
socket.enableSSL = false
mqttClient = CocoaMQTT(clientID: clientId, host: host, port: UInt16(port), socket: socket)
if let mqttClient = mqttClient {
UserManager.shared.isConnected = true
mqttClient.username = username
mqttClient.password = password
mqttClient.keepAlive = UInt16(60)
mqttClient.cleanSession = cleanSession
mqttClient.logLevel = .debug
mqttClient.autoReconnect = false
mqttClient.allowUntrustCACertificate = true
mqttClient.backgroundOnSocket = true
mqttClient.delegate = self
_ = mqttClient.connect()
} else {
UserManager.shared.isConnected = false
delegate?.onMqttError(message: "Mqtt initialization error")
status = .error
}
}
}
Когда я установил EnableSSL = false
Network reachable via Cellular
External Host: driver.cloudmqtt.com
External Port: 38658
External User: xxxxxxx
External Password: xxxxxxx
CocoaMQTT(debug): ping
CocoaMQTT(debug): SEND: PING
CocoaMQTT(debug): =========================MQTT 3.1.1=========================
CocoaMQTT(debug): packetFixedHeaderType 192
CocoaMQTT(debug): remainingLen(len: len) [0]
CocoaMQTT(debug): variableHeader []
CocoaMQTT(debug): payload []
CocoaMQTT(debug): =============================================================
CocoaMQTT(info): Connected to 3.83.156.245 : 38658
CocoaMQTT(info): Enable backgrounding socket successfully
CocoaMQTT(debug): SEND: CONNECT(id: CONNECTED_GEAR-933, username: xxxxxxx, password: xxxxxxx, keepAlive : 60, cleansess: false)
CocoaMQTT(debug): =========================MQTT 3.1.1=========================
CocoaMQTT(debug): packetFixedHeaderType 16
CocoaMQTT(debug): remainingLen(len: len) [54]
CocoaMQTT(debug): variableHeader [0, 4, 77, 81, 84, 84, 4, 192, 0, 60]
CocoaMQTT(debug): payload [0, 18, 67, 79, 78, 78, 69, 67, 84, 69, 68, 95, 71, 69, 65, 82, 45, 57, 51, 51, 0, 8, 104, 101, 121, 103, 108, 105, 104, 103, 0, 12, 71, 103, 107, 106, 74, 101, 110, 81, 114, 119, 120, 48]
CocoaMQTT(debug): =============================================================
CocoaMQTT(debug): socket wrote data -192
CocoaMQTT(debug): socket wrote data 0
CocoaMQTT(debug): socket disconnected
Disconnect: Socket closed by remote peer
Когда я установил EnableSSL = true
External Host: driver.cloudmqtt.com
External Port: 38658
External User: xxxxxxx
External Password: xxxxxxx
CocoaMQTT(debug): ping
CocoaMQTT(debug): SEND: PING
CocoaMQTT(debug): =========================MQTT 3.1.1=========================
CocoaMQTT(debug): packetFixedHeaderType 192
CocoaMQTT(debug): remainingLen(len: len) [0]
CocoaMQTT(debug): variableHeader []
CocoaMQTT(debug): payload []
CocoaMQTT(debug): =============================================================
CocoaMQTT(info): Connected to 3.83.156.245 : 38658
CocoaMQTT(info): Enable backgrounding socket successfully
CocoaMQTT(debug): socket wrote data -192
CocoaMQTT(debug): socket disconnected
Disconnect: The operation couldn’t be completed. (kCFStreamErrorDomainSSL error -9806.)
CocoaMQTT(info): Try reconnect to server after 1s
CocoaMQTT(info): Connected to 3.83.156.245 : 38658
CocoaMQTT(info): Enable backgrounding socket successfully
CocoaMQTT(debug): Call the SSL/TLS manually validating function
MQTT Over WebSocket and SSL
, но ничего не работает.Примечание: - Я установил
AllowArbitraryLoads = true
в info.plist.
К вашему сведению: из-за проблемы с GeoFence в React-Native мы разработали приложения на Native Swift и Kotlin.
Да, это причина добавить AllowArbitraryLoads
в info.plist
Наконец я нашел решение, и теперь MQTT Connection
и WebSocket Connection
в сети любого типа работают нормально.
func connect(host: String, port: Int, username: String?, password: String?, cleanSession: Bool) {
guard !host.isEmpty else {
delegate?.onMqttDisconnected()
return
}
status = .connecting
let clientId = "CONNECTED_GEAR-" + String(ProcessInfo().processIdentifier)
//During connection without HomeNetwork wifi, required to connect with WebSocket. That's the main reason to implement different connection request for Network type.
if NetworkMonitor.shared.connection != .wifi {
let websocket = CocoaMQTTWebSocket(uri: "/ws")
mqttClient = CocoaMQTT(clientID: clientId, host: host, port: UInt16(port), socket: websocket)
if let mqttClient = mqttClient {
UserManager.shared.isConnected = true
mqttClient.enableSSL = true
mqttClient.username = username
mqttClient.password = password
mqttClient.keepAlive = UInt16(60)
mqttClient.cleanSession = cleanSession
mqttClient.backgroundOnSocket = true
mqttClient.allowUntrustCACertificate = true
mqttClient.willMessage = CocoaMQTTMessage(topic: "/will", string: "dieout")
mqttClient.autoReconnect = true
mqttClient.logLevel = .debug
mqttClient.delegate = self
_ = mqttClient.connect()
} else {
UserManager.shared.isConnected = false
delegate?.onMqttError(message: "Mqtt initialization error")
status = .error
}
} else {
mqttClient = CocoaMQTT(clientID: clientId, host: host, port: UInt16(port))
if let mqttClient = mqttClient {
UserManager.shared.isConnected = true
mqttClient.delegate = self
mqttClient.username = username
mqttClient.password = password
mqttClient.keepAlive = UInt16(60)
mqttClient.cleanSession = cleanSession
mqttClient.backgroundOnSocket = true
mqttClient.logLevel = .error
mqttClient.deliverTimeout = 15.00
mqttClient.autoReconnect = true
mqttClient.willMessage = CocoaMQTTMessage(topic: "/will", string: "dieout")
_ = mqttClient.connect()
} else {
UserManager.shared.isConnected = false
delegate?.onMqttError(message: "Mqtt initialization error")
status = .error
}
}
}
delegate
отсутствовалПримечание. – Я запросил чатGPT и получил предложение добавить эти 2 метода.
extension MqttManager: 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)")
}
info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>my-domain.cloudmqtt.com</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
Вы искали ошибку
kCFStreamErrorDomainSSL error -9806.
?