Problems with connecting to IBeacon - ios

I am using the example from here to connect IBeacon. I believe that my UUID is correct. But the Event RegionEntered is never called and e.Beacons.Length in DidRangeBeacons event is always 0.
locationMgr.DidRangeBeacons += (object sender, CLRegionBeaconsRangedEventArgs e) => {
var a = e.Region;
if (e.Beacons.Length > 0) {
//make notification
}
}
The difference from above mentioned sample is that I use the IBeacon instead of IPad.

Check to be sure you know the ProcimityUUID of your beacon by using the Locate app for iOS. You will need to configure the app with your ProximityUUID.
If the app will not detect your beacon, the beacon may be misconfigured or you may not have the proper UUID.
EDIT: I have added instructions for how to scan for your ProximityUUID here.

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

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,

How can I be notified of a bluetooth connection when the iOS app is backgrounded in Xamarin?

We need our app to receive notifications from the OS when the connects or disconnects from a bluetooth audio device (specifically, the one in their car).
The app gets notified when the BT device initially connects, but it then immediately seems to disconnect and logs the error:
BTCentralManager::DisconnectedPeripheral > SoundCore mini(ATT)
ERROR Error Domain=CBErrorDomain Code=7 "The specified device has disconnected from us."
...and the "DisconnectedPeripheral" event is never actually fired.
We're unsure how to simply receive connect and disconnect events while the app is backgrounded.
Do we need to connect the peripheral with the central manager? We only need to know if the audio device is connected or not - we don't need to interact with it in any way.
The events never call a second time from the background, after getting the disconnect peripheral. Presumably because of the error message we are receiving.
Sample code below:
public class BTCentralManager : CBCentralManagerDelegate
{
public CBCentralManager centralManager;
public static CBPeripheral peripheral;
public BTCentralManager()
{
System.Diagnostics.Debug.WriteLine("BTCentralManager::Constructor > ");
centralManager = new CBCentralManager(this, new DispatchQueue("myqueue"),
new CBCentralInitOptions { ShowPowerAlert = true, RestoreIdentifier = "myRestoreIdentifier" });
NSUuid[] arr = { new NSUuid("7e9002be-547f-42bc-8d56-209736f70aa2") }; //Sound core mini
var devices = centralmanager.retrieveperipheralswithidentifiers(arr);
peripheral = devices.firstordefault();
//is the only way to trigger the events, we need to first connect the peripheral to central manager???
centralManager.connectPeripheral(peripheral, new PeripheralConnectionOptions
{
NotifyOnConnection = true,
NotifyOnDisconnection = true,
NotifyOnNotification = true
});
}
//Always is triggered inclusive in background
public override void UpdatedState(CBCentralManager central)
{
System.Diagnostics.Debug.WriteLine("BTCentralManager::UpdatedState > " + central.State.ToString());
}
//Only is triggered when the device is first time connected ( Inclusive in background)
public override void ConnectedPeripheral(CBCentralManager central, CBPeripheral peripheral)
{
System.Diagnostics.Debug.WriteLine("BTCentralManager::ConnectedPeripheral > " + peripheral.Name);
//After the connect made successfully I receive this error, and never connect again to the device
//Error Domain=CBErrorDomain Code=7 "The specified device has disconnected from us."
}
public override void DisconnectedPeripheral(CBCentralManager central, CBPeripheral peripheral, NSError error)
{
System.Diagnostics.Debug.WriteLine("BTCentralManager::DisconnectedPeripheral > " + peripheral.Name + " ERROR>" + error.Description);
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
System.Diagnostics.Debug.WriteLine("BTCentralManager::DiscoveredPeripheral > " + peripheral.Name);
// base.DiscoveredPeripheral(central, peripheral, advertisementData, RSSI);
}
}
as far as I understand your question, you need to observe the availability of a bluetooth audio device. I had some investigations in this a couple of time ago and the result was not really satisfying me. Here's my conclusion:
1.) CoreBluetooth is intented to be used for Bluetooth 4.0 / Bluetooth Low Energy devices only. Many Bluetooth headphones or even car radios are still not bluetooth 4.x. So, unless you can rely on your user's bluetooth audio device to be 4.x, CoreBluetooth might be a waste of time.
2.) Your app wont be notified about a audio device being connected when your app is in background.
So far no good. But, there might be some approaches that may help.
1.) By using the CLLocationManager, you may start observing e.g. the compass (not the location to save battery) to get notified whenever the phone has been moved. Simply check the connected audio devices when the app is calling the CLLocationManagerDelegate. This is of course not very efficient, but it might work.
2.) use iBeacons and CLBeaconRegions if available. Place an iBeacon in the user's car and start observing the beacon.
I know, this is not exactly what you want to hear, but I'm afraid there's no straight forward solution for your problem.
cheers,
Peter

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.

Resources