I want to use the new Geofence API of iOS 8 (scheduleLocalNotification:).
I schedule a UILocalNotification with a region and so on. Everything works, but how can I differentiate between ENTERING and EXITING a region, resp. ignore EXITING?
iOS always displays/sends a notification, but I only want a notification when the user enters the region.
Right now I think I have to stick to the "old" startMonitoringForRegion: API.
Is that correct?
You can set region.notifyOnExit = NO to only receive notifications when you enter a region. You can also set region.notifyOnEntry = NO to only receive notifications when you exit a region.
If you want to monitor both, while still being able to tell if it is an entry or an exit, I see two options. The first option would be to schedule two notifications, one where notifyOnExit is false and one where notifyOnEntry is false. The second option is to use the existing startMonitoringForRegion api to monitor both. It depends on the use case.
Keep in mind that there is a limit to the number of regions that can be monitored (currently 20 per application I believe). I'm not sure if monitoring the same region twice counts as one or two in this case.
Hope this helps.
Related
Using the estimote beacons, I get multiple local notifications fired from didEnterRegion. I only range & monitor 1 region under which all my beacons reside.
I am trying to restrict this functionality so that users only get notified once whilst in the region. I would think this is out-of-the-box functionality since there's a corresponding didExitRegion event, so in essence you only get 1 notification whilst inside the region.
I don't see this behaviour though. Event didEnterRegion fires multiple times while I am physically inside the region. So I implemented a counter that's initially set to 0 and increments by 1 every time I'm inside didEnterRegion. I only allow the local notification to fire when the counter < 1.
But this has left me wondering; how will this work when the app is not running? Also, by doing it this way (i.e. not resetting the counter back to 0 via didExitRegion) do I only notify the user just once throughout the presence of the app on his phone, regardless the times he will physically enter / exit the region (while the app is installed and not running)? I want to inform him just once whilst in the region, and not just once in general.
I'm clearly confused with this, so would love to hear any feedback.
Make sure that you're not monitoring the same beacon multiple times, by inspecting the monitoredRegions property of your ESTBeaconManager/CLLocationManager.
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.
I'm building an iOS App, in which I would wish to handle more than 20 iBeacons. Basically all beacons added to the web portal have to be handled by the App. Since there is an iOS restriction to number of region to be monitored as 20, I'm unable to give different local notifications for beacons in same region (having same UUID).
Is there any way to handle this?
A few points:
The 20 region limit applies to the number of CLRegion objects that can be registered by a single app. It does not mean you can only detect 20 beacons. Since each CLRegion object can leave the major and/or minor nil (making the fields a wildcard), each one can match billions of beacons.
Beacon apps typically use local notifications, not push notifications.
The way you set up many different notifications to come from many different beacons is like this:
Define a single wildcard region that matches all of your beacons. (Or a few regions if needed for background triggering).
Start monitoring and ranging for each of these regions.
In the didRangeBeacond:inRegion callback keep a flag for each individual beacon to see if you have sent a notification for it before. If not, set the flag to true and trigger a local notification specific to that beacon's identifiers.
For a specific business case, I would like to trigger proximity-based notification (push or UILocalNotification) by leveraging the iBeacon technology.
This is aimed to work while the app is in background/lockscreen.
I have some specific constraints :
The product has to scale at a certain level so it's not possible to range 20 regions. We will range on one UUID only (maybe 2 or 3 if we develop new set of features, but we will not register a region per physical beacon)
We will use the major and minor to call webservices
Regarding this, I know I will have to use the following approach : first didEnterRegion: with no prior information on the major/minor/distance, and then didRangeBeacon: to perform more advanced actions.
I already use local storage mechanisms to timeout a beacon after he has been used considering the fast beaming rate of beacons.
* The major constraints : we have to region events regarding to the distance of the beacon (exemple, only trigger the notification if CLProximityImmediate)
Now I see a major limitation. As my app will only range in background for a few seconds after it entered in a region, if I had constraints based on the distance/proximity, it is very possible that the app will:
return to background state before the user get close enough from the physical beacon for the event to be triggered
never be triggered again because it has to enter the region to range again, which will probably not happen
Do you have any ideas / work around for such a case ?
You are absolutely correct on the limitations CoreLocation applies in this use case. If you set it up as you describe, the typical behavior will be that the app will detect the beacon in the background at an unknown distance (often the max range of around 50 meters), range in the background for about 5 secs, then the app will be suspended by iOS. That five seconds of ranging time will typically not be enough for the user to get near enough to the beacon to trigger your use case.
Unfortunately, there are no easy workarounds with standard beacons and CoreLocation. CLBeaconRegion objects do not have a distance field like CLCircularRegion does for geofences.
Two more extreme approaches you might try:
Turn off monitoring of your one region as soon as you detect the device is too far away, then re-enable it right as your app suspends itself in the applicationWillResignActive: callback. You might get a new entry event and more background ranging time.
Use nonstandard beacons that periodically stop their transmissions to trigger forced exit/entry events.
I want implement a geo location notification in iOS, but just in a specific date and time.
The notification will only be launched if the user is in a certain location and at a certain date and time.
Ex.: The user is in Rio de Janeiro and is 12 o'clock.
Does anyone know how to merge these two conditions to launch a notification?
There is nothing built in that I know of -- you will have to code the logic yourself. So you will simply get geo updates from CoreLocation, and you can create a timer to give you time updates, then write some logic that execs periodically and, if the time/place matches your business rules, fire the notification. Note that the app will have to be running to accomplish this. You could send a push notification from an external server, but that server must know where the phone is, and your app must tell it.
Does this help?
It seems that this can be done elegantly as long as location updates are given precedent.
Use this CoreLocation startMonitoringSignificantLocationChanges
To get updates about location, and these updates will be able to start your app in the background (as explained in the docs). Then, in the "application:didFinishLaunchingWithOptions" method of your AppDelegate, include your logic for checking if it is the right time to send a notification (by checking with stuff in CoreData or otherwise).
There shouldn't be a need to create a timer with periodic checks. Just let CoreLocation handle the event's entry point since it'll launch your app in the background at the right location.
This is simple. I assume that you are familiar using the CLLocationManager and the MKReverseGeocoder classes. For your purpose monitoring for only significant location changes would probably be fine (even if that sometimes only happens for moving kilometers). It will help you save battery power on the device.
So, for CLLocationManager's delegate there is a method called locationManager:didUpdateToLocation:fromLocation what you can use. All you need to do is to use reverse geocoding here to determine the actual city's name depending the actual location using the MKReverseGeocoder class. Also, you have to check the local time on the device, match the two, and act accordingly (set up a local notification to wake the app from the background for example).