Nest Thermostat Blocked error 9999 - ios

I have an iOS app that uses a Nest Thermostat. Specifically, I want to set the Away/Home status, and then set a target temperature on it.
It works at first, but after some calls to the Nest API, i receive this error:
Error: Error Domain=com.firebase Code=9999 "{"error":"blocked","type":"https://developer.nest.com/documentation/cloud/error-messages#blocked","message":"blocked","instance":"cb7307d1-4fdc-4caf-9f80-f9ad57764dd8"}" UserInfo={NSLocalizedDescription={"error":"blocked","type":"https://developer.nest.com/documentation/cloud/error-messages#blocked","message":"blocked","instance":"cb7307d1-4fdc-4caf-9f80-f9ad57764dd8"}}
This happens both the simulator and the actual device.
I am based on the sample code provided in the Developers Nest website. It uses the Firebase API to connect to the NEST. I have seen this post with the same problem whilst authenticating, but I have this problem while trying to awake it. It takes around 20 minutes to be available again.
I also tried to call [Firebase goOffline] when I don't need to connect to it, and [Firebase goOnline] when I do, but it seems useless.
Do you know how it should be handled, and how to unblock the nest?

Related

Make sure network request gets executed before app is uninstalled

I have a PacketTunnel Provider extension running with my app. Once a user un-installs the app I get a call "stopTunnel" with an identifiable reason.
Trying to send a last network request appears to fail. Yet I'm wondering if there might be any low level network options I should try before giving up on this quest?
Happy for suggestions even if they are un-verified. I can try them in my set up.

Track when application is uninstalled on iOS

i have been trying to find a way to track when our app is uninstalled from iOS device :
Sending Push notification, this sometimes gives the desired 410 ( app uninstalled ) most of the time returns just 200. I could not find any examples on how to use their Feedback service, which seems obsolite.
Background pinging works only when the app is in the background but not shutdown. It probably could work if the app uses location services, but that would require more permissions.
Is there any way stable way to track this at all ?
many thanks
You can share your exact case to get alternative solutions.
BTW, The nearest technique to achieve this is:
1- Send silent notification, Check the following:
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
And Note the following:
The system treats background notifications as low-priority: you can
use them to refresh your app’s content, but the system doesn’t
guarantee their delivery.
2- Once you have received the notification in the device, call a web-service to flag this device/ user.
In case you want this for collecting insights, you can use analytical frameworks like: Google Analytics to get all insights that you want (Active, Downloaded, ...). Check the following:
https://developers.google.com/analytics/devguides/collection/ios/v3

Intermittent & Temporary iOS Keychain Failure

We have an app that heavily relies on being able to access a user's session token using iOS's Keychain. When our app opens, the first thing that's checked is whether the token is available - and if not, we show the user a login screen. We do not use any 3rd party library for this, and use Keychain's SecItemAdd() / SecItemCopyMatching() directly with the following options:
kSecClassGenericPassword
kSecAttrAccessibleAlwaysThisDeviceOnly
We see little to no issues with this during normal usage.
The Problem
We've had users reporting that upon opening their app, they're shown the login screen (suggesting Keychain could not find a value), when they were in fact logged in. We found that in this instance, we found that upon killing and relaunching the app, users were back to normal (session was found in Keychain). Once we found this, we tried added an exponential backoff to keep querying Keychain, thinking that it may had only been unavailable for the first few seconds. This did not work, and proved to us that Keychain seems to be unavailable for the entire app launch session. We are not able to reproduce this issue. It seems to happen very intermittently.
Upon further investigation, we found that commonly, users had received VoIP Pushes prior to having this issue. We're still not able to reproduce this issue reliably, but upon debugging, found that our Keychain.session was found to be nil when receiving these pushes (we rely on it there as well), which is before the user would open their app to see that they are pseudo- "logged out."
We use PushKit and PKPushRegistry in order to do VoIP Push. This requires our app to have "Background Modes: Voice over IP" enabled. We use all of this as suggested by Apple's documentation. Here's a sample:
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
guard let _ = Keychain.session else {
print("Session token not available")
return
}
handle(notification: payload.dictionaryPayload)
}
This code relies on Keychain.session being immediately available upon receiving a VoIP Push. As mentioned before, we've seen instances where it is not available, and so this function logs out and simply returns.
I've also found this relevant Apple forum post, suggesting that this could be an iOS bug.
Can anyone help us with this issue? Any help would be greatly appreciated. Even if this is in fact an iOS bug, we're open to workarounds.
I think this topic is driving the iOS dev community literally crazy since long time. I've read so many articles and thread about this that I lost the count.
So, I'm dealing with this issue too, and based on the #naqi answer, I started moving in that direction and I might have found a working solution.
Assumptions:
The issue seems to happen when the app is getting suspended, due any sort of reason (eg. the app in background from long time and due memory pressure the OS send it in suspended state, or the app is in bg and user upgrades to a new version from the store or automatic app update does it). I'm no longer fully sure what suspended means, but I strongly suspect that the app may get resumed/awaken without actually getting presented on the screen (due bg task, but not necessarily).
One Apple stuff member on the Apple developer forum, had the brave to reply saying something like "try to put a delay between addDidFinishLaunchingWithOptions and appDidBecomeActive". Apart from the madness here, reading that comment made me consider that maybe when the app gets resumed it triggers the addDidFinishLaunchingWithOptions but of course not the appDidBecomeActive (as it may not be resumed by the user but from any sort of event handled by the OS in background, for which we may not have the control seems, or any other feature like bg task or silent push notifications etc).
Extra info:
According with a quite old penetration test article I've found on the web (https://resources.infosecinstitute.com/iphone-penetration-testing-3/) querying the keychain actually would address the query to another process called securityd running on the device, which magically schedule the queries and performs them to the keychain db and, finally returns back the content to the requesting app, assuming that the app is still alive when the query gets completed on the keychain db. This made me think that, if that is still true, such process may fall in sort of "DDoS" attack where your app (or maybe all the apps in execution? Not clear how it actually works) performs too many queries. This may lead to false positive errors like secItemNotFound or similar. Again, as nobody confirmed this, keep it as my personal consideration.
Approach:
From the #Naqi answer, I could exclude the points 2,3 and 4, keeping the point 1 as only still valid reason. Said that, I decided to move any CRUD operation dealing with the keychain, from the addDidFinishLaunchingWithOptions to appDidBecomeActive, by handling the app setup instructions (whatever needed by your app) in there, in order to make sure that eventual background events of suspending/resuming actions won't affect the keychain at all as the appDidBecomeActive would not get called unless user actually makes the app to get opened and shown on the screen. Of course this should happen only on app launch, so you can use a bool flag or similar semaphore approach in appDidBecomeActive to make sure your setup logic is executed only once.
Combined with the above approach, In the App Delegate I also explicitly implemented application(shouldSaveApplicationState:) by returning false and application(shouldRestoreApplicationState: still returning false (Even though I assume by default should be already like this). This may not necessarily be useful but it was worth it to try too.
Summarising, on some affected devices which were randomly failing the keychain access, seems now not to happen anymore since weeks and, consider this was happening for some, almost every 2/3 days let's say, I assume it might have attenuated the issue at least.
I can say that the monitored devices were all in different configurations, with a lot of apps installed or not, with storage memory almost full or not, with a lot of apps in bg or none at all, any form factor and different iOS versions. Keychain backup to cloud not enabled, and items attribute on the keychain at least as kSecAttrAccessibleWhenUnlockedThisDeviceOnly
Open point not fully verified: Supposedly the access to keychain should be thread safe, but I found different thread on the web contradicting each other. Maybe that could somehow impact your logic and cause unexpected state
(Congrats if you managed to read up to here :) )
Hope this helps to further understand what's going on with this keychain tragedy in iOS
I was having similar issues and after talking to engineers at WWDC we identified few issues that is leading to this behavior.
We were calling Keychain too often and this can lead to a situation where it gets expensive and some calls would not finish or timeout
If an app does not provide Access Group for keychain or does not add it in save transaction with keychain then Xcode generates one but this is dynamic and can change between dev environments
If you provided an access group later in the life of your app, then your old keychain value will remain associated with the app and a new value will be created with the access group you will now provided
This also means that when you query keychain you have to provide an access group otherwise you will get a reference to what ever was found first.
Edit: formatting

Parse iOS SDK: saveEventually and logout

I'm writing an app using Parse which saves data to the server over a connection with unknown stability. As such I'm using saveEventually.
I'm trying to deal with the situation where the app is minimised, and then terminated by the system before a save is complete. The trouble is, when
opening the app afresh, I issue a logout command, since users are required to log in. It appears that this logout command can overtake the save commands, removing the session from the server, causing the queued save commands to fail. (I also can't see any way of handling these failures after an app restart, since I don't see any delegate based handlers, and blocks are cleared.)
I can't see any user-facing solutions to this either, since there is no guarantee when saveEventually might decide to run, and I can't block the user indefinitely.
Has anybody dealt with this? Any suggestions are most welcome.

Change timeout for Parse requests

In the iOS Developers Guide for Parse, it states "By default, all connections have a timeout of 10 seconds." I am looking to change this for all requests made from the app, but am not finding any information on how to do so.
The reason we'd like to modify this is that it's taking a long time for requests to fail when the user doesn't have Wi-Fi or Cellular enabled. We want to reduce the amount of time it takes to receive said error message, just a little. We don't want to implement our own reachability tests, as it will result in duplicate popup error messages and we have many requests in various view controllers throughout the app.
Can the timeout be modified, or is there some other way to obtain a better user experience than waiting 10 seconds for an error message?
There is no information on this but certainly the request timeout limits are set by Parse and a developer will not be able to change them. I think they kept the timeouts to be long to avoid a user request being rejected if their connection becomes suddenly intermittent or they go in a tunnel, etc.
You can try to warp Parse queries around a timer which uses let say 5 seconds timeout, if the response does not come in that time you cancel your your query using PFQuery cancel function and show them a message.
If you want to avoid timing out, consider checking Reachability before making the call. You may want to show the user an alert if they're not connected and you need to do something.
A lot of people say you should just assume a connection and make the attempt without checking reachability; basically just let the connection fail and handle the error that way. I think as long as the failure isn't invisible to the user, so they don't blame your app vs their network you're good though.

Resources