简体   繁体   English

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

[英]Best way to connect an iOS device to AWS IoT using MQTT?

I have built an ipad app which i connect to a sensorTag, which is sending temperature data to the app. 我已经构建了一个ipad应用程序,我连接到sensorTag,它正在向应用程序发送温度数据。

What I would like to do is to send the temperature data to AWS IoT, the idea was to use MQTT. 我想做的是将温度数据发送到AWS IoT,其想法是使用MQTT。 I have set up a local server to which I send test data to AWS IoT, but I don't manage to connect the device to the same endpoint. 我已经设置了一个本地服务器,我将测试数据发送到AWS IoT,但我无法将设备连接到同一个端点。 I think the reason for this is that the local server can publish data because it refers to the certificate and the private key. 我认为原因是本地服务器可以发布数据,因为它引用了证书和私钥。 But in xcode I don't know how to do that, so without certificate and private key reference I don't think the iOS app can connect to IoT. 但是在xcode中我不知道如何做到这一点,所以没有证书和私钥引用我不认为iOS应用程序可以连接到物联网。 Is this correct? 它是否正确?

What would be the best way to go from here? 从这里出发的最佳方式是什么? I downloaded the AWS iOS SDK, but it doesn't seems to support IoT. 我下载了AWS iOS SDK,但它似乎不支持物联网。

I was thinking that I maybe can let the iOS app send its data to a external server which has the certificate and the key connected to itself, and then let the server publish the data over to AWS IoT. 我想我可能会让iOS应用程序将其数据发送到具有证书和密钥连接到自身的外部服务器,然后让服务器将数据发布到AWS IoT。

The AWS iOS SDK has been updated with support for AWS IoT. AWS iOS SDK已更新,支持AWS IoT。 You can now interact with the control API as well as establish connections to the platform and perform publish and subscribe actions. 您现在可以与控件API交互,并建立与平台的连接并执行发布和订阅操作。

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

Pub/sub interface: http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSIoTDataManager.html 发布/订阅界面: http//docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSIoTDataManager.html

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

Besides that, you can also create your certificate and policy in AWS IoT and plug your certificate keys in to a TLS-compliant MQTT client for iOS. 除此之外,您还可以在AWS IoT中创建证书和策略,并将证书密钥插入适用于iOS的TLS兼容MQTT客户端。 There are a few on GitHub. GitHub上有一些。

No, you can not able to connect without certificate. 不,没有证书就无法连接。 The best approach is write a function to connect with aws iot in appdelegate save iot manager and iot datamanger object in userdefault. 最好的方法是在userdefault中的appdelegate save iot manager和iot datamanger对象中编写一个与aws iot连接的函数。 when you launch app check with object, get connection status, if not connected then try to connect again. 当您使用对象启动应用程序检查时,获取连接状态,如果未连接,则尝试再次连接。

first initialize 首先初始化

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)
}

Connect to AWS IOT 连接到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)
        }
    }
}

Discoonect from AWS 来自AWS的Discoonect

func disconnectToAWS(){
    print("Disconnecting...")

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

        }
    }
}

Subscribe topic 订阅主题

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{

                    }
                }
            }
        }
    } )
    }

unsubscribe topic 取消订阅主题

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

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

There is a way to do it without requiring users to be authenticated with AWS Cognito, or generating X.509 certs for each client (like the above methods require - github example / amplify) 有一种方法可以在不要求用户使用AWS Cognito进行身份验证或为每个客户端生成X.509证书的情况下执行此操作(如上述方法所需 - github example / amplify)

I wrote an article on how to do it simply using the AWS iOS SDK, no auth required. 我写了一篇关于如何使用AWS iOS SDK进行操作的文章,不需要auth。 May be useful for your usecase: 可能对您的用例有用:

  1. On Medium (think it might be behind a paywall though) 在中等 (虽然它可能在付费墙后面)
  2. IoT for all (Should be accessible - name would be ironic otherwise, haha) 所有的物联网 (应该是可访问的 - 否则名称会具有讽刺意味,哈哈)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM