In the info.plist :
We have added the NSLocationAlwaysUsageDescription.
On required background modes we have added ALL the bluetooth stuff( communicate and share data with bluetooth) and the location - "register for location updates"
We have imported the location and bluetooth frameworks ,and foundation.
We are starting the bluetooth with this :
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.beaconRegion.notifyOnEntry=YES;
self.beaconRegion.notifyOnExit=YES;
self.beaconRegion.notifyEntryStateOnDisplay=YES;
[self.locationManager requestAlwaysAuthorization ];
[self.locationManager requestWhenInUseAuthorization];
NSUUID *uuid_in = [[NSUUID alloc] initWithUUIDString:uuid];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid_in identifier:#"com.name.us"];
[self.locationManager startMonitoringForRegion:self.beaconRegion];
The delegate is called :
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"started:%#",region);
//[self.locationManager requestStateForRegion:self.beaconRegion];
self.beaconRegion.notifyEntryStateOnDisplay=YES;
}
Problem is that when we turn on the hardware beacon(which is working-checked with other apps) the delegates are not being called (iPhone6):
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
A few tips:
You should only do one of these two. Get rid of the second line if you have the first line. (You also have the same first line repeated above.)
[self.locationManager requestAlwaysAuthorization ];
[self.locationManager requestWhenInUseAuthorization];
No special background modes are needed.
Bluetooth framework is not needed.
You are modifying your CLBeaconRegion before it is initialized. The lines starting with self.beaconRegion.notifyOnEntry=YES; need to be moved down to be after initialization.
Make sure the ProximityUUID defined in uuid_in actually matches your beacon. Please post the code of how this is initialized so we can help be sure.
Try uninstalling and reinstalling your app. Make sure you get prompted for location permissions on first launch and accept. If you do not get prompted, something is wrong.
Couple things to check:
In privacy settings be sure that your app is checked to Allow Location Access. I'm not certain what will happen when you call both of these in your code:
[self.locationManager requestAlwaysAuthorization ];
[self.locationManager requestWhenInUseAuthorization];
Confirm UUID are you passing to initWithProximityUUID. This will need to match the beacons you are interested in finding.
Add monitoringDidFailForRegion to your code and see what you get...
(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(error);
}
Related
My iOS app rejected from apple due to following reason :-
Your app enables the display of nearby users' locations on a map, but
does not have the required privacy precautions in place.
And they are sharing this screenshot of my app with rejection message.
In my app, I am using user’s location for showing near by events on the Map. Also I have enabled option showing user’s location on the Map.
I am using following code for setting up location services into my app.
//Declarting objects in .h file
CLGeocoder *geocoder;
CLPlacemark *placemark;
#property (nonatomic,retain) CLLocationManager *locationManager;
//Calling this method from viewDidLoad for setup location services..
-(void)getUserCurrentLocation
{
geocoder = [[CLGeocoder alloc] init];
self.locationManager=[[CLLocationManager alloc]init];
self.locationManager.delegate=self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter=kCLDistanceFilterNone;
if ([_locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[_locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
}
-(void)StopUpdateLOcation
{
if([CLLocationManager locationServicesEnabled])
{
[self.locationManager stopUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil)
{
//Saving location
[USERDEFAULT setValue:[NSNumber numberWithFloat:currentLocation.coordinate.latitude] forKey:#"CurrentLocationLatitude"];
[USERDEFAULT setValue:[NSNumber numberWithFloat:currentLocation.coordinate.longitude] forKey:#"CurrentLocationLongitude"];
//Here reverseGeocodeLocation method for fetching address from location
[self StopUpdateLOcation];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
Also I have added property “Privacy - Location When In Use Usage Description” with proper message. Also I have disabled the location service when got the location.
Not sure, why they are rejecting app. Did I miss something.?
How can I resolved this issue.?
Any help would be appreciated.
Finally, Got the proper solution for this. Thanks #Anbu.kartik for helping to findout this solution.
I have enabled the option for showing user’s location on the MAP. but didn’t wrote the failure delegate methods for handling, if user’s location not found.
So I write following delegate methods and send an app for approval again. And the app is approved by apple.
- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error{
NSLog(#"didFailToLocateUserWithError %#", error.description);
}
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error{
NSLog(#"mapViewDidFailLoadingMap %#", error.description);
}
So we must have to write failure delegates for handling errors for all the functionalities. So never happens rejection of app related this type of issues.
Hope, this is what you're looking for. Any concern get back to me. :)
Have you added this message to iTunes store description:
Continued use of GPS running in the background can dramatically
decrease battery life.
e.g: check the last line in Google Maps description:
https://itunes.apple.com/us/app/google-maps-navigation-transit/id585027354?mt=8
I want to get the current location latitude and longitude without using the map, is it possible to get like that, I am not getting that from searching the internet, can any one help me to find that.
I tried this with using the core location but even I am not got any thing.
please tell me how to find the latitude and longitude, thank you.
//remember to stop before you are done, either here or in view disappearance.
- (void) dealloc
{ [locationManager stopUpdatingLocation]; }
in .h file:
CLLocationManager *locationMgr;
in .m file:on load
locationMgr =[[CLLocationManager alloc] init];
locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
locationMgr.delegate = self;
if ([locationMgr respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationMgr requestWhenInUseAuthorization];
}
[locationMgr startUpdatingLocation];
add following delegates:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Handle location updates
CLLocationCoordinate2D location=newLocation.coordinate;
float altitude = newLocation.altitude;
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// Handle error
NSLog(#"error: %#",[error localizedDescription]);
}
may you are not authorising the location from user. thats why you are not getting anything
thanks
I'm trying to access the major and minor values for the closest beacon within the didEnterRegion delegate. However, when printing the values to the console they return null
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
if ([region isKindOfClass:[CLBeaconRegion class]]) {
CLBeaconRegion *beaconRegion = (CLBeaconRegion *)region;
int major = [beaconRegion.major intValue];
int minor = [beaconRegion.minor intValue];
NSLog(#" Major %# Minor %#", beaconRegion.major, beaconRegion.minor);
}
}
The region monitoring callback you have implemented will not tell you the individual identifiers of the beacons you detect. If you want to get the identifiers for individual beacons detected, you have to use the beacon ranging APIs as #Larme says in his comment. The callback for ranging includes a second parameter that is an array of all beacons seen.
You have to differentiate between Monitoring and Ranging iBeacons. Only successfully ranging iBeacons provides you with the Major/Minor IDs.
Looks like you are not initializing the BeaconRegion with minor and major values
While initializing the beacon region you need to use
initWithProximityUUID:major:minor:identifier:
instead of
initWithProximityUUID:identifier:
If you do not want to initialize minor and major values into regions, then you may want to call didRangeBeacons method as mentioned in the comments.
you're trying to get region's major and minor values. but you say that want to get the beacon's values.
it depends on which beacon brand you're using but there must be a method that returns the beacons array the device has found. generally the first object of the array is the closest one.
in that method you can get the beacon's values.
an example code:
- (void)beaconManager:(ESTBeaconManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(ESTBeaconRegion *)region
{
if([beacons count] > 0)
{
// beacon array is sorted based on distance
// closest beacon is the first one
ESTBeacon* closestBeacon = [beacons objectAtIndex:0];
NSString* theMajor = [NSString stringWithFormat:#"%#",closestBeacon.major];
}
}
Setup locationManager (remember to configure plist for iOS 8 to add in these 2 values NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription).
#property (strong, nonatomic) CLLocationManager *locationManager;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[[UIApplication sharedApplication] cancelAllLocalNotifications];
// Needed for iOS 8
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
Then call startRangingItem:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
if ([region isKindOfClass:[CLBeaconRegion class]]) {
[self startRangingItem];
}
}
- (void)startRangingItem {
CLBeaconRegion *beaconRegion = [self beaconRegionWithItem];
[self.locationManager startRangingBeaconsInRegion:beaconRegion];
}
- (CLBeaconRegion *)beaconRegionWithItem{
NSUUID *iPadTransmitterUUID = [[NSUUID alloc] initWithUUIDString:#"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEFFFFF1"];
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:iPadTransmitterUUID identifier:#"Transmitter1"];
return beaconRegion;
}
Then in didRangeBeacons:***
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
CLBeacon *testBeacon = [beacons objectAtIndex:0];
NSLog(#"Inside didRangeBeacons Major %# Minor %#", testBeacon.major, testBeacon.minor);
}
***Please note that this didRangeBeacons method will only run in background for 5 seconds once the user enter the region. It will stop ranging after 5 seconds. If you want to continue ranging, the user needs to launch the app. (forcing the didRangeBeacons to run in background is possible, but it might get rejected by apple)
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?
Here is what I do whenever I'm setting up an iBeacon app.
Not all these things are necessary, but it will
work
keep your user happy
(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] );
}
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.
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.
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:
The device doesn’t have the necessary hardware to support region
monitoring.
The user denied the app the authorization to use region monitoring.
The user disabled location services in the Settings app.
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
I have developed ios application which is supports for both iphone & iPad.
In that application I have integrated location tracking feature.
Here is how I implemented it.
//start monitoring for region for checked in location
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude,longtitude);
regionalMonitor = [[CLRegion alloc] initCircularRegionWithCenter:centerCoordinate radius:REGIONAL_MONITOR_RADIOUS identifier:#"checkedIn"];
[locationManager startMonitoringForRegion:regionalMonitor];
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"didEnterRegion");
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"didExitRegion");
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"Region monitoring failed with error: %#", [error localizedDescription]);
}
This methods are perfectly working in iphone application. But when I try to executes them in ipad
monitoringDidFailForRegion
method will be called. But it works perfectly in ipad simulator.
Is there any particular reason for it, or is this device oriented bug. because if I comment
[locationManager startMonitoringForRegion:regionalMonitor];
Then it will not called monitoringDidFailForRegion method
log message - Region monitoring failed with error: The operation couldn’t be completed.
Thanks
I'm pretty sure that geofencing is not supported on WiFi iPads, or at least older ones.
Try printing the value of [locationManager isMonitoringAvailableForClass:CLRegion]. If that is true (1), than it should work. Otherwise, it's unsupported on the current device.