How to run CLLocationManager in a specific period of time - ios

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.

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.

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.

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

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.

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.)

How much time is an iOS app given when unsuspended or relaunched by a background service?

I have a location-based iOS 4 app that relies on significant location change monitoring while in the background. Apple's docs state:
At wake-up time, your application is
put into the background and given a
small amount of time to process the
location data. Because your
application 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.
Does anyone know how long "a small amount of time is?" Specifically, I'm wondering if I have enough time to call startUpdatingLocation on a location manager in order to get a more accurate fix than what might be provided by the initial location event. (My background location events almost always report their horizontalAccuracy as 1000m.)
If Apple's "small amount of time" would be insufficient for that purpose, am I allowed to call beginBackgroundTaskWithExpirationHandler: from a backgrounded application in order to request more time? I know that usually gives you an additional 600s, which is more than adequate.
Do you absolutely need to find a more accurate fix during application re-launch, or can you do this heavy lifting after your app has been moved into the foreground, and show a "Loading..." type screen while the work happens? That would eliminate any concerns regarding timeouts.

Resources