location based alarm/notification ios - ios

I'm building an iOS app, however I want to get notification which may be a local and simple notification, such that on defined area of location, such that to provided the latitude and longitude to get the area around 200meter and when the user entered in that location, it alerts the notification.
How can I schedule the location based local notification in iOS.

Take a look at what is available in the SetSDK, https://cocoapods.org/pods/SetSDK. It will allow you to get notified whenever the user arrives to a new "location" (as learned on the fly by the sdk) and then just quickly evaluate to see if it is a location you care about. So it would look something like this,
SetSDK.instance.onArrival(to: .any) { newArrival in
/* Compare the new location with the one of interest */
if newArrival.location.distance(from: placeOfInterest) < 200 {
/* do your things here */
}
}

Use a CLRegion in combination with Background Location and your app will be woken up when the user enters that region. From there you can schedule a UILocationNotification for immediate display.

Related

Parsing Beacon Information in didEnterRegion Method of Altbeacon Library

I would like to use the didEnterRegion method in association with the RegionBootstrap or MonitorNotifier in my application. Currently I'm using the RegionBootstrap but perhaps the MonitorNotifier is better for my application.
In particular I'm adding an iBeacon parser to the beaconmanager and then setting "Id1" of a region to look for the UUID portion of my iBeacon and setting "Id2" and "Id3" to Null. Though they are set to Null in the Region, I would like to be able to parse the information from those locations upon entering the didEnterRegion method. I'm using "Id2" (Major) and "Id3" (Minor) to provide random identification parameters of the beacons.
This information along with a portion of the data from the UUID would then be sent in a notification to the phone user. When testing, I'm entering the didEnterRegion method but the data that is provided is only that which matches the set region of "Id1". If someone could provide any insight at all, it would be greatly appreciated!
I would also like to receive the didEnterRegion method for the same iBeacon every 10 seconds, but with testing it appeared that once that particular iBeacon was seen once, didEnterRegion wouldn't get a subsequent call again. Any way to clear that the iBeacon was captured so that subsequent captures could happen?
I'm trying to keep the battery usage as low as possible and when using the scanRecord data from a onNonBeaconLEScan to parse the information, I'm noticing significant battery drain even when setting the foreground and background time "BetweenScanPeriod" to something really large. I really only need to see that the iBeacon entered the region and pull the information, then 10 seconds later do it again.
Intended application flow -
User enters region of beacon with matching UUID (ID1)
Beacon information from ID2 and ID3 are parsed and sent along with ID1 to user via notification
10 seconds later user receives another notification with same data
repeat until person leaves region or iBeacon stops transmitting
The simplest way to get the information you need is to enable ranging in the didDetermineStateForRegion callback:
public void didDetermineStateForRegion(int state, Region region) {
beaconManager.startRangingBeaconsInRegion(region);
beaconManager.addRangeNotifier(this);
}
public void didRangeBeaconsInRegion(Region region, List<Beacon> beacons) {
for (Beacon beacon : beacons) {
Identifier id2 = beacon.getId2();
Identifier id3 = beacon.getId3();
// Now do something with id2 and id3
}
}
The didRangeBeaconsInRegion callback will be made every 1100 ms with default settings, but you can change this to be 10 seconds if you wish with a line like this the first time you access the BeaconManager:
beaconManager.setScanPeriod(10000l);
beaconManager.setBetweenScanPeriod(0l);
In terms of battery, if you want to be getting scan updates every 10 seconds, you will be using a lot of battery, because this means doing almost constant bluetooth scans. In the background, you may wish to back off and do a 10 second scan only once every 5 minutes with this:
beaconManager.setBackgroundScanPeriod(10000l);
beaconManager.setBackgroundBetweenScanPeriod(290000l);
BackgroundPowerSaver powerSaver = new BackgroundPowerSaver();

Monitoring for more than 20 BLE beacon regions using CLLocationmanager in iOS

Currently I am using CLLocationmanager to monitor for BLE beacon regions in iOS.
I know I can range beacons if i want more than 20 regions but unfortunately ranging would not allow me to register entry(RegionDidEnter) and exit(RegionDidExit) events as far as I know.
In my use case I need to trigger actions on user's entry and user's exit in a particular beacon region even when app is in killed state or in background.
I need a efficient way to do this as if I look for significant location changes it also uses battery and also using beacons would not make much sense then if i use GPS.
When didEnter happens, iOS will launch your app into the background and give it a few seconds of execution time to handle the event. You can use that time to start ranging, receive the ranging results, and since ranging always provides full UUID/major/minor info, trigger an appropriate action based on that.
Pseudo-code:
let myUUID = x
startMonitoring(myUUID)
func onDidEnter {
startRanging(myUUID)
}
func onDidRange(beacons) {
if beacons.empty { return } // keep ranging until we find something
let major = beacons.first.major
if major == 1 { show("Welcome to X") }
if major == 2 { show("Welcome to Y") }
stopRanging(myUUID)
}
To ensure that your app doesn't get put back to sleep before it manages to range a beacon, you can also use a background task, then the (pseudo-)code would look something like:
func onDidEnter {
self.task = beginBackgroundTask(expirationHadler: {
// our background time is up, iOS requires us to finish our work
stopRanging(myUUID)
endBackgroundTask(self.task)
})
startRanging(myUUID)
}
func onDidRange(beacons) {
if beacons.empty { return }
let major = beacons.first.major
if major == 1 { show("Welcome to X") }
if major == 2 { show("Welcome to Y") }
stopRanging(myUUID)
endBackgroundTask(self.task)
}
You can add a workaround to this. Register only those regions near to the user location. When the location changes, you can remove regions that are now farther way and add regions coming up on the user’s path.
To save battery when dealing with location, register for significant-change location updates or make use of defer location updates or use visit monitoring.
Why Core Location limited to 20
Regions are a shared system resource, and the total number of regions
available systemwide is limited. For this reason, Core Location limits
to 20 the number of regions that may be simultaneously monitored by a
single app. To work around this limit,

iOS - EKEvent with a location-based alarm

I'm creating a 'just another task manager' app which heavily relies on the EventKit framework.
What I want to do is to add a geofencing alarm functionality. I've done some research and found the EKAlarm class which according to the docs is just what I need. As a container for those alarms I'm using the EKEvent instance (rather than EKReminder) - this is crucial because I want all my tasks to show app in the Calendar app.
The documentation says the following:
While geofence-enabled alarms can be applied to events, they are more practical for reminders.
So it is clear that those geofence-enabled alarms can be used with events, but the thing is that I just can't make them work - the alarm doesn't get kicked off.
Here is some code I'm using for the alarm creation (it is in Swift yet I'm pretty comfortable with Objective-C):
let structuredLocation = EKStructuredLocation(title: marker.title)
structuredLocation.geoLocation = CLLocation(latitude: marker.position.latitude, longitude: marker.position.longitude)
structuredLocation.radius = kGeofenceRadius
<...>
let alarm = EKAlarm()
alarm.structuredLocation = structuredLocation
alarm.proximity = .Enter
event.addAlarm(alarm)
In iOS 8 if I open the Calendar app I can see the created event with When I arrive text in the Alert section - something you can't achieve using the standard interface. Under iOS 9 though it is different: the interface no longer says anything about the location, instead it shows On day of event.
Does anyone have an idea of how to make it work?
Thanks

Get current location from the geo fence sample project

I was trying out the Google's Geo fence sample project. I'm getting the entry/exit events correctly. But how can I get the current location of the user from it. I would like to keep track of user location even after entry/exit points. Please help.
The sample project is from the developer portal.
in your broadcastrecievero or service you get a GeofencingEvent , use it to get the triggering position
public class GeofenceTransitionsIntentService extends IntentService {
//[...]
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
// ...
}
Location l = geofencingEvent.getTriggeringLocation()
}
//[...]
}
You'll need can get the user location from the Fused Location Provider in the normal fashion. The full tutorial is here: http://developer.android.com/training/location/retrieve-current.html
But basically, when you receive the geofence event inside your Receiver or Service, get an instance of LocationClient there, connect to it, and in the callback, onConnected(), get the last known location:
Location position = locationClient.getLastLocation();
99.9% of the time, or a little better, you'll find this location to be inside your geofence.
To continue keeping track of user location updates, follow the Receiving Location Updates: http://developer.android.com/training/location/receive-location-updates.html

Settings alarms while app is closed

How can I set local notifications with out forcing user to open app.
I need my app set a local notification for sunrise and sunset, but I don't want to ask people open app.
I know I can have up to 64 notifications via scheduleLocalNotification, but I need to set it for a year so I should be able to run app in background and set alarms for future sunrises and sunsets in background.
The simple answer is you can't. Your app can't run whenever it wants in the background; it can't schedule a timer to wake itself up to post more notifications when they are due.
The only way you could come close to something like this is by having a server which send a background push notification to your app as a wake-up call when a new batch of 64 notifications are coming close to needed to be posted.
However this would be relying on the fact the user doesn't terminate your app. If the user does then you'd have to send a non-background push notification to the user and hope they click on it to launch your app.
Android Awareness API has recently announced new features that provide a simple solution for your use-case (that avoids you having to explicitly manage location request or computing sunrise times). The way to achieve what you're trying to do is to create and register a TimeFence specified relative to sunrise/sunset.
For example:
// Create TimeFence
AwarenessFence sunriseFence =
TimeFence.aroundTimeInstant(TimeFence.TIME_INSTANT_SUNRISE,
0, 5 * ONE_MINUTE_MILLIS);
// Register fence with Awareness.
Awareness.FenceApi.updateFences(
mGoogleApiClient,
new FenceUpdateRequest.Builder()
.addFence("fenceKey", sunriseFence, myPendingIntent)
.build())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Fence was successfully registered.");
} else {
Log.e(TAG, "Fence could not be registered: " + status);
}
}
});
You will get callbacks when the fence evaluates to TRUE at sunrise, and when it evaluates back to FALSE at 5-min after sunrise.
Please check Fence API code snippets docs for how to add your custom app logic.

Resources