I've been working on iOS app which interacts with iBeacon devices. Workflow is next:
if user near iBeacon then app receiving push notification from internet.
So for recognizing if user near some iBeacon needs to be turned on next modules:
gps
bluetooth
wifi/3G
push notification
The issue is that without turned on GPS module app can't find any iBeacons. It's weird since iBeacon technology works using bluetooth only.
How to solve the following problem?
I use Xcode 6.1.1, iOS 8, CoreLocation and CoreBluetooth frameworks.
Here is a code how I implemented:
if ([CLLocationManager locationServicesEnabled]) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
if([_locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"12345678-1234-1234-1234-123456789012"];
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:bundleIdentifier];
[_locationManager startMonitoringForRegion:beaconRegion];
[_locationManager startRangingBeaconsInRegion:beaconRegion];
}
else {
NSLog(#"location service is disabled");
}
You don't need GPS for iBeacon to work, but you do need Location Services.
This why I asked how you were "turning off the GPS", as I am not aware of any way in iOS that you can turn off the GPS receiver specifically.
When the user disables Location Services in the Settings app they aren't just turning off GPS - as the name says, they are turning off Location Services. Location Services in iOS refers to anything that can locate the user, which includes GPS, WiFi location and iBeacon.
No, without GPS, iBeacon will not work properly. CLLocation Manager is a class in the core location framework. The delegates of CLocation Manager will not get triggered without GPS. Here iBeacon works with the help of CLocation Manager.
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
This is the delegate that is getting triggered while an iBeacon is identified in a region. This delegate will not work without GPS.
Related
I am developing an app which has beacon region monitoring.Below is the code for monitoring beacon region.
-(void)setBeaconMonitoringForUUID:(NSString *)strID withMajor:(NSString *)strMajor withMinor:(NSString *)strMinor withIdentifier:(NSString *)strIdentifier {
NSUUID *strUUID = [[NSUUID alloc] initWithUUIDString:strID];
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:strUUID major:[strMajor intValue] minor:[strMinor intValue] identifier:strIdentifier];
[beaconRegion setNotifyEntryStateOnDisplay:YES];
[beaconRegion setNotifyOnEntry:YES];
[beaconRegion setNotifyOnExit:YES];
[self.objLocationManager startMonitoringForRegion:beaconRegion];
[self.objLocationManager startRangingBeaconsInRegion:beaconRegion];}
and the locationManager initialization is as below
- (id)init
{
self = [super init];
if (self != nil)
{
self.objLocationManager = [CLLocationManager new];
self.objLocationManager.delegate = self;
self.objLocationManager.distanceFilter = 10.0;
self.objLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.objLocationManager.allowsBackgroundLocationUpdates = YES;
if ([self.objLocationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.objLocationManager requestAlwaysAuthorization];
}
[self.objLocationManager startUpdatingLocation];
}
return self;
}
Now the question is for monitoring beacon region the iOS device must have to enable bluetooth or its working without turn on bluetooth?.I have also refer the below link but there is no explanation about to enable bluetooth for region monitoring
Determining the Availability of Region Monitoring
I have test with kontakt.io beacon and its not working without turning on bluetooth on device but as i read the region monitoring is working on Location service then why we need to enable bluetooth.so every beacon require to turn on bluetooth or it is specific to kontakt.io beacon?
Apple made a change in iOS 11 so that even if the user disables bluetooth in Control Center, scans for and detections of iBeacon devices are still performed by the operating system. (Control Center is the quick access pane you get by swiping up from the bottom of the screen on iOS.) See here for more details: https://support.apple.com/en-us/HT208086
The above statement is not true for iOS 10.x and earlier, where turning off bluetooth in Control Center will disable beacon detection. And as #Paulw11 states in his answer, you must also have location enabled on the phone, and the app must obtain a dynamic location permission from the app before it can detect beacons.
Also on all versions of iOS, if you go to Settings -> Bluetooth and disable bluetooth it will disable beacon detection.
iBeacons use Bluetooth Low Energy to advertise themselves, so the Bluetooth setting on the iOS device must be on in order to receive the signal.
Since detection of a beacon can be used to determine a user's location by correlating the detection of a beacon with the known location of the beacon you must obtain the user's permission to use their location.
I'm currently working on app that requires iBeacon monitoring.
I wrote the app one year ago, using iOS 8.x SDK.
It was working as it was supposed to, but now, one year from then, the same code doesn't work anymore (I'm testing it with the same beacons!).
Beacon regions detection has become much more unpredictable.
It has a will of its own.
Some beacons get detected, some are just ignored.
I couldn't find anything relevant on OpenRadar.
A few people complained about something similar on Apple Dev Forums, but Apple never came back to them.
Thoughts?
This is how I initialize the location manager.
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
// Worst accuracy is set in order to preserve battery life.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.allowsBackgroundLocationUpdates = YES;
// Required to keep the app living in the background.
// Background mode "Location Updates" is enabled.
[self.locationManager startUpdatingLocation];
I think before you were using geofences or CLCircular regions. Core location doesn't need any of that code to detect iBeacons. Try setting it up like this:
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
[self.locationManager startMonitoringForRegion:beaconRegion]; // Where "beaconRegion" is a CLBeaconRegion with a UUID that matches the beacon you want to detect (major & minor optional)
beaconRegion.notifyEntryStateOnDisplay = YES;
beaconRegion.notifyOnEntry = YES;
beaconRegion.notifyOnExit = YES;
You also need to add NSLocationAlwaysUsageDescription to your info.plist. Once all that is done, you should begin getting enter and exit events for your beacons through these two methods:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
Here's the code snippet. Below.
// Initialize the region with the Estimote iBeacon manually generated UUID of 16 bytes size.
NSUUID *estimoteUUID = [[NSUUID alloc] initWithUUIDString:[Repository getiBeaconRegionUUID]];
_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID
identifier:#"A"];
// Launch app when display is turned on and inside region.
_beaconRegion.notifyEntryStateOnDisplay = YES;
// Create a location manager
_locationManager = [[CLLocationManager alloc] init];
// Set delegate
_locationManager.delegate = self;
if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]])
{
[_locationManager requestAlwaysAuthorization];
[_locationManager startMonitoringForRegion:_beaconRegion];
// Get status update right away for UI
[_locationManager requestStateForRegion:_beaconRegion];
}
else
NSLog(#"This device does not support monitoring beacon regions");
There is the NSLocationAlwaysUsageDescription added to the app. plist.
There was never the dialog with the text from the key above.
In Settings => Privacy => Location Services for the app. was turned off after the first app. run.
The delegate method
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state
forRegion:(CLRegion *)region
is never called.
In iOS 7 the same app. worked without the authorization request.
Share your experience.
i have face same problem when i migrate to ios8 from ios7.and i have done following way with the apple doc with explanation of mine.
Check What apple says Here :
APPLE DOC
from iOS 8, NSLocationWhenInUseUsageDescription or a NSLocationAlwaysUsageDescription key value in Info.plist file is required.but also you need to request permission from the user before you registering for location updates, either by calling [_locationManager requestWhenInUseAuthorization] or [_locationManager requestAlwaysAuthorization] choose any of above as per you requirement.
please note this info it will gonna help through out ios 8.
After I added NSLocationAlwaysUsageDescription key-value pair into InfoPlist.strings it showed the dialog and started to work.
When testing with a simple app to test beacon region monitoring I seem to get very inconsistent results depending on the device (not the device model, the specific device). The problem is that I don't receive the CLRegionStateInside state on the region after requestStateForRegion and didEnterRegion does not get called at all on these device. startRangingBeaconsinRegion: works fine but to conserve power and processing it is recommended to only start ranging when the didEnterRegion: method gets called. I tested this on 6 devices and it works on half on them (iPhone 5's) and does't work on one iPhone 5, one 5S and one 4S.
The beacons I use are the kontakt.io beacons.
This is the code to setup the region monitoring
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_UUID];
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:#"regionIdentifier"];
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
region.notifyEntryStateOnDisplay = YES;
[self.locationManager startMonitoringForRegion:region];
[self.locationManager requestStateForRegion:region];
//If I enable this line, ranging starts on all devices
// [self.locationManager startRangingBeaconsInRegion:region];
I Found the problem. Apparently to use iBeacons in the way that is described in the documents users are required to have the Background Refresh setting enabled in the Settings. To check for this setting I use the following snippet:
if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusAvailable) {
NSLog(#"Background updates are available for the app.");
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied)
{
NSLog(#"The user explicitly disabled background behavior for this app or for the whole system.");
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted)
{
NSLog(#"Background updates are unavailable and the user cannot enable them again. For example, this status can occur when parental controls are in effect for the current user.");
}
Found in this answer: Detecting user settings for Background App Refresh in iOS 7
Monitoring may not work for several reasons. One being that App Background Refresh is disabled to save your battery. Another one is neglecting to ensure you have setup the correct App Capabilities.
If this doesn't work there is a great post you can read that details all of the items to troubleshoot.
iBeacon StartMonitoringForRegion Doesn’t Work
I'm trying to wake up my app (relaunch it) when it enters my defined beacon region but I just can't get it to work. This are the steps and code I'm using.
Set "Location updates" Background Mode to YES.
Monitor my CLBeaconRegion
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"EBEFD083-70A2-47C8-9837-E7B5634DF524"];
beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"daRegion"];
beaconRegion.notifyEntryStateOnDisplay = NO;
beaconRegion.notifyOnEntry = YES;
beaconRegion.notifyOnExit = YES;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startMonitoringForRegion:beaconRegion];
Implement delegate methods
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region;
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
Anything that I might be missing? I have read the documentation, blog posts, forums and nothing seems to work. This is one of the websites I read, and this is the other.
The comment "I just can't get it working when the app is killed" is critical.
If you use the iOS7 app switcher to kill an app (e.g. by swiping up on the app icon), then you will not be able to re-launch the app in the background upon entering or leaving an iBeacon region. This is by design -- if the user doesn't want the app running, then Apple thinks code should not be able to make it re-launch. See this thread.
Fortunately, users don't typically do this. For testing purposes, if you want to completely stop an app, don't do this. Reboot your phone instead. (Note, however, that it takes a minute or so after boot before you can detect iBeacons.)
EDIT 2014/03/10: This behavior has changed as of the release of iOS 7.1. Killing an app from the task switcher no longer stops it from detecting iBeacons in the background.