I'm using awsIot to getThingShadow its working fine in lower than iOS 13 but getting issue on ios 13. I'm using below versions of pods
pod 'AWSMobileClient'
pod 'AWSIoT', '~> 2.13.0'
For getting thing state using below function which is giving error in iOS 13.
func getThingState( thingName: String, completion: @escaping (String, String) -> Void )
{
print("Cognito Identity Id (authenticated): \(String(describing: AWSMobileClient.default().identityId))")
print(AWSMobileClient.default().username)
print(AWSMobileClient.default().credentials())
let IoTData = AWSIoTData.default()
let getThingShadowRequest = AWSIoTDataGetThingShadowRequest()
print(AWSMobileClient.default().credentials())
print(IoTData.configuration)
getThingShadowRequest!.thingName = thingName
IoTData.getThingShadow(getThingShadowRequest!).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("failed: [\(error)]")
}
if (task.error == nil /*&& task.exception == nil*/) {
DispatchQueue.main.async() {
let result = task.result!
do {
// let json = try JSON(data: (result.payload as! NSData?) as! Data)
//completion( thingName, json )
}catch{}
}
}
return nil
}
}
The error console is as below
Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “data.iot.ap-southeast-1.amazonaws.com” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=( "", "" ), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://data.iot.ap-southeast-1.amazonaws.com/things/testThingNoCert/shadow, NSErrorFailingURLStringKey=https://data.iot.ap-southeast-1.amazonaws.com/things/testThingNoCert/shadow, NSUnderlyingError=0x600002c32460 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9807, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, kCFStreamPropertySSLPeerCertificates=( "", "" )}}, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <9C9FC79B-9072-4C35-B39D-51207517C8B4>.<1>" ), _kCFStreamErrorCodeKey=-9807, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <9C9FC79B-9072-4C35-B39D-51207517C8B4>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “data.iot.ap-southeast-1.amazonaws.com” which could put your confidential information at risk.}]
I tried to get solution from stackoverflow and aws the similar problem link The certificate for this server is invalid awsIOT
Kindly please post an answer or anything you find related to this, thanks.
@awsmobilesdk @palpatim @minbi @royjit @aws-amplify-ops @rohandubal @Coeur @lawmicha
Hi,
Thanks for reaching out... I executed the code you included, and was able to see the Cert issue in iOS13 and iOS11 (I didn't try on iOS12, but I suspect I would see the same thing).
I suspect this issue has to do with the way that the request is being set up. Is it possible to direct the request to your account specific endpoint? It can be found by going to
AWS IoT Core -> Settings (lower left hand corner) -> At the top, you should see "Custom endpoint"
which will look something like:
xxxxxxxxxxx.iot.<region>.amazonaws.com
In order to have your data plane operations pointed to your account specific endpoint, I think we should be able to set the defaultServiceConfiguration in the following manner:
//Set defaultServiceConfiguration
let awsRegion = AWSRegionType.<<<REGION>>
let IDENTITY_POOL_ID = "<<<REGION>>:<<UUID>>"
let iotEndPoint = AWSEndpoint(urlString: "https://xxxxx.iot.<region>.amazonaws.com")
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:awsRegion,
identityPoolId:IDENTITY_POOL_ID)
let iotDataConfiguration = AWSServiceConfiguration(region: awsRegion,
endpoint: iotEndPoint,
credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = iotDataConfiguration
//Your code as supplied above:
let IoTData = AWSIoTData.default() //this seems to pick up the [AWSServiceManager defaultServiceManager].defaultServiceConfiguration (which should now be iotDataConfiguration)
let getThingShadowRequest = AWSIoTDataGetThingShadowRequest()
IoTData.getThingShadow(getThingShadowRequest!).continueWith { (task) -> AnyObject? in
...
}
I haven't tried this specific (getThingShadow)request myself, but it is very similar to code I've run for a similar use case for data plane operations. Let me know if this helps, or if you encounter additional errors.
@wooj2 Thanks for your response. I will check with adding credentialsProvider which i was passing default and will update here.
@wooj2 I tried as per your suggestion, i've added credentialsProvider but giving same error. Please let me know if any other possibilities.
@kshrikant -
When you created an instance of AWSServiceConfiguration did you pass in your account specific IoT Endpoint?
Would it be possible for you to copy and paste the code you are using to initialize your service configuration?
Thanks!
@wooj2 I'm following basic code from these examples
https://medium.com/swlh/connect-an-ios-app-to-aws-iot-fc99d5a9562f. https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift
Using below code snipeets
```
let credentials = AWSCognitoCredentialsProvider(regionType:AWSRegion, identityPoolId: IDENTITY_POOL_ID)
let configuration = AWSServiceConfiguration(region:AWSRegion, credentialsProvider: credentials)
AWSIoT.register(with: configuration!, forKey: ASWIoTDataManager) // Same configuration var as above
let iotEndPoint = AWSEndpoint(urlString:IOT_ENDPOINT) // Access from AWS IoT Core --> Settings
let iotDataConfiguration = AWSServiceConfiguration(region: AWSRegion, // Use AWS typedef .Region
endpoint: iotEndPoint,
credentialsProvider: credentials) // credentials is the same var as created above
AWSIoTDataManager.register(with: iotDataConfiguration!, forKey: ASWIoTDataManager)
// Access the AWSDataManager instance as follows:
self.iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
Using this i'm able to connect successfully but when i try to get state it gives error which i mentioned top of this question (want to know what can be reason for the issue).
I need one help are there any AWS iOT examples or something where i can get getThingState. I need some basic stuff where i can get all how to setup at AWS console for is there must be something which i'm missing at AWS console/Xcode project setup, due to that i'm getting error ?
```
func getThingState( thingName: String, completion: @escaping (String, String) -> Void ){
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegion,identityPoolId:IDENTITY_POOL_ID)
let configuration = AWSServiceConfiguration(region:AWSRegion, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let IoTData = AWSIoTData.default()
let getThingShadowRequest = AWSIoTDataGetThingShadowRequest()
getThingShadowRequest!.thingName = thingName
IoTData.getThingShadow(getThingShadowRequest!).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("failed: [\(error)]")
}
if (task.error == nil /*&& task.exception == nil*/) {
DispatchQueue.main.async() {
let result = task.result!
do {
// let json = try JSON(data: (result.payload as! NSData?) as! Data)
//completion( thingName, json )
}catch{}
}
}
return nil
}
}
Hey @kshrikant
I’m having trouble understanding what code you are using and what error you are now seeing. In your latest response, you have two code snippets.
In the first snippet, it looks like you are attempting to create an AWSIotDataManager, which is a higher level client which uses the lower level AWSIotData class. You are encouraged to use the AWSIotDataManager, but I’m not exactly sure if this fits your use case. On the other hand, if you use the AWSIotData class, then you are responsible for managing that request/response.
If IoTDataManager fits your use case, then there’s no need to use the AWSIotData -- and as you have figured out, there is an example here:
https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift
(unfortunately, it doesn't go through a shadow example)
If IoTDataManager does not provide functionality that fits your use case, and you plan on using the low level class AWSIotData, there are a number of ways to initialize it. In your example, you are using the defaultIoTData static initializer. When doing so, please make sure you are setting up the defaultServiceConfiguration with your specific IoT endpoint in the following manner:
let iotEndPoint = AWSEndpoint(urlString: “https://————.iot.<region>.amazonaws.com ")
let configuration = AWSServiceConfiguration(region:AWSRegion,
endpoint: iotEndPoint,
credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
If you look under the hood, you can see how this class is using the defaultServiceConfiguration.
https://github.com/aws-amplify/aws-sdk-ios/blob/master/AWSIoT/AWSIoTDataService.m#L160
If the endpoint is not setup correctly, you will continue to get the certificate errors you initially reported.
Given this information, can you please let us know:
Thank you!
@wooj2 My bad due to some error was trying to add below code while fetching getThingState
```
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegion,identityPoolId:IDENTITY_POOL_ID)
let configuration = AWSServiceConfiguration(region:AWSRegion, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
```
Can you please let me know as you got there are 2 scenarios in my case
i.e first i want to connect AWS iot using web socket so there i'm using AWSIotDataManager and
second thing i want to getThingState so there is i thought only option is go with AWSIotData to get state.
May i know whats the wrong with this. This my requirement is something wrong with it ? As i see in sample code i got this is way. Can you share something for these 2 cases. Going further from App i also want to update state. You can suggest me best way to achieve all these.
Hey @kshrikant
Thank you so much. That's a lot more clear -- sounds like you want to
For these three use cases, it seems like you should be able to use the AWSIotDataManager, and not have to use the lower level generated classes (directly).
I suspect you already have this working, but just in case -- to connect over a websocket, the first thing you will need to do is setup the iotDataManager w/ your account specific IoT Endpoint.
To setup the iotDataManager see this function:
https://github.com/awslabs/aws-sdk-ios-samples/blob/master/IoT-Sample/Swift/IoTSampleSwift/ConnectionViewController.swift#L290
Then, to make the iotDataManager connect over a websocket, you'll want to get a reference to the iotDataManager and call connectUsingWebsocket(), shown here:
https://github.com/awslabs/aws-sdk-ios-samples/blob/ec0f63d95f7942b704e980e058ba3ec17e39e1bd/IoT-Sample/Swift/IoTSampleSwift/ConnectionViewController%2BWebsocket.swift#L60
At this point, it sounds like you want to get a shadow of your "thing". I did some basic prototyping, and it seems like the first thing you'll want to do is to register for updates of your thing by using iotDataManager's register function:
iotDataManager.register(withShadow: "xxxThing",
options: nil,
eventCallback: { (name, operationType, status, clientToken, data) in
print("name: \(name)")
print("operationType:\(operationType)")
print("status:\(status)")
print("clientToken:\(clientToken)")
print("data:\(data)") //json data you'll want to deserialize
})
After this, seems like you can generate your own UUID and call getShadow, to get the status of your device via its shadow:
let clientToken = UUID().uuidString
iotDataManager.getShadow("xxxThing", clientToken)
Upon getShadow completing successfully, the eventCallback should get executed with the shadow's state, which you should be able to get by deserializing the data field to JSON.
To update your thing via its shadow, it seems like you can use iotDataManager's updateShadow:jsonString:clientToken. I haven't used this myself, but I would guess it would be very similar to how getShadow works.
Best of luck!
@wooj2 Thanks for details & briefly explanation ill follow and recheck my code and will update you.
@wooj2 Thanks a lot for your time, i've implemented your suggested code it seems working for a while But now i'm always getting time out issue
i.e. AWSIoTShadowOperationStatusType timeout The exactly similar issue is opened AWSIoTDataManager.getShadow() timeout I'm looking into this now, but is there anything due to that this timeout issue is getting ? I tried with by increasing timeout interval but it doesn't seems working.
iotDataManager.register(withShadow: "005JYPAZCHSAA",
options: ["shadowOperationTimeoutSeconds": 300.0],
In addition to this can you please share some useful links for my future requirement on this where i can see all these classes ?
iotDataManager.register(withShadow: "xxxThing",
options: nil,
eventCallback: { (name, operationType, status, clientToken, data) in
print("name: \(name)")
print("operationType:\(operationType)")
print("status:\(status)")
print("clientToken:\(clientToken)")
print("data:\(data)") //json data you'll want to deserialize
})
Hey @kshrikant
Great! Glad you were able to use the AWSIotDataManager in order to connect via websocket, get status of your thing via a shadow, and (I'm guessing) updating it as well. With regards to the issue you initially reported, I will be optimistically closing this ticket, but feel free to re-open if needed.
With regards to the timeout issue you are seeing, and based on the issue you linked it sounds like by calling getShadow prior to completing the register call is the crux of the issue, and in order to avoid these timeout issues, developers need the ability to either:
a. Determine when register has completed
or
b. Intelligently queue/wait on calling GET/Update/etc on the shadow when register has completed
That being said, it does seem like other customers have worked around this issue by waiting 500ms (or more). Perhaps you can do use this stop-gap solution until the feature request has been prioritized, designed, implemented and released.
With regards to links or learning resources for IoT on iOS, I did a quick google search but sadly didn't find much. Maybe this is something you can write as you learn more through your journey ;). If you are looking for other classes in IoT on iOS, feel free to take a look at the source code here:
https://github.com/aws-amplify/aws-sdk-ios/tree/master/AWSIoT
Best of luck!
@wooj2 Sure thing mate, thanks a lot for your response.
Most helpful comment
@wooj2 Sure thing mate, thanks a lot for your response.