Processing network calls from background. Is it allowed by Apple? - ios

We are working in a groupon-like app where alerts are displayed to the user when he/she enters in the range of an offer.
The client insists on having alerts even when the app is in the background.
Due to the architecture of the system, the app gets the location of the client at intervals and checks with the server if there is any new alert. If so, the app does some processing in the local database and displays a notification.
APN cannot be used since changes in the server are out of reach for this project.
My question is whether Apple would accept it in AppleStore as I have read different opinions about it and Apple discourages its use as in this extract from iOS Developer Library
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html
At wake-up time, your app is put into the background and given a small amount of time to process the location data. Because your app is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your app may be terminated
Thanks

How often does your app get location from the user? According to Apple's Background Execution and Multitasking, if you are getting the location updates on a regular schedule (I think it's less than 10 minutes), your app can still process in the background if you add location to UIBackgroundModes in your info.plist. With those CLLocation coordinates, you can then process your web service requests.
I personally have not done something like this, so I can't tell you for sure if Apple will reject your app or not. However, if everything is within the guideline and requirements set by Apple, I don't see why they would reject your app.
EDIT:
From the Apple doc:
An app that provides continuous location updates to the user (even
when in the background) can enable background location services by
including the UIBackgroundModes key (with the location value) in its
Info.plist file. The inclusion of this value in the UIBackgroundModes
key does not preclude the system from suspending the app, but it does
tell the system that it should wake up the app whenever there is new
location data to deliver. Thus, this key effectively lets the app run
in the background to process location updates whenever they occur.
I guess even if the app is suspended, it will wake up whenever there is a new location data to deliver.

I think you should reconsider your approach for this application. It sounds like you have decided to build a set of features which are not necessarily well informed by, or a good fit for, the characteristics of the devices the app will run on.
You write that "the app gets the location every n minutes" but that's not how iOS location services work. Querying location services for the current location occasionally is a good approach when your app is running in the foreground but that's not an option once it is suspended or terminated. Instead you need to subscribe to location events, at some level of accuracy, and your app will be notified when the device's location changes. There are no guarantees about the schedule on which you receive these events and it varies depending on the accuracy you request and the speed at which the device is moving.
Additionally, obtaining a location is an expensive operation and can quickly drain the device's battery. Burning through a user's available battery power in an hour or two is a very good way to get your app uninstalled quickly. Where possible you should be using the significant location change service to get low accuracy location updates with minimal power consumption. If you need more precision then consider using boundary crossing events for a defined region or at least reduce the accuracy your have requested as much as possible.
With all that out of the way you still need to work within the limited time your app has to run once started by a location update. That's probably not long enough to make a round trip to the server. If a network connection is already active and the device happens to have low latency you will probably get a response some of the time but I would expect to see the app terminated by the OS frequently. When that happens I don't know that you will continue to receive location updates which might otherwise re-launch the app.
Instead of downloading a list of alerts and displaying them locally a better solution might be to attempt to send your current location to the server via UDP when you see a significant location change. That way you can fire off a network request without waiting for a response. Only some of those requests will still succeed but at least your app won't be terminated. You can then process the locations you receive on the server and send push notifications when appropriate.
I realize that you don't seem to be able to make server side changes. In that case the best you might be able to do is pre-fetch alerts for the nearby region when the app runs (and if you ever manage to complete a round-trip while in the background). That way you could compare location updates to that list and not need to fire off a network request on every location update. Unfortunately it sounds like you might be backed into a corner here with no reliable solution available under your current constraints.

Related

Getting continous user location and based on that sending information to server

I've got a concept of adding feature to my app which will register user location in interval of few seconds. Then sending this coordinates through cellular or Wi-Fi all when staying active in background. I need to send this in almost real time, so the app can't be killed in backgorund.
I know this concept is very power consuming but it is only a conception.
The conception of getting constant location in backgorund is in this theard https://forums.developer.apple.com/thread/69152
so I think it is possible.
But refreshing only the process in my app of sending coordinates to server it's a little bit difficult. I could not get straight answer that it is possible to set the time interval in which the app will refresh in backgrund.
Is there a method for telling the app how often it should refresh in background?
Apple won't let your app idea onto the app store. They're quite strict about which types of apps are allowed to run in the background, and are allowed to use continuous GPS. (Both of those things really drain the user's battery.) Sending a continuous stream of location updates to a server will also keep the cellular/WiFi transmitter powered up, making things even worse.
For your own experimentation, though, you can probably set up your app to be a navigation app. Those are allowed to keep the GPS "lit" constantly and to run in the background. You could then set up the location manager with the highest accuracy setting and start updating your location.
I don't think you have the ability to control how often you get location updates though. You could create a timer that fires on a regular interval and fetches the current location from the location manager. However I don't think there's much value in that, since you WILL get called when the user's location changes, and fetching the current location more often will just give you the same answers repeatedly.

How to run CLLocationManager in a specific period of time

I've read this and many other questions. I learned that there is no way to schedule task to run from background at a specific time.
My application uses CLVisit api to send location information to the server. But I want the user to be able to select a time range to send his/her check-ins. Is there any different way to stopMonitoringVisits() and startMonitoringVisits() at a specific time from background? Should my app always monitor and decide to send the location after receiving didVisit call?
Same question can be asked for startMonitoringSignificantLocationChanges()
As long as visit monitoring does exactly what your app needs, keep the monitoring always on and decide on proper handling (whether you should report location to server) when processing didVisit callback.
You are not going to put any noticeable stress on battery this way, as visit tracking is very battery friendly and iOS runs that kind of monitoring by default with or without your app.
Furthermore, any attempt to employ some "smart" tricks designed to circumvent the good practices, which are recommended by vendor and even enforced by API design, inevitably results in "bad practices", which in your case most likely will bring extra battery consumption.
The only adverse effect of keeping monitoring always on is the solid arrow in status bar, which is considered as a sign of high battery usage by many "educated" iPhone users. If this is the primary concern, and if your use case deals with quite a few time spans (for example, leaving office and home locations), you may try to use silent push notifications to activate the monitoring at around the right time.

In iOS, is it possible to start region based geofencing at a particular time?

My iOS app (which targets iOS 8.1+) use location services to determine if a user has entered a particular region during an event. Ideally I would like to enable the geofencing a little before the event and turn it off a little after the event completes. The problem is there is no guarantee the app is running an hour before the event so I turn on geofencing at the point the user registers for the event. This is not the best approach as it means the geofencing is on for much longer than it needs to be.
As far as I can tell, there is no way to "wake up" the app in the background at a scheduled time in iOS. I could use the push notification meant for updating content, but It's not clear to me if Apple would reject such a misuse of that notification.
Any suggestions?
I've been looking into this myself.
If you can arrange a push notification from your backend ("Silent push notification", aka "content-available"), it seems to be a good option. In real-world situations, this seems to give you the best control over the timing. Unfortunately, it won't work if the person doesn't have connectivity. Also, unfortunately, you need a backend that can queue events at a time (not just in response to an input.) If you have such a backend already, and your app is only useful to the user when they have network coverage anyway, this is probably the best option. It seems this an appropriate use of the technology, so Apple should approve.
Another option I'm trying is to use background fetch. You specify a "minimum interval" to avoid too much fetching. Try 50% of the remaining time-to-event as a minimum. Every time the app wakes up (whether in the foreground because the user opened it, or in the background because background-fetch opens it) you can calculate the time-to-next-event, update the fetch interval, or start the region monitoring. You are supposed to use "background fetch" to fetch information from a server, but there doesn't seem to be any requirement to poll a server, you could poll your internal data instead. I haven't fully tested this yet but it seems promising.
You can use significant location change monitoring, which I've read will wake up your app briefly every 15 minutes or less, and you can use the time/location information to decide whether to turn on the geofence. I think this would work well in combination with the above "background fetch": Many hours or days before the event you rely on background fetch, which you then use to turn on significant location change monitoring a few hours before the event. (There's speculation that geofencing is actually more battery efficient than significant change monitoring, but you could choose to assume that other apps on the user's device will already by watching for significant changes, in which case the marginal cost of your app adding itself to the list should be minimal.)
Putting them all together, you could create a sequence of
background fetch -> significant location monitoring -> geofencing
as the time gets closer.
There is also the CLVisit monitoring functionality, it's not understood very well, but supposedly uses less power and is called less frequently than significant location change monitoring. If the background fetch or silent remote notifications aren't working to wake up your app, give this a try, and please report back!
You can't (yet) do a silent content-available local notification (AFAICT). However, perhaps you can schedule up a local notification "Your event starts tomorrow" or something that convinces the user to click the option that starts the geofence. Here's a tutorial on it http://www.appcoda.com/local-notifications-ios8/, the response of action can be UIUserNotificationActivationMode.Background so your geofence can come on (if the user responds to the notification) without bringing the app to the foreground.
It's been 5 to 6 weeks since you asked, do you have your own answer already? Please let me know.

How does RunKeeper's Breeze app stay running in the background?

I'm working on figuring out how RunKeeper's Breeze iOS app stays running in the background all the time. We're building something vaguely similar (uses step data, but does other things with it) and I need to do short processing on the incoming data every few minutes.
I've noticed a few things.
Breeze registers for the following background modes:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>location</string>
<string>remote-notification</string>
</array>
At first I thought maybe they were using silent notifications to bring the app back to life on regular intervals, but it seems the system holds silent notifications unless the device is plugged in, so that limits its use for this application.
In the battery usage area it says Background Location under the Breeze app. We've set up background location updates which work fantastic for a while, but the system eventually suspends the app. We've also set up significant location updates, but that brings us back at most every 20 minutes or so, if at all. Then we're suspended again after a few moments. Which makes sense for that API.
Another interesting thing I've noticed is if you manually kill the Breeze app from the task list, you immediately get a local notification telling you to relaunch the app. Perhaps this is from applicationWillTerminate, but will this get called if the system suspends the app?
Cory,
I'm an engineer on Breeze, and I can give you some insight into how it works. Breeze does not run continuously in the background, but it does wake up frequently via all the methods you listed above (location, background fetch, and silent push).
Background location (with autopause turned off) will give you near continuous execution in the background, but it has a severe battery cost as the CPU can never sleep. I wouldn't recommend it!
Breeze allows both autopause and when it is actively using "best" accuracy location data, it also employs deferred updates. We use significant location updates only due to a bug/shortcoming that requires significant location change to start/stop standard location services in the background. When we are using significant location services (usually after you've been still for awhile), we use region monitoring (geofences) to trigger higher accuracy location data again. As the app is woken by location services, it checks motion data from the M7 to determine how location services (and other high battery drain activities) should be adjusted.
Secondly, we use background fetch to wake the app, perform the same motion data checks. Background fetch occurs throughout the day, and you can specify an interval between fetches, but that is not guaranteed. Breeze primarily uses the minimum interval, but does its own rate limiting, so is not executing significant work every time it wakes up. Background fetch occurs more frequently when the phone is awake (and often when the user has the phone open and is doing other things).
The final app wakeup is silent push, as you noticed. This is essentially a fallback, if our servers have not heard from a client app in awhile, a silent push will be used to wake the app up. It has not been our experience that silent pushes are only delivered to an app that is plugged in, but they are certainly not guaranteed reliable.
The applicationWillTerminate local notification is a failsafe primarily for iOS7, where killing an app via the task list will prevent it from receiving silent push notifications. I believe this is no longer the case in iOS8.
Thanks for your interest in Breeze, it's a very fun product to work on!

How to alert user about ram hard drive or battery in iOS

I am able to get ram, hard disk and battery info and would like to inform users when free hdd, ram or battery is (let's say) less than 20% even if my app is not running.. Is it possible? Thanks..
No, you can't. You might be able to shoehorn in to the significant location change API, which provides notification when the device changes cell towers, but this will really only work if the user moves on a regular basis (and Apple may well reject your app because you're not actually interested in the user's location).
There may be apps that monitor a network account and send a push notification message when certain thresholds are met, but all the polling and logic for this will occur on a centralised server (e.g. at your ISP) and not on the device. Such app(s) may well provide additional info while they're running—it would be possible, I think, to do this in a manner that appears to the user as though the app is running in the background, when in fact it isn't.
(If you only want this for yourself—i.e. you're a developer running your own code on your own device, and don't need to comply with the App Store guidelines—then you may also be able to use the VoIP background task type. This will get you the heartbeat-style polling you're after, but you will not get in to the App Store using the VoIP background task type for non-VoIP things—just ask the people who made Sparrow.)

Resources