iOS Can not find the iBeacon again in fore ground - ios

Hi~ I'm learning to use CLLocationManager to detect iBeacon. I read this article:
http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html
It says that startRangingBeaconsInRegion will make system scan beacon every second. I test and it's right.
But a problem happens if the program only execute startMonitoringForRegion without startRangingBeaconsInRegion.
My program can find the beacon first time I start a beacon hardware, and after I stop beacon the founction didExitRegion is called. But after I start the beacon second time, program cannot find it(execute didEnterRegion) at all. I have wait for 1 hour.
The Hardware I use for test are iPhone 5s with iOS 8.1.2 and radBeacon USB.
Here is my code.
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (retain, nonatomic) IBOutlet UITextView *textView;
#property (strong, nonatomic) NSMutableString *myLog;
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) CLBeaconRegion *beaconRegion;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self startBeaconMonitoring];
}
- (void)startBeaconMonitoring {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
_locationManager.delegate = self;
[_locationManager performSelector:#selector(requestAlwaysAuthorization)];
[self userGeofencingPreferencesWereUpdatedWithNotification:nil];
[self updateLogWithString:#"start the app"];
}
- (void) userGeofencingPreferencesWereUpdatedWithNotification: (NSNotification *) notification
{
if (1) {
NSUUID *proximityUUID = [[NSUUID UUID] initWithUUIDString:#"EEF45689-BBE5-4FB6-9E80-41B78F6578E2"];
_beaconRegion = [[CLBeaconRegion alloc]
initWithProximityUUID:proximityUUID
identifier:#"1"];
_beaconRegion.notifyEntryStateOnDisplay = YES;
[_locationManager startMonitoringForRegion:_beaconRegion];
//[_locationManager startRangingBeaconsInRegion:beaconRegion];
//[_locationManager stopUpdatingLocation];
}
}
- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
[self updateLogWithString:#"enter"];
NSLog(#"enter");
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
[self updateLogWithString:#"exit"];
NSLog(#"exit");
}
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region {
//NSLog(#"range");
}
- (void)dealloc {
[_textView release];
[_myLog release];
[_locationManager release];
[_beaconRegion release];
[super dealloc];
}
- (NSMutableString *)myLog {
if (!_myLog) {
_myLog = [[NSMutableString alloc] init];
}
return _myLog;
}
- (void) updateLogWithString:(NSString*)newLog {
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"hh:mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSString * logWithTime = [NSString stringWithFormat:#"%#---%#\n",[dateFormatter stringFromDate:now], newLog];
[self.myLog appendString:logWithTime];
self.textView.text = self.myLog;
[dateFormatter release];
}
#end

I found something by accident and this solve my problem. When I use a iOS APP named Broadcaster to simulate a iBeacon, it triggers iBeacon detection APP very quickly which run on another iOS device no matter in foreground, background or screen off.
When I use Rad Beacon USB, still failure. I test all my 4 Rad Beacon USBs and same thing happens.
It seems that the BLE message sent by Rad Beacon USB is a little different from which simulated by iOS(I just tried the APP Broadcaster). And iOS8 treats them
different in some situations.
My Rad Beacon USBs are version 2.0.

Related

Hard to get the geofencing running on test phone - IOS

This is my first post every here. Woohoo.
Here is my story ... I spent about a week trying tutorials about geofencing in IOS. The problem is that i have to do it in Objective-C for now.
I am trying to get a small app to run this geofencing but i keep having problems with the actual trigger events.
I am testing it on my actual phone (iPhone 7Plus) and i can't get to make some events show on the screen whether i'm inside the region or out.
i will paste code from the .h and .m files. these are the only ones that i have implemented so far.
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate>
#property (weak, nonatomic) IBOutlet UILabel *myLat;
#property (weak, nonatomic) IBOutlet UILabel *myLon;
#property (weak, nonatomic) IBOutlet UILabel *destLat;
#property (weak, nonatomic) IBOutlet UILabel *destLon;
#property (weak, nonatomic) IBOutlet UILabel *diff;
#property (weak, nonatomic) IBOutlet UILabel *answer;
#property BOOL alwaysOn;
#property BOOL isCLickOn;
#property (retain, nonatomic) CLLocationManager *locationManager;
#end
... and this what i have in my .m file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) viewDidAppear:(BOOL)animated{
// [self showAlertMessage:#"Test" message:#"Maybe works"];
// [self showAlertMessage:#"Test" message:#"Maybe works"];
[self setupTheAuthorizations];
if(!_isCLickOn){
[self startTheRegionMonitoring];
}
// _answer.text = #"Merge";
}
- (void) setupTheAuthorizations {
_locationManager = [[CLLocationManager alloc] init];
[_locationManager requestAlwaysAuthorization];
_locationManager.delegate = self;
[_locationManager startUpdatingLocation];
//check the type of authorization
CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus];
switch (authStatus) {
case kCLAuthorizationStatusAuthorizedAlways:
// should do somethinglike getting the things started and stuff like that ...
_alwaysOn = YES;
break;
case kCLAuthorizationStatusNotDetermined:
[_locationManager requestAlwaysAuthorization];
default:
break;
}
}
- (void) startTheRegionMonitoring {
if (_alwaysOn && [CLLocationManager isMonitoringAvailableForClass:[CLRegion class]]){
CLLocationDegrees latitude = 37.972004;
CLLocationDegrees longitude = -121.293740;
CLLocationDistance radius = 200;
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(latitude, longitude);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:#"CH"];
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
_destLat.text = [NSString stringWithFormat:#"%f", latitude];
_destLon.text = [NSString stringWithFormat:#"%f", longitude];
_myLat.text = [NSString stringWithFormat:#"%f", _locationManager.location.coordinate.latitude];
_myLon.text = [NSString stringWithFormat:#"%f", _locationManager.location.coordinate.longitude];
[_locationManager startMonitoringForRegion:region];
}
_isCLickOn = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
}
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region{
NSLog(#"entered region");
if ([region.identifier isEqualToString:#"CH"]){
_answer.text = #"IN";
CLLocation *me = [[CLLocation alloc] initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
CLLocation *dest = [[CLLocation alloc] initWithLatitude:37.972004
longitude:-121.293740];
int dist = [me distanceFromLocation:dest];
_diff.text = [NSString stringWithFormat:#"%i", dist];
}
}
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region{
NSLog(#"entered region");
if ([region.identifier isEqualToString:#"CH"]) {
_answer.text = #"OUT";
CLLocation *me = [[CLLocation alloc] initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
CLLocation *dest = [[CLLocation alloc] initWithLatitude:37.972004
longitude:-121.293740];
int dist = [me distanceFromLocation:dest];
_diff.text = [NSString stringWithFormat:#"%i", dist];
}
}
- (void)locationManager:(CLLocationManager *)manager
didStartMonitoringForRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0) __TVOS_PROHIBITED __WATCHOS_PROHIBITED{
NSLog(#"Monitoring started");
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"error");
}
- (void) showAlertMessage:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[self dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
What happens is that i don't get any events showing on my phone even when the app is open. so I have a view controller on the storyboard that is supposed to show my location and destination location and to show the distance between the two objects. But it doesn't show it even if i walk 400 meters and then i walk back to the center.
I know that Swift is what I should use, and I will switch to Swift but for right now I am really wanting to understand the process that goes in this geofencing thing.
Any help will be appreciated. I am also pretty new at programming so I still have things that I am trying to learn and understand about Objective-C in particular.
Thank you.

Call Webservice on iBeacon found event in backround

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.

Can't detect iBeacon in iOS 8

I've followed online tutorials from AppCoda and Devfright to create an iBeacon detection app. I'm using an iBeacon from estimote, an iPad 3 with iOS 8. The app simply does not detect my iBeacon whereas its being detected by other iBeacon apps. I can't understand what I'm missing or doing wrong in my code.
Here's my .h file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate>
#property (nonatomic, strong) CLBeaconRegion *beaconRegion;
#property (nonatomic, strong) CLLocationManager *locManager;
#property (nonatomic, strong) IBOutlet UILabel *label1;
#property (nonatomic, strong) IBOutlet UILabel *label2;
#end
Here's my .m file:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
//default uuid for estimote beacons
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
self.beaconRegion = [[CLBeaconRegion alloc]initWithProximityUUID:uuid identifier:#"com.rk.testregion"];
[self.locManager startMonitoringForRegion:self.beaconRegion];
[self locationManager:self.locManager didStartMonitoringForRegion:self.beaconRegion];
// 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 didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region
{
// Beacon found!
self.label1.text = #"Welcome to";
self.label2.text = #"Location 1";
CLBeacon *foundBeacon = [beacons firstObject];
// retrieve the beacon data from its properties
NSString *uuid = foundBeacon.proximityUUID.UUIDString;
NSString *major = [NSString stringWithFormat:#"%#", foundBeacon.major];
NSString *minor = [NSString stringWithFormat:#"%#", foundBeacon.minor];
NSLog(#"UUID: %#", uuid);
NSLog(#"major: %#", major);
NSLog(#"minor: %#", minor);
}
- (void)viewDidDisappear:(BOOL)animated
{
[self.locManager stopRangingBeaconsInRegion:self.beaconRegion];
[super viewDidDisappear:animated];
}
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region
{
[self.locManager startRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region
{
[self.locManager stopRangingBeaconsInRegion:self.beaconRegion];
self.label1.text = #"Searching again...";
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locManager startRangingBeaconsInRegion:self.beaconRegion];
}
#end
The delegate method didRangeBeacons simply does not get called. Could someone please let me know how to fix this.
Check out the answer below, which describes some extra hoops you now need to jump through to get this working:
Location Services not working in iOS 8
Full disclosure: I have not tried this myself.

didUpdateToLocation not called in iOS GPS Library

I am trying to build a library for GPS in iOS using XCODE, But it is not working as a library, didUpdateToLocation is not called when I used in client application, but it is working fine as a application programm. I am not getting where I have done a mistake.
This is my application side code, where I have imported library code
- (void)viewDidLoad
{
[super viewDidLoad];
LocLibrary *mFunctions = [[LocLibrary alloc] init];//Creating a object
[mFunctions startGps];// Calling library method
}
Below is my LocLibrary.h
#interface LocLibrary : NSObject <CLLocationManagerDelegate>
{
CLLocationManager *locMgr;
int latitude,longitude;
}
-(void)startGps;
#property (strong, nonatomic) CLLocationManager *locMgr;
#property (strong, nonatomic) CLLocation *currentLocation;
#end
Below is LocLibarry.m code, didUpdateLocation method is not working
-(void)startGps
{
NSLog(#"getGps");
locMgr = [[CLLocationManager alloc] init];
NSLog(#"getGps1");
locMgr.delegate = self;
locMgr.distanceFilter=kCLDistanceFilterNone;
locMgr.desiredAccuracy = kCLLocationAccuracyBest;
[locMgr startUpdatingLocation];//Upto this working, it is not calling below code
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { //This method not working
self.currentLocation = newLocation;
NSLog(#"Success");
if(newLocation.horizontalAccuracy <= 100.0f)
{
[locMgr stopUpdatingLocation];
NSLog(#"Stopped");
}
}
Check below line in viewDidLoad method you are creating object Of LocLibrary2 and assigning it to LocLibrary.
LocLibrary *mFunctions = [[LocLibrary2 alloc] init];//Creating a object

Combining Beacon Monitoring with Beacon Ranging to get Major and Minor IDs on didEnterRegion Method

I am trying to get the "major" and "minor" id from the beacon that triggers a didEnterRegion method. I have been told that I can do this by combining ranging and monitoring together, but I cant seem to get it working right.
I am using the Estimote beacons and am using the Estimote API. Any ideas whats going wrong here? Thanks!
Here's a link to where it says you can combine monitoring and ranging: iBeacon: get major and minor - only looking for uuid
Setup:
#import "ViewController.h"
#import "ESTBeaconManager.h"
#interface ViewController () <ESTBeaconManagerDelegate>
#property (nonatomic, strong) ESTBeaconManager* beaconManager;
#property (nonatomic, strong) UIImageView* bgImageView;
#property (nonatomic, assign) BOOL notificationShown;
#property (nonatomic, strong) UIImageView* productImage;
#end
#implementation ViewController
ViewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.beaconManager = [[ESTBeaconManager alloc] init];
self.beaconManager.delegate = self;
self.beaconManager.avoidUnknownStateBeacons = YES;
ESTBeaconRegion* region = [[ESTBeaconRegion alloc]
initRegionWithIdentifier:#"EstimoteSampleRegion"];
[self.beaconManager startMonitoringForRegion:region];
[self.beaconManager requestStateForRegion:region];
[self.beaconManager startRangingBeaconsInRegion:region];
[[NSUserDefaults standardUserDefaults] setObject:#"FALSE"
forKey:#"connectedToBeacon"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
DidRangeBeacons:
-(void)beaconManager:(ESTBeaconManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(ESTBeaconRegion *)region {
NSString *connectedToBeacon = [[NSUserDefaults standardUserDefaults]
stringForKey:#"connectedToBeacon"];
if (connectedToBeacon == FALSE) {
NSNumber *beaconMajor = region.major;
NSNumber *beaconMinor = region.minor;
NSString *alertText = [NSString stringWithFormat:#" Entering (%#,%#)",
beaconMajor, beaconMinor];
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = alertText;
notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
[[NSUserDefaults standardUserDefaults] setObject:#"TRUE"
forKey:#"connectedToBeacon"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
I haven't yet tried using Estimote's frameworks. I've been using the Core Location framework's Core Location manager, CLBeaconRegion and CLBeacon classes, so my answer is going to be based on that.
Assuming they work the same way, the beacon ranging call passes you both an array of 1 or more beacons and the region they match.
The major and minor version values in the region will be nil unless you set up the regions with those values.
The major and minor values in the beacon objects, however, will contain the major and minor numbers of the beacons you've actually detected. If you are currently detecting more than one you have to come up with logic that picks one. What I've done is to loop through and select the closest one (using accuracy) who's proximity is not unknown.
(EDITED to correct a few typos)

Resources