Prevent websocket connection to drop when entering background state ios swift - ios

After doing lots of research it seems this is a grey area...
I am trying to send occasional network requests via websockets once a user has entered the background state (using the Swift library Starscream, but I believe the problem is with iOS and sockets in general). Shortly after the user leaves the app, the socket connection automatically disconnects. I gather this has something to do with Apple's policy on 3rd party network activity in the background.
In my AppDelegate, I have tried reconnecting when the user leaves, etc, but this does not work. I have also heard about workarounds involving playing audio, but apparently this will stop my app from being published to the App Store (if that's not the case, then why and how does this work?). Others say I need some sort of grant from Apple, how do I request this? It would be great for someone to clear this up, and provide a legitimate solution. I feel this is something that apps should be capable of, so I'm waiting to find a solution.

I believe there is no legitimate way to truly work around this. Apple doesn't want apps doing stuff in the background because background activity is a big battery drain and it could make iPhone users feel their battery doesn't last enough (in addition to other issues such as "unexplained" network usage and so on), so they only provide very limited options regarding background activity in iOS apps for the sake of user experience. However, we can keep the app alive in some manners:
From the App Programming Guide for iOS:
When you find it necessary to keep your app running in the background, iOS helps you do so efficiently and without draining system resources or the user’s battery. The techniques offered by iOS fall into three categories:
Apps that start a short task in the foreground can ask for time to finish that task when the app moves to the background.
Apps that initiate downloads in the foreground can hand off management of those downloads to the system, thereby allowing the app to be suspended or terminated while the download continues.
Apps that need to run in the background to support specific types of
tasks can declare their support for one or more background execution
modes.
So it seems that, other than asking iOS to allow the app to finish short tasks or downloads, the only way to request the system to allow the app to run in the background is to specify a background execution mode in our Info.plist. This can be done in XCode's Capabilities dialog for your project, or by editing the property list file directly. Let's check which background execution modes we have available:
In iOS, only specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
Keeping a socket alive could fall into the "Apps that need to download and process new content regularly" use case, so let's check that:
Fetching Small Amounts of Content Opportunistically
Apps that need to check for new content periodically can ask the system to wake them up so that they can initiate a fetch operation for that content. To support this mode, enable the Background fetch option from the Background modes section of the Capabilities tab in your Xcode project. (You can also enable this support by including the UIBackgroundModes key with the fetch value in your app’s Info.plist file.) Enabling this mode is not a guarantee that the system will give your app any time to perform background fetches. The system must balance your app’s need to fetch content with the needs of other apps and the system itself. After assessing that information, the system gives time to apps when there are good opportunities to do so.
So it seems that this option is only usable for obtaining small amounts of content through HTTP requests (or other network requests), not for the kind of two-way constant communication a websocket would allow you to use. In fact, looking at other related answers, it seems there is indeed no legitimate manner to keep a socket open when the app enters background mode.
This means that, to do what you want, you cannot use websockets as your only communication channel. I'd recommend you to either use the fetch background mode (as described above) in order to fetch content in larger chunks than you would using the websocket while the app is in the background, or if you want the user to be able to see that new content is available, you could implement push notifications.
You can't use Push Notifications to send large amounts of content directly, but they can be used to prompt the user that there is new content available when they open your app. Regardless of whether you use background fetch or Push Notifications, you should implement methods on your App Delegate which will synchronize the app's state with your backend's state whenever your app is brought back from the background state.
Finally, regarding using audio as a workaround: The audio background state key will allow your app to stay alive indefinitely in the background - but if your app does not truly use it in order to play audio, it will get rejected by the app store.

This is solution-
var backgroundUpdateTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0)
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskIdentifier.invalid
}
func applicationWillResignActive(_ application: UIApplication) {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func applicationDidBecomeActive(_ application: UIApplication) {
self.endBackgroundUpdateTask()
}

I'm not sure what your application is doing so I can promise that Apple will approve, but you'll need a Backgroundmodes entitlement to do this.
In Xcode:
Here is a link to the Apple Docs on adding entitlements to your application.
Here is the docs for programming background execution in iOS.
After you've enabled the entitlement in Xcode and added the needed types to your plist you should be able to start coding your background websocket connection

If you have just AppDelegate you should use this
If you have SceneDelegate use my answer:
var backgroundUpdateTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0)
func sceneDidBecomeActive(_ scene: UIScene) {
self.endBackgroundUpdateTask()
}
func sceneWillResignActive(_ scene: UIScene) {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskIdentifier.invalid
}

Related

Execute a Task after specific time, even if app is in background on iOS using Swift

I have a VPN-Client app that asks the user to pause the connection for 5, 30, and 120 Minutes. The user probably leaves the application to do some work outside of my app in this period, therefore I need to Reconnect the app even if is in the background.
I tested these ways:
UIApplication.shared.beginBackgroundTask: It only leaves the app unsuspended for 30 seconds.
DispatchQueue.global(qos: .background).asyncAfter: It waits to app enter the foreground to toggle.
Thread.sleep in Background Thread: This waits to launch as DispatchQueue
Local Notification: Unfortunately it does not support silent mode as APNS.
My problem with possible ways:
Using APNS and Scheduled Push Notification` to send a silent message: This way probably works, but I prefer to handle it without a server.
Using Background Fetch from Capabilities in Background Modes: I searched a lot about this, and I think it was used for background app refresh and cycling tasks that should be run every day, hour, etc. Therefore, my case can't be used, or it's not efficient at all.
Using Background processing from Capabilities in Background Modes: I searched a lot about this too, I didn't quite catch that it can be used once, or this should be used in a cyclic way as Background Fetch. and my task to reconnect is not that heavy and long to use this strict feature that many times apple mentioned using alternative ways if possible.
Apple only allows a very limited set of app types to run in the background:
Music streaming apps, turn-by-turn navigation apps, VoIP apps, and maybe one or 2 more. (I haven't looked at this in detail for a couple of years so my info is a little stale.)
They do support various tasks like background downloading that the system performs on your app's behalf, but you want your app to re-launch after the designated period and start running again. (Even if the user just locks their phone while your app is paused, the app won't get any CPU time and may be terminated without warning.)
In short, I suspect you are out of luck.
It seems like a VPN app is another class of app that should get "always running in the background" status.
If you are a licensed Apple developer I suggest using one of your pre-paid support tickets to ask about OS support for what you are trying to do, but I have a feeling the answer is going to be "no dice."

Processing (sending/receiving) UDP data in background

I'm developing an app in Xamarin for iOS/Android that will send and receive data using UDP.
Would it be possible to do this while the app is running in the background or even when the screen has gone to sleep?
Much like when Facebook Messenger app is in an active call.
Short answer (for iOS): No. Background fetch is opportunistic, you can't just force it. Remote notifications can be triggered remotely but the processing time is limited.
VoIP apps use libraries provided by Apple to perform those tasks (E.g: PushKit, CallKit), and also make use of VoIP Background mode. Have a look at Background Execution. You can't just download content in the background whenever you want though, there are limits (in notifications, data processing, etc.)
On Android, you can use Services, that can perform long-running operations in the background, and it does not provide a user interface.
The closest to Android Services are Remote Notifications or Background fetch. Allowed background execution modes (excerpt):
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
Declaring the services lets the system know which services you use, but in some cases it is the system frameworks that actually prevent your application from being suspended.
Background fetch caveat:
Enabling this mode is not a guarantee that the system will give your app any time to perform background fetches

iOS background execution for health care apps

I need to implement the following requirement:
iOS app should periodically(Ex:- Every 1 hour) collect the data from health app and send the data to the server when in background mode.
I tried implementing this scenario like below :
I implemented the following code:-
func applicationDidEnterBackground(application: UIApplication) {
self.bgTask = application.beginBackgroundTaskWithName("updateMedicalData") {
self.endBackgroundUpdateTask()
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) {
print("Time remaining ::",application.backgroundTimeRemaining)
NSTimer.scheduledTimerWithTimeInterval(25, target:self, selector:#selector(self.performBackgroundTask), userInfo:nil, repeats:true)
}
}
I have implemented the logic of fetching the data from health app and sending server in the method "performBackgroundTask()"
But the issue is, App is running in the background only for 3 min and expiration handler is called.
I have set the key "Required background modes" to "App downloads content from the network" and for the key "Application does not run in background" to "NO" in plist file.
Can anyone tell me if it is possible to implement the above requirement ?
It is only possible for certain types of Apps to have longer background execution. More specific:
For tasks that require more execution time to implement, you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:
Apps that play audible content to the user while in the background, such as a music player app
Apps that record audio content while in the background
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Apps that need to download and process new content regularly
Apps that receive regular updates from external accessories
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Please look at this link to see whether this will works for you. I guess that the "Background fetch" might suit your needs. In that case, you need to set your UIBackgroundModes value to "fetch". Did you already do this?
Good luck!
Adding to what Robski18 has answered. There's no way you can periodically send data to the server. The only way to do this is for the server to periodically send your app a silent push notification and have the background mode which is called in that answer "Apps that need to download and process new content regularly". Except you will be pushing content not fetching it.
Even if the server sends the push periodically that does not mean the app will receive them periodically, if the server sends them every hour the app might not receive one for several hours and then they'd be all bunched together.
Also if the user kills the app then the app will not receive the pushes.
Perhaps the BGTaskScheduler is what can do the job. Though if your device is bluetooth based, there is special background mode for it when your bt device can wake up the app.

How do iOS chat apps keep running in the background?

I have always coded for Android, and now I'm looking to expand my knowledge to iOS development; so I'm really new at this, please be patient.
I understand that only a small group of apps are allowed to run indefinitely in the background. Those are VoIP, Music players and location tracking apps.
I want to write a chat app using the XMPP framework. Everything is fine until the user puts the app in the background, in which case, the app will stay connected for about ten minutes to then be killed by the system and therefore the user won't be able to receive new messages.
I am aware of hacks to keep the app alive. Hacks such as defining it as a music playing app in the info.plist file and then just play some empty sound indefinitely. But I'm also aware that Apple will reject the app when it's time to publish to the App Store.
So, normally, how do other apps do it? How can other chat apps stay alive in the background to receive new messages from the servers? Apps like Google Hangouts, IM+ and such?
Ideally, they aren't really running in the background, but use push notifications, as others have mentioned.
But some chat clients seem to do something else: I've verified (by sniffing the traffic of an idle iOS device) that at least Google Hangouts, Facebook and Skype all keep a persistent socket opened in the background, and regularly send traffic to keep it alive.
I'm suspecting that they are using the VoIP exceptions to Apple's otherwise strict background execution policies. iOS allows "VoIP apps" to run in the background and keep one socket open to be notified about incoming calls and messages.
Maybe they are also using the new "background fetch" feature of iOS 7, but as far as I know, that doesn't allow persistent socket connections.
The iOS operating system allows for the existence of something called a PUSH NOTIFICATION
There exists hundreds of tutorials online which teach you how to implement the notification code and how to respond accordingly when you receive such a message!
http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1
Check this link out for an in-depth tutorial on push notifications!
http://maniacdev.com/2011/05/tutorial-ios-push-notification-services-for-beginners
I think most of these apps use push notifications and just load the last messages from the server as soon as the app is being opened.
While there are some hacks, and your app can ask for more time when it goes in background (up to a point, and with no guarantees), this is a perfect application for push notifications.
The server tells the phone there's a message, and iOS wakes your app up to process it.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html
As of iOS 7 there is a new background-execution mode - 'fetch' for apps that need to periodically fetch new data. It sounds like your case would meet that definition.
You can find the information in the iOS App Programming Guide -
Fetching Small Amounts of Content Regularly
In iOS 7 and later, an app that retrieves content regularly from the
network can ask the system for background execution time to check for
new content. You enable support for background fetches from the
Background modes section of the Capabilities tab in your Xcode
project. (You can also enable this support by including the
UIBackgroundModes key with the fetch value in your app’s Info.plist
file.) At appropriate times, the system gives background execution
time to the apps that support this background mode, launching the app
directly into the background if needed. The app object calls the
application:performFetchWithCompletionHandler: method of its app
delegate to let you know when execution time is available.
You can also use push notifications, but that requires some server infrastructure
An app running in the background has limited capability. Read App States and Multitasking thoroughly to decide how best to design your app. Chat is not listed as one of the specific exceptions that can operate with a more relaxed policy. You will never be able to "keep [your] app live in background forever." You might be able to leverage an iOS 7 feature also described in this guide, Fetching Small Amounts of Content Regularly.
iOS App Programming Guide: App States and Multitasking
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOS ProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html

Implementing Long-Running Background Tasks in iOS

my client asks me to develop some app that periodically retrieves the user location & the phone battery status, and then send them to our backend server for data analysis, then feed back by push notification.
But through the app doc, I get to know that from apple ios dev doc:
For tasks that require more execution time to implement, you must
request specific permissions to run them in the background without
their being suspended. In iOS, only specific app types are allowed to
run in the background:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that keep users informed of their
location at all times, such as a navigation app
Apps that support
Voice over Internet Protocol (VoIP)
Newsstand apps that need to
download and process new content
Apps that receive regular updates
from external accessories
I'm wonder if this would be feasible if we wrap this app as some navigation app so we can have long-running background tasks? Does appstore will reject on our app?
BTW, what is the definition of navigation app by Apple?
You might consider using:
[CLLocationManager startMonitoringSignificantLocationChanges];
This will cause your app to be restarted if it has been killed whenever the location changes significantly, allowing you to update the details on the server at fairly regular intervals, assuming the user is moving. This does not require any special background permission. From the docs:
If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the locationManager:didUpdateLocations: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application was launched because of a location event.
Your other option is to configure the app as requiring continuous location updates in the background, but without knowing the primary function of the app it is hard to know if this will pass store submission or not.
https://github.com/yarodevuci/backgroundTask Check my code here I am using audio player that plays blank wav file Works perfectly on IOS 8 Battery usage around 10% in 24 hour period How to use:
var backgroundTask = BackgroundTask()
backgroundTask.startBackgroundTask() //Starts playing blank audio file. You can run NSTimer() or whatever you need and it will continue executing in the background.
backgroundTask.stopBackgroundTask() //Stops the task

Resources