I am using the keychain with iOS7 as target, I use the attribute : kSecAttrAccessibleWhenUnlockedThisDeviceOnly
It is working great, after 10sec when the device is lock the keychain variables are not accessible.
What I want now is to delete the keychain before the app is killed. applicationWillTerminate is only called if the app is killed before going into background or if the system release the application. If the app is in background for like 1min before being killed by the user, I can't find how to clear the keychain.
Is there any way to delete the keychain or have a function called when the app is killed by the user after several minute in background ?
Is there any way to delete the keychain...
NO. On iOS, there's only one keychain and its a shared resource.
If interested, here's some reading from the data security point of view. Not much has changed since the iOS 4/5 days. I think the most interesting new things are the NSSecureCoding Protocol for iOS 7 (or was it 6?) and fingerprint authentication.
Dino Zavi's Apple iOS 4 Security Evaluation
Sogeti ESEC's iOS 5 data protection updates
Belenko's Blackhat slides Evolution of iOS Data Protection and
iPhone Forensics
or have a function called when a app is killed after several minute in background
Yes and no. -applicationWillTerminate is not sent, despite what the literature says. Instead, you know you are terminating when the SIGKILL arrives. And you can't trap it. But you may be able to perform a quick wipe and return from the sighandler, though (I've never tried it, so I don't know).
The strategy to use when the data sensitivity warrants is to begin wiping data when your delegate receives -applicationWillResignActive. Or start a timer when -applicationWillResignActive arrives but cancel it if -applicationWillEnterForeground arrives. If the time elapses, then begin wiping. But both can create a poor user experience.
Related
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.
First of all it's important to note that I'm developing an Enterprise App, so there is no need for App Store guidelines \ approvals considerations.
My goal is the following:
1) An iPhone app which the user should open only one time only. During this one time he will go through some sign up process.
2) Once step (1) has finished (either by app suspension or app close), the app should "wake up" every hour (more or less) and send the server some data regarding the user from the background (all is done with the user agreement of course).
Optional Solutions I tried:
I read very thoroughly Apple guidelines for running in background in https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
I decided to go with 2 UIBackgroundModes:
location
fetch
1) For location I use:
startMonitoringSignificantLocationChanges();
manager.requestAlwaysAuthorization()
In order to make sure my app will run after "app close" or even "device reboot" I had to use both options. See Apple guidelines:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW1
If you leave the significant-change location service running and your
iOS app is subsequently suspended or terminated, the service
automatically wakes up your app when new location data arrives.
2) For background fetch I use
performFetchWithCompletionHandler()
and
UIApplication.sharedApplication().setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum);
For some reason the app doesn't run in background after 24 hours. Meaning the app never "wakes up" again even though according to Apple guidelines whenever significant location update occurs - it suppose to wake up.
What can I do in order to guarantee as much as possible that my app will run regularly in the background?
In your project properties you have to allow background mode for your application to Update location and for background fetch.
Fetch in background is not so easy as it seems.
iOS will define by itself how often it will fetch data in background modeeven you set option for each 15 minutes :(
As my practice shows time interval for fetching new data is less if user open application from time to time so iOS makes some calculations about normal app use. As a result app calls background fetch data according to app ussage.
But you can make one trick:
you can call fetch procedure from you location procedure. For data exchange it was usefull in my projects :)
The solution worked with Silent PN.
My goal as noted in the bounty was: ".. to have an iOS app that runs regularly in the background for 30+ days when not opened at all. Should also run after the app closes."
I found that when sending PN with "content-available" : 1 did the trick for me.
I set up a server which sends every 15 min a "silent PN" to all registered devices. I was able to confirm from the same server that those clients receive the PN and act on it.
Thanks #andlin for the advice.
If the user performs an action in an iOS app while offline (e.g. airplane mode), can the app complete the action (by sending data to its server) once the user is online, even if the user completely closed the app before going online?
I’m asking because Twitter and Facebook do not have this functionality. (If I post something while offline, then close the app and go online, the post will not be submitted until I start the app again.)
No. If the user kills your app, it's gone. It can no longer execute any of your applications code. The best you can do is research background tasks and you then have ~10 minutes to execute your actions before it's automatically terminated (if the user doesn't do it before the OS).
You can store the actions in a Database (Core Data, Realm) or even in NSUserDefaults. When the app comes online, you can periodically attempt to parse those actions and send the network requests with exponential back-off. I imagine this is the process Facebook and Twitter use.
I disagree with #JoeyClover's answer.
If what you want to do is an HTTP POST, you should be able to set up an NSURLSession for background processing. The system should then take over submitting your post even if the app is not running. See Xcode's docs on NSURLSession for more information. (You can do the same thing for downloads with an HTTP GET, but that's not what you're asking about.)
The exception to this is if the user actually terminates your app by swiping up on it in the task list. In that case the system kills your background upload/download tasks. The info on that is in the section on NSURLSessionConfiguration. To quote Apple's docs:
Use this method to initialize a configuration object suitable for
transferring data files while the app runs in the background. A
session configured with this object hands control of the transfers
over to the system, which handles the transfers in a separate process.
In iOS, this configuration makes it possible for transfers to continue
even when the app itself is suspended or terminated.
If an iOS app is terminated by the system and relaunched, the app can
use the same identifier to create a new configuration object and
session and retrieve the status of transfers that were in progress at
the time of termination. This behavior applies only for normal
termination of the app by the system. If the user terminates the app
from the multitasking screen, the system cancels all of the session’s
background transfers. In addition, the system does not automatically
relaunch apps that were force quit by the user. The user must
explicitly relaunch the app before transfers can begin again.
(I bolded the key bit.)
We have a customer who wants us to have our iOS app check for new data posted every night and download it if it is available. As far as I can tell this is only possible if the app is already open or if they have someone physically accept a notification or initiate the process themselves.
Is this correct? I can't imagine Apple wanting to allow launching of an app and downloading data with no user interaction at all.
Yes, generally you can only download data at exactly specified times if the app is actually running in the foreground, that is correct. It wouldn't matter if the app was open already or the user opened it from a notification, the point is that user interaction is required. So, the client can't have exactly what they want.
Look at background downloading (fetch) from iOS7+ where you can register the app to perform background downloading in advance of usage. iOS is fully in control of this and it may choose to run the app and it may not. iOS will monitor when your app is usually used by a particular user and, if appropriate, it will allow the app to run in the background to do some downloading before the user is expected to use the app.
In particular you're looking at setMinimumBackgroundFetchInterval: and setting the UIBackgroundModes key with to fetch in the Info.plist.
As an aside, here's an idea based on your expanded information:
Use idleTimerDisabled to prevent the app from sleeping during main usage and keep a track of the time
After the main usage period of the app is over, start your downloads
After the downloads are done allow the screen to sleep
On the next day, if a user opens the app, repeat
It isn't perfect, but it's an approximation
1) My plist configuration to provide backgroundmode:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
2) In didFinishLaunchingWithOptions I have:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:1.0];
3) I declared the protocol UIApplicationDelegate in the delegate.
4) I implemented the following method, but it never gets fired. (It only works if I simulate the fetch with "XCode->Debug->Simulate Background Fetch".)
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
Why? Is this a DP5 beta error? Should I radar this?
Running your app in the iOS Simulator, in Xcode Debug mode, you can force a background fetch from the Xcode menu:
Debug > Simulate Background Fetch
May work for a tethered device, I haven't tried it recently.
I'm afraid this is hard to debug on a device because you're not guaranteed it is called in the amount of time you specify.
setMinimumBackgroundFetchInterval means that it is not called in an interval which is smaller than the value you specified. But there's no setMaximumBackgroundFetchInterval.
So if iOS decides to call your app just once a day or even just once a week than it won't be called more often regardless your minimumBackgroundFetchInterval. AFAIK iOS decides when to call performFetchWithCompletionHandler measured by the pattern when and how often the users start the app.
There are many considerations:
Make sure the background fetch capability was set in the plist.
Make sure the background fetch capability hasn't been disabled for this particular app, or in general, in the device's Settings app.
Make sure to set the minimum fetch interval.
Make sure you gracefully leave the app (e.g. just hit the home button and fire up another app and/or just lock the device). But if you kill the app (by “force quitting” by double tapping on the home button and swiping up or, for those devices without home button, swiping up from the bottom to pull up the task manager and then swiping up on the app in question) that will prevent the OS from offering your app a chance to fire off subsequent background fetch requests (at least until the user runs the app again).
Make sure you are testing this on physical device and not running the app via the Xcode debugger. Being attached to the debugger changes the behavior of background operations.
Make sure the app is actually doing some network requests. If you have app that performs no network requests at all, it won't participate in background fetch. If you do, for example, a little test app with "background fetch" and don't issue any network requests, you won't participate in background fetch.
Likewise, if the OS starts up your app in background mode so it can perform a background fetch, if you don't actually perform a network request, the OS may stop offering your app the ability to perform background fetches in the future.
Make sure to call the completion handler, and do so within the allotted time, or your app may not participate in background fetch in the future.
The timing of when the OS performs background fetch is dictated by poorly documented rules that may change in the future. But the relevant factors include:
Whether the device is connected to power and/or is sufficiently charged;
Whether connected to WiFi or not;
How often the user actually fires up the app;
Whether the device is doing other network related tasks (e.g. whether background fetch can be coalesced with other network operations);
How frequently past background fetch requests resulted in there being data available.
In my experience, after the app is run the first time, if connected to wifi and power, if you wake the device about 5 minutes later, the app will perform background fetch. This isn't a hard and fast rule, but just what we've experienced in the past.
But many new developers post on Stack Overflow with questions like “how can I have app request data ever x minutes (or hours)”, “how can I request data every day at 2 am time”, etc. The short answer is that you can't. The OS decides the timing of background at its own discretion. You cannot control this (other than the minimum request interval; but you cannot control the maximum interval, as the OS controls that).
This may seem obvious to many, but make sure you've got a reliable way of knowing whether background fetch process is running correctly or not. User Notifications framework can be used to present some alert so you know if the background request resulted in something. Alternatively, os_log or Logger “Unified Logging” (see WWDC 2016 Unified Logging and Activity Tracing or 2020’s Explore logging in Swift) can be used to post messages on device that can be monitored on macOS Console app. But more than once, I've seen users do something like waiting for message to show up in Xcode or waiting for UIAlertController. You need some mechanism that works when not connected to Xcode and when the app never enters foreground.
Using your device you can fire application:performFetchWithCompletionHandler with the following steps:
Put your app in the Background state
Lock your device and wait 5 minutes.
Unlock your device, this will fire the method
(It only works if I simulate the fetch with "Xcode->Debug->Simulate
Background Fetch".)
It's because you're in Debug mode. Please try launch app without Xcode.
Another thing to check is your plist file. Make sure the UIApplicationExitsOnSuspend key is not present.
Many people here on Stack Overflow have recommended using that setting as a way to force your app to start fresh each time it's launched. That does work, but the side effect is that it prevents the new iOS 7 background fetch feature from being triggered.
If application: performFetchWithCompletionHandler: never gets fired (unless you simulate it using Xcode), check also if "Background App Refresh" preference is "On" for your app. (Settings app -> General -> Background App Refresh)
Also, background fetch is disabled if the iPhone is in Low Power Mode.
Apple provides an algorithm which defines how often the background fetch should trigger, based on your own usage of the app. If you use it a lot, then it will fetch as often as possible, but if you use like at 4pm every day, the background fetch should trigger just before, so your data is updated when you launch it.