Here is a code I use to detect Eddystone using iPhone iOS 9:
- (void)viewDidLoad
{
[super viewDidLoad];
if ([CLLocationManager locationServicesEnabled]) {
_locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager requestAlwaysAuthorization];
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"f7826da6-4fa2-4e98-8024-bc5b71e0893e"];
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:bundleIdentifier];
self.locationManager.allowsBackgroundLocationUpdates = YES;
[self.locationManager startMonitoringForRegion:beaconRegion];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
[self.locationManager startUpdatingLocation];
}
else {
NSLog(#"location service is disabled");
}
}
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(nonnull NSArray<CLBeacon *> *)beacons
inRegion:(nonnull CLBeaconRegion *)region
{
NSLog(#"beacons count: %lu", (unsigned long)[beacons count]); // beacons count always "0"
}
Also I added in plist NSLocationAlwaysUsageDescription field.
The problem is that it can't detect any Eddystone device with code above. But with third party apps it finds well.
What I'm doing wrong?
Your code is using Core Location, which only works with iBeacon. You won't be able to discover Eddystone beacons this way.
You need to use some Eddystone-compatible SDK. Since you seem to be using Kontakt.io's beacons, you might want to use their SDK:
http://developer.kontakt.io/ios-sdk/quickstart/#eddystone-support
Alternatively, you can use iOS's native Core Bluetooth to implement Eddystone scanning yourself. There's even an example on how to do that, available in the official Eddystone GitHub repo:
https://github.com/google/eddystone/tree/master/tools/ios-eddystone-scanner-sample
Related
Well, I'm having a problem with a beacon. I'm using only the location manager with his monitoring for region's method...which enables the app icon in lock screen.
When beacon is in range and my mobile is using his 3G or 4G network, the app icon in lock screen isn't showed
but, if I switch to WIFI Network the app icon is showed
and, if I'm in WIFI and switch to 3G - 4G, the app icons is showed
Why is this happening? I can't find a true answer for this.
I'm using iOS 8.3 and Xcode 6.3.2
App Delegate section:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//....other configurations...
[self startLocalizationMultipleBeaconManagerStartInBackground];
}
- (void)startLocalizationMultipleBeaconManagerStartInBackground{
BeaconController *beacon = [[BeaconController alloc]init];
[beacon startBeacon];
}
My code is this, custom beacon class:
- (void)startBeacon{
[self configureBeacon];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager = [self settingLocationManager:self.locationManager];
//At this point; authorization is: Authorized Always
[self.locationManager startMonitoringForRegion:self.beaconRegion];
}
- (CLLocationManager*)settingLocationManager:(CLLocationManager*)locationManager{
if([locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[locationManager requestAlwaysAuthorization];
}
locationManager.delegate = self;
locationManager.pausesLocationUpdatesAutomatically = NO;
return locationManager;
}
- (void)configureBeacon{
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kBeaconUUDIDForce];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:kBeaconIDForce];
self.beaconRegion.notifyOnEntry = YES;
self.beaconRegion.notifyOnExit = YES;
self.beaconRegion.notifyEntryStateOnDisplay = YES;
}
Any suggestions will be awesome.
Thanks.
My customer asked if it is possible that when a customer walks by his store he receives an email with todays special prices, even if the app is not running.
My question is: Is it allowed by iOS to call a restservice if the app is wakened by the iBeacon event?
I tried to play a system sound to simulate the restservice call and this is not working. Only when the app is in foreground.
To give you an idea how I designed my Beaconhandler so far, here is my code. Perhaps someone has an idea to improve it:
#import "BeaconHandler.h"
#interface BeaconHandler ()
#property (strong, nonatomic) CLLocationManager *locationManager;
#property CLProximity lastProximity;
#end
#implementation BeaconHandler
-(void) startMonitoring{
if(![self monitoringIsAllowed]){
return;
}
[self initLocationManager];
[self startMonitoringBeacons:[self beaconIDsToMonitor]];
}
-(BOOL) monitoringIsAllowed{
//TODO configuration
return YES;
}
-(NSDictionary*) beaconIDsToMonitor{
//TODO: load beacons from server
return #{#"region1":[[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6D"],
#"region2":[[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6A"]
};
}
-(void) initLocationManager{
self.locationManager = [[CLLocationManager alloc] init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
}
-(void) startMonitoringBeacons:(NSDictionary*)beacons{
for (NSString* beaconIdentifier in beacons.allKeys) {
NSUUID *beaconUUID = beacons[beaconIdentifier];
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:beaconIdentifier];
beaconRegion.notifyEntryStateOnDisplay = YES;
[self.locationManager startMonitoringForRegion:beaconRegion];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
}
[self.locationManager startUpdatingLocation];
}
//TODO replace by backend call
-(void)sendLocalNotificationWithMessage:(NSString*)message{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody =message;
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
#pragma CLLocationDelegate
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
for (CLBeacon *beacon in beacons) {
if(beacon.proximity == self.lastProximity ||
beacon.proximity == CLProximityUnknown) {
return;
}
self.lastProximity = beacon.proximity;
[self sendLocalNotificationWithMessage:[NSString stringWithFormat:#"You are inside region %#", region.identifier]];
}
}
Yes, this is possible. I can confirm I have done this successfully on iOS. A couple of tips to get it running in the background:
Get this working in the foreground first.
You only have 5 seconds of background running time after entering/exiting a region, so make sure your web service returns quickly.
Add NSLog statements to your callbacks to figure out what is and is not completing in the background.
If the above does not help, post your code in the callback.
Thanks in advance
I have IBeacon Broadcaster and receiver sample apps for ios. But Ibeacon receiver not working in some devices.
Here is my code
enter code here- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Initialize location manager and set ourselves as the delegate
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Create a NSUUID with the same UUID as the broadcasting beacon
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"A77A1B68-49A7-4DBF-914C-760D07FBB87B"];
// Setup a new region with that UUID and same identifier as the broadcasting beacon
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:#"com.appcoda.testregion"];
// Tell location manager to start monitoring for the beacon region
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
// Check if beacon monitoring is available for this device
if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Monitoring not available" message:nil delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil]; [alert show]; return;
}}
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region{
// We entered a region, now start looking for our target beacons!
self.statusLabel.text = #"Finding beacons.";
[self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion];}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region{
// Exited the region
self.statusLabel.text = #"None found.";
[self.locationManager stopRangingBeaconsInRegion:self.myBeaconRegion];}
-(void)locationManager:(CLLocationManager*)manager
didRangeBeacons:(NSArray*)beacons
inRegion:(CLBeaconRegion*)region{
// Beacon found!
self.statusLabel.text = #"Beacon found!";
CLBeacon *foundBeacon = [beacons firstObject];
// You can retrieve the beacon data from its properties
//NSString *uuid = foundBeacon.proximityUUID.UUIDString;
//NSString *major = [NSString stringWithFormat:#"%#", foundBeacon.major];
//NSString *minor = [NSString stringWithFormat:#"%#", foundBeacon.minor];}
But these codes are working in some devices
1) You try to monitor before verifying that monitoring is available.
2) I don't see any request for authorization:
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
3) For authorization to even work, you need to have a string in your plist:
NSLocationAlwaysUsageDescription
If you google around using "CLLocationManager requestAlwaysAuthorization NSLocationAlwaysUsageDescription" you will find numerous blogs with step-by-step instructions on how to get beacon tracking to work.
I am getting data from and hardware iBeacon , in which i can program to change its UUID.
I know the UUID of the hardware, but i dont understand what is the identifier in :
[[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"com.name.iBeacon"];
Is it my app identifier, or something the iBeacon is transmitting(its name?)
I wonder if this is why its not working .
I have set everything and i can't even discover the iBeacon :
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"74278BDA-B644-4520-8F0C-720EAF059935"];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"com.company.iBeacon"];
[self.locationManager startMonitoringForRegion:self.beaconRegion];
[self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion];
Than these delegates, which are in the same class(should be in app delegate?) are never fired :
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
NSLog(#"ENTER");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
NSLog(#"EXIT");
}
I have read that you have to go in and out from the area ??
Another issue is, Apple says every BLE has services,that includes characteristic, but than, in iBeacon, what are the major and minor values? characteristics of the same service ?
Got it ,
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
Must be done first .
I'm having an issue where my app will not fire the didEnterRegion event if I start the app within the region. If I start the app outside the region and then enter the region, it fires. If I start the app inside the region, then leave the region, then re-enter the region, it fires.
Any suggestions on how to get it to fire as soon as the app is opened if it's in the region would be much appreciated!
I suggest you to use this code
[locationManager requestStateForRegion:region];
And use the delegate method didDetermineState: to check if the state is CLRegionStateInside or CLRegionStateOutside.
I don't think you can do that.
But, you can get the current location and check if it's inside the region you're specifying yourself. CLCircularRegion has a containsCoordinate: method for this.
The first conclusion is that didEnterRegion is implemented consistently with its name. :)
Implement something like this in your CLLocationManagerDelegate:
- (void) locationManager: (CLLocationManager *) manager
didStartMonitoringForRegion: (CLRegion *) region
{
if ([self insideRegion: region location: manager.location])
[self locationManager: manager
didEnterRegion: region];
}
From apple's documentation:
Monitoring of a geographical region begins immediately after
registration for authorized apps. However, don’t expect to receive an
event right away, because only boundary crossings generate an event.
In particular, if the user’s location is already inside the region
at registration time, the location manager doesn’t automatically
generate an event. Instead, your app must wait for the user to cross
the region boundary before an event is generated and sent to the
delegate. To check whether the user is already inside the boundary
of a region, use the requestStateForRegion: method of the
CLLocationManager class.
So I ended up doing this:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) NSDictionary *regionDictionary;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// setup regions in case you have multiple regions
self.regionDictionary = #{#"com.test" : #"2FAE2A83-1634-443B-8A0C-56704F81A181"};
// setup location manager
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
//start monitoring for all regions
for (NSString *key in self.regionDictionary.allKeys) {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[key]] identifier:key];
[self.locationManager startMonitoringForRegion:beaconRegion];
}
}
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region {
if (region.identifier.length != 0) {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[region.identifier]] identifier:region.identifier];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
}
}
- (void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region {
if (region.identifier.length != 0) {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:self.regionDictionary[region.identifier]] identifier:region.identifier];
[self.locationManager stopRangingBeaconsInRegion:beaconRegion];
}
}
- (void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region {
// Beacon found!
CLBeacon *foundBeacon = [beacons firstObject];
NSLog(#"UUID:%#; major:%#; minor:%#;", foundBeacon.proximityUUID.UUIDString, foundBeacon.major, foundBeacon.minor);
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]] && state == CLRegionStateInside) {
[self locationManager:manager didEnterRegion:region];
}
}
- (void)locationManager:(CLLocationManager *) manager didStartMonitoringForRegion:(CLRegion *) region {
[manager requestStateForRegion:region];
}