Lena Bru
Lena Bru

Reputation: 13937

Why doesn't it find my beacons?

I am writing both Android and iOS apps which need to find BLE beacons around the device.

When I run my code from Android, it finds several beacons in the room I am in.

I have 8 beacons.

When I run the beacon code from iPhone, it returns a list of exactly 0 beacons.

Here is my code:

    - (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    [self initRegion];
    [self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

- (void)initRegion {
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BEACONUUID];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:BEACONIDENTIFIER];
    [self.locationManager startMonitoringForRegion:self.beaconRegion];

}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    NSLog(@"Beacon Found");
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    NSLog(@"Left Region");
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
    self.beaconFoundLabel.text = @"No";
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    CLBeacon *beacon = [beacons lastObject];//<== is always 0

    self.beaconFoundLabel.text = @"Yes";
    self.proximityUUIDLabel.text = beacon.proximityUUID.UUIDString;
    self.majorLabel.text = [NSString stringWithFormat:@"%@", beacon.major];
    self.minorLabel.text = [NSString stringWithFormat:@"%@", beacon.minor];
    self.accuracyLabel.text = [NSString stringWithFormat:@"%f", beacon.accuracy];
    if (beacon.proximity == CLProximityUnknown) {
        self.distanceLabel.text = @"Unknown Proximity";
    } else if (beacon.proximity == CLProximityImmediate) {
        self.distanceLabel.text = @"Immediate";
    } else if (beacon.proximity == CLProximityNear) {
        self.distanceLabel.text = @"Near";
    } else if (beacon.proximity == CLProximityFar) {
        self.distanceLabel.text = @"Far";
    }
    self.rssiLabel.text = [NSString stringWithFormat:@"%ld", (long)beacon.rssi];
}

In my didRangeBeaconsInRegion, the beacons NSArray always comes up with 0 objects. Though I have 8 objects. And i've downloaded several apps that are not mine, and they all see several of my beacons.

Why doesn't my code see any of my beacons?

Upvotes: 0

Views: 3799

Answers (4)

Jonathon Hibbard
Jonathon Hibbard

Reputation: 1546

Here is what I do whenever I'm setting up an iBeacon app.

Not all these things are necessary, but it will

  1. work
  2. keep your user happy
  3. (maybe most importantly) keep Apple happy

iOS 8+ Only

First things first: if you're using iOS 8, you need to make sure you actually have access before using CLLocationManager.

CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;

// You can either use requestAlwaysAuthorization, or requestWhenInUseAuthorization
[self.locationManager requestAlwaysAuthorization];

You'll also need an entry for NSLocationAlwaysUsageDescription in your plist (again, iOS 8 only )


iOS 7+

Your App's pList

Regardless you're using iOS 8 or 7, you should add the following to your plist file (you need to decide if you'll use background or not).

Note: The below is in the form of KEY : KEY TYPE : VALUE for string, and KEY : KEY TYPE : [ Value1, Value2... ] for Arrays:

NSLocationUsageDescription : String : "Gimmie access to your location or else..."
NSBluetoothPeripheralUsageDescription : String : "Gimmie access to your blue tooth or else"

// Optionally supply if you need background modes.  I don't believe you need this either if you plan to turn these options on using the Capabilities section of your App's Settings (see below section)
UIBackgroundModes : Array : [ location, bluetooth-central ]
UIApplicationExitsOnSuspend : Boolean : NO



Your App's Project Settings (Capabilities)

this section has been removed as this can cause your app to be rejected (as noted by @heypiotr in the comments)


Final Thoughts

A final suggestion would be to try moving [self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion] into your viewDidAppear.

Here is an example of what I typically do ( which works quite well for me ).

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [self initLocationManager];
    [self initBeaconRegion];
    [self startMonitoring];
}

-(void)initLocationManager {

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    // Not necessary, but I like to do it.
    if( ![CLLocationManager locationServicesEnabled] ) {
        [self.locationManager startUpdatingLocation];
    }

    // Only necessary if you're in iOS 8.  Checking for existence though to support iOS 7
    if( ![CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized ) {
        if ([CLLocationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
            [self.locationManager performSelector:@selector( requestAlwaysAuthorization )];
        }
    }
}

-(void)initBeaconRegion {

    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kYOUR_UUID_HERE];

    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:kYOUR_IDENTIFIER_HERE];

    // Change this to whatever you want....
    self.beaconRegion.notifyEntryStateOnDisplay = YES;
    self.beaconRegion.notifyOnEntry = NO;
    self.beaconRegion.notifyOnExit = YES;
}


# pragma mark -
# pragma mark Monitoring Beacons
# pragma mark -

-(void)startMonitoring {
    // Monitor Beacon signals around me and report them back to me
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
}

The last part ( placement in viewDidAppear ) may or may not help - it all depends I guess on too many factors to consider in a stackoverflow response.

Hope that helps and good luck!

Final Edit

Forgot one more thing that may help. There are some helpful methods that you can implement that can help you debug the issue further. Here is an example of a few of them:

#pragma mark Authorization Status Changed
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {

    if( ![CLLocationManager locationServicesEnabled] ) {
        NSLog(@"Couldn't turn on ranging: Location services are not enabled.");
    } else {
        NSLog(@"Location services ARE enabled.");
    }

    if( [CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized ) {
        NSLog(@"Couldn't turn on monitoring: Location services not authorized.");
    } else {
        NSLog(@"Location services ARE authorized.");
    }
}


#pragma mark -
#pragma mark CLLocationManager Errors
#pragma mark -

-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog( @"FAIL ERROR: %@", [error description] );
}

-(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion (CLBeaconRegion *)region withError:(NSError *)error {
    NSLog( @"RANGE BEACONS ERROR: %@", [error description] );
}

Upvotes: 2

jofi123
jofi123

Reputation: 31

Please check this note from apple

Before attempting to monitor any regions, your app should check whether region monitoring is supported on the current device. Here are some reasons why region monitoring might not be available:

  1. The device doesn’t have the necessary hardware to support region monitoring.
  2. The user denied the app the authorization to use region monitoring.

  3. The user disabled location services in the Settings app.

  4. The user disabled Background App Refresh in the Settings app, either for the device or for your app.

5.The device is in Airplane mode and can’t power up the necessary hardware.

In iOS 7.0 and later, always call the isMonitoringAvailableForClass: and authorizationStatus class methods of CLLocationManager before attempting to monitor regions. (In OS X v10.8 and later and in previous versions of iOS, use the regionMonitoringAvailable class instead.) The isMonitoringAvailableForClass: method tells you whether the underlying hardware supports region monitoring for the specified class at all. If that method returns NO, your app can’t use region monitoring on the device. If it returns YES, call the authorizationStatus method to determine whether the app is currently authorized to use location services. If the authorization status is kCLAuthorizationStatusAuthorized, your app can receive boundary crossing notifications for any regions it registered. If the authorization status is set to any other value, the app doesn’t receive those notifications. Apple link goes here

Upvotes: 0

Sunny Shah
Sunny Shah

Reputation: 13020

First check with the other app like.Locate app add your UDID and check this app is showing your iBeacon. if not then there is a problem with apple IOS sometimes. then remove the app. Restart the app. it will work for you.

Upvotes: 1

jefftang
jefftang

Reputation: 104

We had similar problem before, make sure your iBeacon device respond the scan request from iOS with a response DOES not contain manufacturer specific field.

Upvotes: 0

Related Questions