I am working on an iBeacon project where I want to send text informations along with iBeacon data. I am now using iPhone as iBeacon. I can't find a way to customise the data transmission as well as reception using CoreLocation.
I am able to do this if both sender and receiver are of Bluetooth mode. I have gone through similar questions (Question, Question2) and these are different from what I want.
You cannot do this with iBeacon alone. You will need your device to act as an iBeacon and a BLE peripheral. Once you enter the beacon region you will need to initiate a connection to the BLE peripheral using Core Bluetooth in order to read the additional characteristics.
I have already work on jaalee beacon, its working like a push notification also.
//start Monitoring for beacon
locationManager:(JLEBeaconManager *)manager didStartMonitoringForRegion:(JLEBeaconRegion *)region
{
[manager requestStateForRegion:region];
[beaconManager startRangingBeaconsInRegion:region];
}
//Enter method
beaconManager:(JLEBeaconManager *)manager didEnterRegion:(JLEBeaconRegion *)region
//Exit method
beaconManager:(JLEBeaconManager *)manager didExitRegion:(JLEBeaconRegion *)region
Related
I took several months developing an application based on iBeacons and I'm really frustrated.
The general idea is that when a beacon is detected, the user is notified with information specific to that iBeacon.
The application was designed as follows, all iBeacons have the same UUID, the Major determines the building (Museum, shop...) and the Minor the specific product (pictures, shoes...). So this application may serve multiple clients.
When the application starts, I begin to do monitoring and ranging for region with our UUID. When the app is in foreground all works perfect. But in background or suspended state the problems starts. Ranging is not allowed on background or suspended state.
I know that the app will be launched into the background for about 5 seconds when you enter or exit the region of a beacon. You can here do ranging in the background for this five second period, after which iOS will suspend your app again.
I managed to extend ranging for up to 3 minutes in the background with the technique learned here. I also get an extra callback with notifyEntryStateOnDisplay = YES;
But this is not enough, if a client enters a region with the app in background or suspended state, he will be notified. And during the extra 3 minutes he will be notified if the ranging detects another iBeacon, but when the 3 minutes background task expired, if no region exit is triggered he will not receive any notification again.
Is there no real solution in a scenario like this? I think it is a very common scenario and I'm surprised no way to deal with it.
EDITED: I tried to find a solution to the problem by monitoring two regions as recommended David Young in his response. In order to obtain more events of entry/exit regions.
I added the code I implemented to try to monitor two regions.
but something I have done incorrectly and didRangeBeacons:InRegion: callback is firing every 10 ms when the expected is every second.
On AppDelegate.m, I'm doing the following inside didFinishLaunchingWithOptions:
[self.locationManager startMonitoringForRegion:self.beaconRegion];
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
[self.locationManager startMonitoringForRegion:self.beaconRegion2];
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion2];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion2];
Then, on didRangeBeacons:InRegion:
- (void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
if(beacons.count > 0){
[self.locationManager stopRangingBeaconsInRegion:region];
for (CLBeacon *beacon in beacons){
NSLog(#"beacon detected major: %# minor: %#", beacon.major,beacon.minor);
}
[self.locationManager startRangingBeaconsInRegion:region];
}
}
When I run the application on the simulator, and there is a beacon of each network in range, the message is displayed on the console approximately every 10 ms.
I suspect that the stop and restart the ranging is breaking the expected callback flow, but when only one region is in the range, callbacks occur every second as expected.
The problem you describe is common. The easiest approach is to extend background ranging time forever using a background location mode. (This is similar to what the OP has already done, but for an unlimited period of time.)
Two other options:
Get hardware beacons that allow you to tune down the transmitter power (my company's RadBeacon products allow this) so the transmissions do not overlap. This way you get an exit event then a new enter event as you move from beacon to beacon.
Redesign your identifier schene so the major field is dedicated to identifying up to 20 different regions (based on UUID and major 1-20). You then monitor for all of these regions. Your individual beacons can still use the minor however you want and specifically as the key to trigger messaging. When placing your beacons, you make sure that none with overlapping transmissions share the same major. This will ensure a new background entry event as you move from one to the other.
Beacon ranging in the background works just fine on iOS 8, provided you jump through all the hoops.
Firstly, you need the correct authorization. Add the key NSLocationAlwaysUsageDescription to your Info.plist, and call
[self.locationManager requestAlwaysAuthorization];
Your app must have a Background Mode of Location Updates. Specify in Info.plist or via the Capabilities (sits parallel alongside Build Settings).
Then check for authorisation in applicationDidBecomeActive with
switch([CLLocationManager authorizationStatus])
{
...
Once authorised, you need to do:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// If you don't do this, location updates will pause after 15 minutes in the same place
// Usually this is what you want, so I've left this line commented out
// self.locationManager.pausesLocationUpdatesAutomatically = NO;
// Create a NSUUID with the same UUID as the broadcasting beacon
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kProximityUUID];
_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:#"uk.co.airsource.testregion"];
// Necessary to get continued background ranging.
// See https://community.estimote.com/hc/en-us/articles/203914068-Is-it-possible-to-use-beacon-ranging-in-the-background-
_locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[_locationManager startUpdatingLocation];
[_locationManager startMonitoringForRegion:self.beaconRegion];
We are doing some work with beacons and iOS and investigating the options for applying a debounce between when we first go in range of the beacon and when we raise a notification to the user.
So the flow would be,
Go in range of a beacon.
Start a timer.
Timer expires, post notification.
Their doesn't seem to be any complications doing this when the app is in the foreground but I'm not sure how this will work with the app closed.
If we register the location background mode then the app will get started when we go in range of a beacon but its unclear to me how long the app we'll be allowed to run. If the app is only allowed to run for a very short period of time then we won't have time to start a timer and have it expire.
Can anyone shed any light on how much execution time the location background mode allows an app when started in the background like this?
I would suggest that once you enter the beacon region that you start ranging the beacon - this will provide you with ranging callbacks at the rate of one per second - even if your app is in the background. You can count these events and use that to determine when you will post the notification. At this point you can stop ranging the beacon.
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
[manager startRangingBeaconsInRegion:(CLBeaconRegion *)region];
self.beaconCount=0;
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
}
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region {
self.beaconCount++;
if (self.beaconCount > SOME_THRESHOLD) {
[manager stopRangingBeaconsInRegion:region];
[self postLocalNotification];
}
}
Because this is using the location background mode there is no overall limit to the amount of background time available, but there is a limit on each invocation of a delegate method of a few seconds - but this code won't be anywhere near that.
You can use local notifications for this purpose. There is no guarantee how long your app will continue running in background. If you want to know how much time the OS gives you, you can check UIApplication's backgroundTimeRemaining property.
https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/backgroundTimeRemaining
I am accessing Gelo iBeacon,Its working fine in foreground mode but how to get ibeacon range or region monitoring when the app is in background mode.
Thanks in advance
Generally iOS lets you monitor for beacons in the background but not range for them. Ranging only works in the background for a few seconds after a monitoring event.
Details on detection times and steps needed to set up background monitoring are here.
Use the following method it will work for background as well as background
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
You need to make sure you ask for always access to location manager.
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
DO NOT use "Location Updates" or "Uses Bluetooth LE accessory" as this might result in rejection from the app store. We are not using ranging, but just monitoring, and this worked fine for us.
I am working on a location services app and am finding some strange behavior. Once the user confirms using location services, the geofence icon appears in the status bar. Everything works great and I get enter and exit region events whether the app is running, in the background, or not in the background. But at some point the geofence icon disappears and my device is insensitive to the Beacon. Are there any conditions under which the geofence is disabled until I power cycle the device? And power cycling does bring it back.
This is a newly introduced bug in CoreLocation. Unfortunately, there is no known automated way to fix this. It requires a power cycle or Bluetooth off/on sequence to resolve.
See here.
I was having a similar problem. My app would work and locate beacons on initial run. When I rebooted, app opened to ScanViewController as expected but did not detect beacon.
I referenced article on StackOverflow, iBeacon: didRangeBeacons stops getting called, must reset device for it to work again and reviewed Apple's WWDC 2013 Video Session "What's new in Corelocation" https://developer.apple.com/videos/wwdc/2013/index.php?id=307
I found additional CLLocation delegate methods:
When you init your beacon region if you set:
notifyEntryStateOnDisplay = YES;
//The following delegate method will be called:
-(void) locationManager: (CLLocationManager *) manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
if (state ==CLRegionStateInside) {
[_locationManager startRangingBeaconsInRegion:region]:
}
//Your alternative code
}
//To help trouble shoot, I added this delegate methods
-(void) locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *) region withError: (NSError *)error {
}
and
-(void) locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLRegion *) region withError: (NSError *)error {
}
I ran app. It returned no failure errors. I checked settings. Bluetooth was enabled and detecting BT devices.
I checked the status bar for geofencing icon. The geofencing icon was present.
I waited for over 2 minutes and then the app detected the beacons and worked as expected. Sluggish is an understatement. I knew that rebooting should work according to all the iOS 7.1 articles that I read in StackOverFlow and other resources.
I rebooted and waited for the app to detect the beacons. On average it took 2 minutes until beacon detection. I am not sure what is causing this slow response. Since must app responses are measured in fractions of seconds, I am sure that developers may think that their apps are not working.
I suggest if your app does not detect beacons or return failure errors that you wait 2 minutes to see if you app will detect the beacon(s). I hope this helps.
Is there a way to define a geofence (center and radius) around the current location of an iOS device, and have the system trigger a callback function in my app when the device exits the geofence? Will this mechanism can wake up a closed app?
I would like to avoid extensive GPS usage, so I would prefer a system message over periodic GPS polling, even at the price of reduced accuracy.
Your solution is Region Monitoring.
In iOS, regions associated with your app are tracked at all times,
including when your app is not running. If a region boundary is
crossed while an app is not running, that app is relaunched into
the background to handle the event. Similarly, if the app is suspended
when the event occurs, it is woken up and given a short amount of
time (around 10 seconds) to handle the event.
Whenever an app request for region monitoring, the iOS takes the stand then. Your app registers some location and asks iOS to monitor the region & notify as on entering or exiting the region with precise accuracy.
Like
CLRegion *region = [[CLCircularRegion alloc] initWithCenter:[location coordinate] radius:250.0 identifier:[[NSUUID UUID] UUIDString]];
Now iOS takes this request & add it to the system queues of region monitoring with an internal identification to your app. As soon as the device enters the region or exits the region, the iOS send a notification to app to rise up & fire the delegate.
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
Please note, if your app is running in the background, the iOS will make your app start in background, once the device enters / exists the registered region.
It is one of the key point on how FourSquare & other similar apps trie to perform much of location data collection & sending it to server & giving user a Tailored message within a small amount of time.
Apple documentation for Region Monitoring
Perfect tutorial which teaches you to build a geo fence step by step in ios
Following are the delegate methods which are triggered when a user enters and exits a region!
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Welcome to %#", region.identifier);
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Bye bye");
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Now monitoring for %#", region.identifier);
}