iOS / HealthKit - server traffic logs tend to spike after app updates - ios

So, I have an app that runs an HKObserverQuery in the background. We take data from HealthKit and push it up to our server for further analysis.
When we do an app update, however, we usually see a spike in requests made to our server. It usually times from when the app becomes available in the store, and usually dies down a few days later.
My question is - when an app is updated, does it try to resume a particular state or something after the installation occurs? Our data fetch/upload process is called in applicationDidFinishLaunching, and my only hunch is that after the update occurs it tries to resume a state, thus invoking that function.
Any insight in to this would be real helpful. Thanks!
EDIT: my curiosity exists because I can't imagine all of our users opening the app after an update occurs, especially the auto-updaters. So my question revolves around if iOS attempts to load the app after installing an update to verify it, henceforth calling applicationDidFinishLaunching, but without bringing the app to the foreground.

Related

AVAggregateAssetDownloadTask stops sending updates when going to background (perhaps stops downloading)

First off, I'm on iOS 13.6.1
I'm downloading HLS videos to later play offline. It all works as expected when in foreground, all the logic does what it should and there doesn't seem to be any problem.
But when the app goes to background I stop getting updates for the AVAggregateAssetDownloadTask (I mean, I don't see the logs in the delegate callbacks printing in the Xcode console).
I followed the documentation:
NSURLSessionConfiguration sessionSendsLaunchEvents is set to true
The AppDelegate implements handleEventsForBackgroundURLSession
The Session delegate implements URLSessionDidFinishEventsForBackgroundURLSession
Also, I have background modes enabled for fetch.
The crazy thing is, if I hook up the instruments network monitor, I do get all the updates. And I see that the download keeps going in the background.
Even without the changes mentioned in the documentation indicated above, I still see that the download keeps going in the background with the monitor open.
But it seems that the network monitor keeps the app alive somehow, because if I don't open it, then I get zero updates.
To be clear, I'm not even thinking about downloads starting or finishing in the background, and waking the app or anything of that. I just want to start a download, go to the background and have the download keep downloading stuff and notifying me (which AFAIK is done in a separate process, and I can confirm from the network monitor it is).
An example:
open the app
start a download
go to background
no updates are shown
open the instruments network monitor and connect to the app running in the device
suddenly start getting updates
I'm running out of ideas. Nothing makes sense anymore, short of a bug in the framework.
Any sort of idea will be greatly appreciated, no matter how simple it may appear.
Thanks in advance!
PS: when going to settings>storage I sometimes see that the file size grows while in the background, which would mean that the download is continuing even if I don't see updates from the delegate callbacks. At some points I saw the file size unchanged over a period of background time, but that might have been an unrelated thing (I hope).

Fetch freezes after react-native app comes back from suspended state on IOS

I'm developing a react-native app, and we noticed something strange. When the app comes back from suspended state (it doesn't happen from normal background state I think), often, the fetch freezes afterwards.
To trigger it, put on battery saver (I think it will make the app go to suspended state a lot quicker), then put the app in the background, do some other stuff on your phone for a minute or 5-10, open the app again and use it.
In our case we navigated to an other screen which tried to fetch three lists of objects at the same time from the backend. In the backend, we noticed only one call coming through, and the Promise.all(...) on the three calls never gets resolved or catched. So there is no error either. Afterwards all calls work again and the problem seems to be gone. So it's a one time issue.
This never happens when not coming from suspended state.
This is extremely hard to debug, since when the app goes to suspended state, the debugger is disconnected.
We haven't tested this yet on Android, it could be that the problem exists there as well.
My gut feeling tells me, it has something to so with the internal networking of IOS or the fetch library of RN. (e.g. when reconnecting to wifi, coming from 4G or something)
Has someone experienced the same problem already or has more insights on why this is happening or how to solve this? (e.g. use a time-out and retry mechanism, which I would like to prevent, force a api call on state change to active - although react-native can't detect the suspended state)
Thanks in advance!
EDIT:
Forgot to add: we're using react-native 54, but are in the process of updating to 57. I'll report back if the issue is still happening on 57...
EDIT 2:
Atm, we solved it by doing to the calls after each other instead of the at the same time (so fetch().then(fetch().then(fetch())) which seems to resolve the issue. So yet again, doing the calls at the same time, never fails normally, only after a suspended state of the app.

iOS Backrground Sync Alternative for enterprise apps?

I have been investigating iOS background fetch for our enterprise applications. According to articles like this, there are limitations like having 30 seconds to download before the app is terminated and the may be (unconfirmed) a penalty where after 3 timeouts, an app gets banned from background sync. Also if the user kills the app, fetches stop happening -noted here.
The goal is to be able to retrieve data from our servers periodically when app is suspended/not running but sometimes the transfers can take minutes due to long running SQL. I don't want to implement sending periodic notifications to all users.
Before I go down the path of developing for the iOS background sync, I needed to do some due diligence and research alternatives to iOS's background sync and didn't find anything.
Has anyone seen or developed an alternative to iOS's background sync or dealt with this issue for their enterprise apps?
As an enterprise app there's nothing extra you can do except that you can use whatever background modes you want (audio, location, voip etc,) without needing to have a legitimate reason to do so.
Where this might assist is:
you could make use of a significant location change (as opposed to a regular location change) notification to run your app in the background. The problem with this is it of course depends on the user of your app to move around. However, assuming everybody in your workforce commutes to/from work with their iPhone then you would have two opportunities each day for the app to run in the background. A app run due to a location change can be made to execute in the background for more than 30 seconds.
voip pushes: Unlike a regular push notification, a voip push will launch the app even if the user has force terminated it. To make use of this functionality is only a tiny bit more effort than using regular push, you don't have to do anything regarding making or receiving an actual voip call, you just need the voip capability and voip certificates instead of normal push certificates.
The comment in that link is not correct regarding force quitting and background fetch - a user force quitting an app does not make it ineligible to run for a background fetch, I have force quit my own app that uses background fetch but it will still be started by the OS, however what will happen is that the frequency when the app is run will decrease lots, and if the user never runs the app again then the OS will stop launching it.
A user force quitting an app will prevent other things from happening, such as it running in the background in response to a silent push notification for example (unless its a voip push).
Also the 30 seconds in not related to download times, NSURLConnection would stop after 30 seconds, NSURLSession is designed to continue to download on your app's behalf. But if you are downloading and then applying lengthy SQL processing it would be an issue. But minutes of processing time seems excessive, are you sure its all optimized?
The goal is to be able to retrieve data from our servers periodically when app is suspended/not running
The only reliable way to achieve such a behaviour is implementing a User-facing Remote (Push) Notifications framework on backend & apps.
You can append 4kB (or 5 for VOIP) worth of data in the push JSON payload, eliminating need for a network fetch request if implemented in a handshake mechanism.
You can evaluate usage on Silent Remote Notifications to augment content updation & fetch small amounts of content opportunistically, though it has the same as Background App Refresh.
You can definitely improve the API that can take minutes due to long running SQL
And remember you need to have the app updated only when the user actually fires it up. Evaluate implementing a catchy & smooth fetching content screen that transitions into the actual screens once all data is fetched.

Uploading video files while iOS app is in background?

I'm currently working on an iOS app which involves recording and uploading videos (from the built-in camera) to a server.
It all works reasonably fine and dandy, but for a new version, the customer has requested a new feature: continuing this process without needing the app to up on the screen, and active.
At present, you record a video, it's stored as an MP4 on the file system, and a background thread uploads the file to the server. This all happens while the app is open, culminating in a screen which essentially tells you to wait until the process has finished.
If you press the home button to "minimise" the app (I'm not fluent in iOS terminology, forgive me), currently all upload processes are paused. The customer wants to have it so that you can minimise and do something entirely different as this process continues, with a notification being shown once the uploads are complete.
My understanding is that iOS offers a few special cases for downloading, streaming music and location stuff.
Supposedly once upon a time you could obtain ten minutes or so of background time while your app was minimised to finish tasks - after which time iOS would forcefully pause everything until the app was front and active again. This apparently has been changed in newer versions of iOS meaning you can't rely on a specific figure anymore - but ten minutes wasn't really good enough anyway.
I can think of hacky ways of abusing the above features but I'm half-concerned Apple might discover this during the iTunes submission process. Really I'm looking for a cleaner method - how do I continue uploading videos while the app is minimised?
I am assuming there's a solution - Dropbox can handle this situation?
Surprisingly I got somewhere with this, despite quite a few guides suggesting it was virtually impossible and even Dropbox admitting it has to do a hacky location-based thing.
The code was utilising the NSURLSession class, and for uploading, you use its uploadTaskWithStreamedRequest() method, passing an HTTP request and getting a NSURLSessionUploadTask instance in return.
What wasn't immediately clear to me, however, was that "resuming" that task led to files being uploaded independently from the rest of the app, i.e. when the app is minimised, this task continues until it either completes or iOS forces it to pause.
In a sense I had already achieved what I asked for without realising, however this task can still be interrupted by iOS after a few seconds. The rest of the app is also paused, so communication is hampered until the app is brought back to the front again.
The trick is these two methods:
uploadTaskID = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({})
and
UIApplication().sharedApplication().endBackgroundTask(uploadTaskID)
with these in place, any code after the "begin" function will run regardless of whether the app is minimised, and will do so until the "end" function is called. With a bit of tweaking, I've been able to get files to upload sequentially and post a notification when the process is done.
I haven't seen this solution be hinted at so it might be a bad idea, but it seemingly works.

guaranteed delivery for uploads after network reconnect, even if my app is not running

I'm spec-ing an iOS app (which will be built outside of our company) which will upload a user's data entry to a server. If the device is not connected to the Internet, we'd like to save data on the device and upload it when the network is re-connected. (The app will primarily run on iPod Touch devices that will be disconnected most of the time).
If the user unlocks the device and re-opens our app after the network is reconnected, then uploading to the server should be easy because the app is running.
But what if the app is not running, where "not running" can mean one or more of:
device was power cycled
user has locked the device and it's sitting in his pocket
app crashed
user exited the app
user started using other apps so our app isn't running in the foreground anymore
are there other cases?
In the cases above, is there a way (ideally a battery-efficient way) to ensure that local data is uploaded soon after Internet connectivity is restored? Is the answer different depending on which of the cases above caused the app not to be running?
And is there a minimum iOS version the device will need in order to enable some (or all) of the above not-running cases to still upload when the app is not running?
My apologies if these are obvious newbie questions-- I'm not an iOS expert.
There is an interesting technique that is used by among others Instapaper and News.me(the pioneers of this technique) where you use region monitoring to initiate background downloads or uploads. Marco (Instapaper) blogged and talked (in episode 80 of the Build and Analyze podcast) about his communication with Apple so it should be a allowed in the App Store.
In brief the technique is that you set up certain regions (geofences) like "home" or "work" and respond to the locationManager:didEnterRegion: (and similar) callback(s). Your app will wake up from the background once you enter the pre-specified region and you can check to see if there is any data to upload.
This technique won't guarantee that the data is uploaded when the network reconnects but it will allow your app to automatically upload the information when the iPod Touch users gets home to their WiFi network.
That should most likely be at least once a day which may or may not be frequent enough for you. You could add a timestamp to when the initial upload was attempted and send that along the upload once it succeeds to get the correct order of events (data entries) on your server.
There is no way to ensure this. If your application is "not running" (by the definition described in your question), it will not be capable of responding to a change in the device's network status. It should be setup to resume upload operations the next time the application runs again.
EDIT:
Some of the cases you've described may indeed provide different opportunities for your application. Specifically, if the user "exits" the app by pressing the home button or launches another app in the foreground, your application may continue to run the in the background and could potentially respond to a change in network reachability.
The nature of what may be done in the background and for how-long is well documented, and supported by any version of iOS that supports multi-tasking. I recommend you review the documentation pertaining to App States and Background Services.
device was power cycled --> really NO WAY of resuming, unless you open the App!!!
user has locked the device and it's sitting in his pocket --> apps applicationStatus is UIApplicationStateInactive but it is running in the background. You still are able to react to notifications and i.e. accelerometer events. Try the Reachability Class and Log the changes!
app crashed --> NO WAY, unless opening the App
user exited the app --> App is sitting in the background. There you have a maximum of 10 Minutes Restriction of fully using your App (like the App "Pastebot" does)
user started using other apps so our app isn't running in the
foreground anymore --> Same as user exited the app
On multitasking Apple says the following:
Real multitasking only for certain kinds of usage, as there is Audio Background playing, VOIP (like Skype), navigation applications
All the other apps can request a specific amount of time after the app is closed/in the background, to finish certain tasks (as sending an email, sms or uploading/downloading important data)
Important Quote from dev docs:
Your app delegate’s applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds.
If you're building a restful API then I would recommend using RestKit, it has a request queue that checks the network status on the device and starts uploading once network access has been assured. You can read more about this here: http://mobile.tutsplus.com/tutorials/iphone/advanced-restkit-development_iphone-sdk/. Read the sections about Request Queue and background download/upload. It should be noted that RestKit is a big library which has it's advantages and disadvantages. I'm not completely sure how this que works with the app lifecycle, if it saves the request que even if the app is terminated. You would have to investigate that. RestKit does support background uploading/downloading, but as already noted, I think it's impossible to do any uploading if the app is terminated and not in background state.
I wouldn't recommend using RestKit if the API isn't Rest though.
You can download and experiment with RestKit here: https://github.com/RestKit/RestKit.

Resources