使用MQTT将iOS设备连接到AWS IoT的最佳方式



我已经构建了一个ipad应用程序,我将其连接到一个传感器标签,该标签将温度数据发送到该应用程序。

我想做的是将温度数据发送到AWS IoT,想法是使用MQTT。我已经设置了一个本地服务器,将测试数据发送到AWS IoT,但我无法将设备连接到同一个端点。我认为这是因为本地服务器可以发布数据,因为它引用了证书和私钥。但在xcode中,我不知道如何做到这一点,所以如果没有证书和私钥参考,我认为iOS应用程序无法连接到物联网。这是正确的吗?

从这里出发,最好的方式是什么?我下载了AWS iOS SDK,但它似乎不支持物联网。

我在想,我可能可以让iOS应用程序将其数据发送到一个外部服务器,该服务器连接了证书和密钥,然后让服务器将数据发布到AWS IoT。

AWS iOS SDK已更新,支持AWS IoT。您现在可以与控件API交互,并建立与平台的连接,执行发布和订阅操作。

SDK主页:https://aws.amazon.com/documentation/sdk-for-ios/

发布/子界面:http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSIoTDataManager.html

样品:https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/

除此之外,您还可以在AWS IoT中创建证书和策略,并将证书密钥插入iOS的TLS兼容MQTT客户端。GitHub上有一些。

不,没有证书就无法连接。最好的方法是编写一个函数来连接appdelegate中的aws-iot保存iot管理器和userdefault中的iot数据管理器对象。启动应用程序时,请检查对象,获取连接状态,如果未连接,请尝试再次连接。

首先初始化

func initalizeAWS(){
    // Initialize AWSMobileClient for authorization
    AWSMobileClient.sharedInstance().initialize { (userState, error) in
        guard error == nil else {
            print("Failed to initialize AWSMobileClient. Error: (error!.localizedDescription)")
            return
        }
        print("AWSMobileClient initialized.")
    }
    // Init IOT
    let iotEndPoint = AWSEndpoint(urlString: IOT_ENDPOINT)
    // Configuration for AWSIoT control plane APIs
    let iotConfiguration = AWSServiceConfiguration(region: AWSRegion, credentialsProvider: AWSMobileClient.sharedInstance())
    // Configuration for AWSIoT data plane APIs
    let iotDataConfiguration = AWSServiceConfiguration(region: AWSRegion,
                                                       endpoint: iotEndPoint,
                                                       credentialsProvider: AWSMobileClient.sharedInstance())
    AWSServiceManager.default().defaultServiceConfiguration = iotConfiguration
    iotManager = AWSIoTManager.default()
    iot = AWSIoT.default()
    AWSIoTDataManager.register(with: iotDataConfiguration!, forKey: ASWIoTDataManager)
    iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
}

连接到AWS IOT

func connectToAWS(){
    func mqttEventCallback( _ status: AWSIoTMQTTStatus )
    {
        DispatchQueue.main.async {
            print("connection status = (status.rawValue)")
            switch(status)
            {
            case .connecting:
                print( "Connecting..." )
            case .connected:
                self.connected = true
                let defaults = UserDefaults.standard
                let certificateId = defaults.string( forKey: "certificateId")
                print(certificateId)
                print( "Connected." )
                //subscribe for topic when connected
                    self.subscribe(topic: topic)  
            case .disconnected:
                print( "Disconnected" )
            case .connectionRefused:
                print( "Connection Refused" )
            case .connectionError:
                print( "Connection Error" )
            case .protocolError:
                print( "Protocol Error")
            default:
                print("unknown state: (status.rawValue)")
            }
            NotificationCenter.default.post( name: Notification.Name(rawValue: "connectionStatusChanged"), object: self )
        }
    }
    if (connected == false)
    {
        let defaults = UserDefaults.standard
        var certificateId = defaults.string( forKey: "certificateId")
        if (certificateId == nil)
        {
            DispatchQueue.main.async {
                print("No identity available, searching bundle...")
            }
            // No certificate ID has been stored in the user defaults; check to see if any .p12 files
            // exist in the bundle.
            let myBundle = Bundle.main
            let myImages = myBundle.paths(forResourcesOfType: "p12" as String, inDirectory:nil)
            let uuid = UUID().uuidString;
            if (myImages.count > 0) {
                // At least one PKCS12 file exists in the bundle.  Attempt to load the first one
                // into the keychain (the others are ignored), and set the certificate ID in the
                // user defaults as the filename.  If the PKCS12 file requires a passphrase,
                // you'll need to provide that here; this code is written to expect that the
                // PKCS12 file will not have a passphrase.
                if let data = try? Data(contentsOf: URL(fileURLWithPath: myImages[0])) {
                    DispatchQueue.main.async {
                        print( "found identity (myImages[0]), importing...")
                    }
                    if AWSIoTManager.importIdentity( fromPKCS12Data: data, passPhrase:"", certificateId:myImages[0]) {
                        // Set the certificate ID and ARN values to indicate that we have imported
                        // our identity from the PKCS12 file in the bundle.
                        defaults.set(myImages[0], forKey:"certificateId")
                        defaults.set("from-bundle", forKey:"certificateArn")
                        DispatchQueue.main.async {
                            print("Using certificate: (myImages[0]))")
                            self.iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:myImages[0], statusCallback: mqttEventCallback)
                        }
                    }
                }
            }
            certificateId = defaults.string( forKey: "certificateId")
            if (certificateId == nil) {
                DispatchQueue.main.async {
                    print( "No identity found in bundle, creating one...")
                }
                // Now create and store the certificate ID in NSUserDefaults
                let csrDictionary = [ "commonName":CertificateSigningRequestCommonName, "countryName":CertificateSigningRequestCountryName, "organizationName":CertificateSigningRequestOrganizationName, "organizationalUnitName":CertificateSigningRequestOrganizationalUnitName ]
                self.iotManager.createKeysAndCertificate(fromCsr: csrDictionary, callback: {  (response ) -> Void in
                    if (response != nil)
                    {
                        defaults.set(response?.certificateId, forKey:"certificateId")
                        defaults.set(response?.certificateArn, forKey:"certificateArn")
                        certificateId = response?.certificateId
                        print("response: [(String(describing: response))]")
                        let attachPrincipalPolicyRequest = AWSIoTAttachPrincipalPolicyRequest()
                        attachPrincipalPolicyRequest?.policyName = PolicyName
                        attachPrincipalPolicyRequest?.principal = response?.certificateArn
                        // Attach the policy to the certificate
                        self.iot.attachPrincipalPolicy(attachPrincipalPolicyRequest!).continueWith (block: { (task) -> AnyObject? in
                            if let error = task.error {
                                print("failed: [(error)]")
                            }
                            print("result: [(String(describing: task.result))]")
                            // Connect to the AWS IoT platform
                            if (task.error == nil)
                            {
                                DispatchQueue.main.asyncAfter(deadline: .now()+2, execute: {
                                    print("Using certificate: (certificateId!)")
                                    self.iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:certificateId!, statusCallback: mqttEventCallback)
                                })
                            }
                            return nil
                        })
                    }
                    else
                    {
                        DispatchQueue.main.async {
                            print("Unable to create keys and/or certificate, check values in Constants.swift")
                        }
                    }
                } )
            }
        }
        else
        {
            let uuid = UUID().uuidString;
            // Connect to the AWS IoT service
            iotDataManager.connect( withClientId: uuid, cleanSession:true, certificateId:certificateId!, statusCallback: mqttEventCallback)
        }
    }
}

AWS 的缺陷

func disconnectToAWS(){
    print("Disconnecting...")
    DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
        self.iotDataManager.disconnect();
        DispatchQueue.main.async {
            self.connected = false
            print( "Connect")
        }
    }
}

订阅主题

func subscribe(topic:String){
    let iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
    iotDataManager.subscribe(toTopic: topic, qoS: .messageDeliveryAttemptedAtLeastOnce, messageCallback: {
        (payload) ->Void in
        let stringValue = NSString(data: payload, encoding: String.Encoding.utf8.rawValue)!
        print("received: (stringValue)")
        if let jsonDict = try? JSONSerialization.jsonObject(with: payload, options: []) as? [String: Any]{
            DispatchQueue.main.async {
                if let type = jsonDict?["message_type"] as? String{
                    if type == "veh_live_info"{
                    }
                    else if type == "oil_change_info"{
                    }
                    else{
                    }
                }
            }
        }
    } )
    }

取消订阅主题

func unsubscribe(topic:String){
    let iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
    iotDataManager.unsubscribeTopic(topic)
}

参考:https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/

有一种方法可以做到这一点,而不需要用户使用AWS Cognito进行身份验证,也不需要为每个客户端生成X.509证书(就像上面的方法需要-github示例/放大)

我写了一篇关于如何简单地使用AWS iOS SDK做到这一点的文章,不需要身份验证。可能对您的用例有用:

  1. 在Medium上(认为它可能在付费墙后面)
  2. 物联网(应该是可访问的——否则这个名字会很讽刺,哈哈)

最新更新