Parsing Beacon Information in didEnterRegion Method of Altbeacon Library - altbeacon

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();

Related

How to get a beacons advertisement data in iOS background mode

I am trying to implement an app that simply detects a beacon and displays a notification while the app is in background mode.
I originally implemented CBCentralManager and received events in didDiscoverPeripheral which worked great but as soon as it goes into background mode it stops receiving events.
Since background mode is a requirement I implemented the CLLocationManager. I marked location, background-central and background-peripheral as background modes in info.plist. I also added NSLocationAlwaysUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUsageDescription to info.plist.
The relevant code is like the following:
locMgr = new CLLocationManager();
locMgr.PauseLocationUpdatesAutomatically= false;
locMgr.RequestAlwaysAuthorization();
locMgr.AllowsBackgroundLocationUpdates = true;
var nsuuid = new NSUuid(uuid.ToString());
var nsidentifier = new NSString(identifier);
CLBeaconRegion region = new CLBeaconRegion(nsuuid, nsidentifier);
region.NotifyOnExit = truel
region.NotifyOnEntry = true;
region.NotifyEntryStateOnDisplay = true;
locMgr.StartMonitoring(region);
public void OnRegionEntered(object sender, CLRegionEventARgs e)
{
is there anyway to get advertising info (instance id) of beacon in here?
anything to identify the beacon besides the proximity id which is the same for multiple beacons?
}
I have a backend server that holds additional info about the beacon that i'd like to call to get name/message. but this is keyed on the instance id of the beacon.
Does anyone know of a way to get the beacon info in background mode? can i connect to peripheral or set up cblcentralmanager in the OnRegionEntered or any other way?
Thanks for any help!
You can setup silent push notification in ios. In which you have to create one web service which will take latitude and longitude from app after certain time duration and will return list of beacons available surrounded with particular region for that latitude and longitude.
Than after, You have to implement this method in your app delegate class:
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
This method will be called when your app will get any push notification from server. You have to update your app according to the list that you get.
You can simply start beacon ranging at the same time you start beacon monitoring. So in addition to this:
locMgr.StartMonitoring(region)
Do this:
locMgr.StartRangingBeacons(in: region)
If you do this, then for about 10 seconds after the first time you detect a beacon region (even in the background) you will get a callback to the following delegate method at a rate of once per second:
didRange(beacons: beacons, region: region)
The above parameter beacons will have an array of all the beacons matching that region as CLBeacon objects, and each one will contain the full identifiers: proximityUUID, major, minor

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,

NearbyAPI iOS doesn't detect beacon already in range

I've set up Google Nearby API for my objective-c project to scan for beacons.
The app detects the beacons fine when moving into the range of a beacon but it does't work if I start the app when I'm already in range. I have to walk away from the beacon and return.
I am not using background scanning. The lib version I use is: 0.10.0
My code is:
[GNSMessageManager setDebugLoggingEnabled:YES];
_messageManager = [[GNSMessageManager alloc] initWithAPIKey:#"..."];
_beaconSubscription = [_messageManager subscriptionWithMessageFoundHandler:^(GNSMessage *message) {
NSLog(#"beacon found: %#",message);
...
} messageLostHandler:^(GNSMessage *message) {
NSLog(#"beacon lost: %#",message);
...
} paramsBlock:^(GNSSubscriptionParams *params) {
params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
params.beaconStrategy = [GNSBeaconStrategy strategyWithParamsBlock:^(GNSBeaconStrategyParams *params) {
params.includeIBeacons = YES;
}];
}];
I know about the Core Location Framework didEnterRegion / didExitRegion methods that are called only when crossing the boundaries of a beacon region and that I can use didDetermineState method but how does the NearbyAPI work on the inside with these and how can I make the app detect the beacons already in range at startup using it?
This is indeed a bug in the way Nearby Messages monitors iBeacon regions. It uses didEnterRegion/didExitRegion, and as you stated, if you're already in a region when scanning starts, didEnterRegion isn't called.
I've experimented with using didDetermineState, and with a bit of work I'm now able to handle this case. We will include this in the next bug fix release.
In the meantime, here's a trick you can use to avoid the problem while testing your app: Put your beacon into a metal enclosure (a faraday cage), and remove it from the enclosure after your app starts scanning for beacons. This simulates movement into the beacon region. I use a small cocktail shaker for my faraday cage, but a small amount of aluminum foil also works.

location based alarm/notification 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.

Ranging beacons interval

On iOS, in my application delegate I start region monitoring and as soon as I enter in a beacon region I start the ranging logic, using locationManager:didRangeBeacons:inRegion. According to the Apple documentation, this method should be called only when the the region comes within the range or out of the range or when the range changes.
My problem is that I get a call to this method every second as long as I am inside the region. How to decrease the number of calls to this method while still ranging?
locationManager:didRangeBeacons:inRegion is called once per second, no matter what. Each time it's called, the beacons parameter will contain an array of all beacons that the app can currently see, ordered by proximity. There's no way to limit the frequency at which this method is called, short of stopping ranging.
When monitoring regions (instead of ranging), your app will have didEnterRegion: and didExitRegion called, along with didDetermineState:. See this answer for a little more detail.
According to the Docs:
"The location manager calls this method whenever a beacon comes within range or goes out of range. The location manager also calls this method when the range of the beacon changes; for example, when the beacon gets closer."
Whats probably happening is the range is changing slightly which is causing the behaviour you describe.
Why is this a problem
EDIT:
IN the background you will get notified of entering regions via the app delegate method:
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{}
You can use this to determine the state:
if(state == CLRegionStateInside)
{
//Inside a region:
}
else if(state == CLRegionStateOutside)
{
//Outside a region
}
else {
//Something else
}
You can use this to gather a limited amount of information or prompt the user to load the application via a local notification. When your app resumes you can then gather more information via the locationManager.

Resources