Im developing an app using beacons. i have multiple beacons within a location and I need to recognise all the beacons.
I have created multiple regions for every beacon.
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:bID];
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"com.test.iBeacon];
[self.locationManager startMonitoringForRegion:region];
The problem is only the last beacon region is getting recognized. The other beacons are not recognized. Should the beacons have same UUID and different major minor??
Two things to consider:
First of all, you can only register up to 20 region to monitor
Last but not least, each of you region must have a different identifier (you can't use 20 times #"com.test.iBeacon")
Related
I know that an iBeacon cannot broadcast/advertise in the background and I also know that its not possible for both the central and the peripheral to be in the background and discover each other. What I want to do is broadcast while in the background so that the central can discover the app while in the foreground. I'm sorry if I'm not explaining this well, please ask for clarification if I'm not clear.
I read here that "apps preform differently when running in the background as opposed to the foreground". On page 37-38 it describes what is different in the background for peripherals. It mentions "service UUIDs contained in the value of the CBAdvertisementDataServiceUUIDsKey advertisement key are placed in a special “overflow” area; they can be discovered only by an iOS device that is explicitly scanning for them." What is an overflow area and how do you explicitly search for the device? All I need is the major/minor values and the RSSI. I don't want to connect to the peripheral, I just want to interact with it as if it were an iBeacon.
Also, I need to be able to discover multiple devices (all with the same UUID) but all with unique major/minor values.
Here's my code:
var locationManager: CLLocationManager!
var beaconRegion: CLBeaconRegion!
var centralManager: CBCentralManager!
override func viewDidLoad() {
locationManager = CLLocationManager()
locationManager.delegate = self
centralManager.delegate = self
let majorVal: CLBeaconMajorValue = 123
let minorVal: CLBeaconMinorValue = 456
let uuid = NSUUID(UUIDString: "00000000-0000-0000-0000-000000000000")
beaconRegion = CLBeaconRegion(proximityUUID: uuid,identifier: "beacon")
locationManager.startRangingBeaconsInRegion(beaconRegion)
locationManager.startUpdatingLocation()
}
Then I just handle the distance to the beacon and record it's major/minor values.
This question is very similar to mine; the only difference is he wanted both devices to work in the background and I only need the peripheral to work in the background not the central.
How do I broadcast in the background and then discover in the foreground?
Thanks for your help!
Unfortunately, you cannot do this. Two things prevent this from working:
An app advertising as an an iBeacon and scanning for other iBeacons will not detect its own transmission. This is not an iOS thing, it is a Bluetooth thing. Bluetooth scans do not detect advertisements originating from the same device.
If you transmit an iBeacon advertisement from an app in the background, it breaks the advertisement format so it no longer is recognizable as an iBeacon transmission. This is caused by the same iOS functionality that moves service uuids to the "overflow area" when in the background. See here for more info.
I have an iOS app which is a tabbed application, with 3 view controllers, all of which need to know when the phone enters specific geographical regions.
The regions which we monitor for are supplied at run time over a web interface, so we need to periodically clear the regions that the CLLocationManager is monitoring for and add new ones. The CLLocationManager object is a member variable of a singleton class which manages the connection with the web server as well.
The problem that I have is that when the application is first installed, the region monitoring works fine. But the first time I try to run it after that first time, the region monitoring does not work.
I can see this on both the actual handset and the iOS simulator.
On receipt of the mesasge from the server which contains the region details, we run the following code:
-(void) initialiseLocationManager:(NSArray*)geofences
{
if(![CLLocationManager locationServicesEnabled])
{
NSLog(#"Error - Location services not enabled");
return;
}
if(self.locationManager == nil)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
}
else
{
[self.locationManager stopUpdatingLocation];
}
for(CLRegion *geofence in self.locationManager.monitoredRegions)
{
//Remove old geogate data
[self.locationManager stopMonitoringForRegion:geofence];
}
NSLog(#"Number of regions after cleanup of old regions: %d", self.locationManager.monitoredRegions.count);
if(self.locationManager == nil)
{
[NSException raise:#"Location manager not initialised" format:#"You must intitialise the location manager first."];
}
if(![CLLocationManager regionMonitoringAvailable])
{
NSLog(#"This application requires region monitoring features which are unavailable on this device");
return;
}
for(CLRegion *geofence in geofences)
{
//Add new geogate data
[self.locationManager startMonitoringForRegion:geofence];
NSLog(#"Number of regions during addition of new regions: %d", self.locationManager.monitoredRegions.count);
}
NSLog(#"Number of regions at end of initialiseRegionMonitoring function: %d", self.locationManager.monitoredRegions.count);
[locationManager startUpdatingLocation];
}
I have tried calling [locationmanager stopUpdatingLocation] in various places, in particular in various places in the AppDelegate.m file (applicationWilLResignActive, applicationDidEnterBackground, applicationWillTerminate), but none of them seem to help. Either way, when I build my application and add a GPX file to simulate locations, the simulator correctly picks up the regions being sent by the web interface. The second time I run the program, the regions are not picked up. When I reload the GPX file, it works again, but from the second time onwards, it doens't work any more.
According to the API documentation, the CLLocationManager keeps a record of regions even on termination (which is why I clear down the regions which we monitor for), but my guess is that my initialisation routine is good for the first time the app runs, but calls things that shouldn't be called from the second time onwards. Also, the clearing down process doesn't always seem to work (the NSLog statement often shows the CLLocationManager clearing down to 0 regions, but not always).
Any ideas why this isn't working?
So lets clean this up a little bit
You dont need to call startUpdatingLocation and stopUpdatingLocation when using region monitoring. Those activate the standard location tracking sending messages to the delegate callback locationManager:didUpdateLocations:. Region tracking apps implement these delegate callbacks:
– locationManager:didEnterRegion:
– locationManager:didExitRegion:
Also its very unlikely that location services will become disabled in the course of this method and you should make sure its not possible to get rid of the 'locationManager' from a background thread. Therefore we dont need to check them twice.
As you are region monitoring its best to make sure you have region monitoring available with + (BOOL)regionMonitoringAvailable. Also best to check the location permissions with + (CLAuthorizationStatus)authorizationStatus at some point and react appropriately.
As per this blog post it seems you also need to have
UIBackgroundModes :{location}
UIRequiredDeviceCapabilities: {location-services}
in your apps info.plist for this all to work correctly.
If you have more information about the mode of failure i can come back with some more specific advice :)
I am new to iOS.
I am making one app using GPS location update.
I am fetching current location and update location to server.
I want to get every change in meter and update it to server.
Here is the code i am using:
locationManager = [[CLLocationManager alloc] init] ;
locationManager.delegate = self; // send loc updates to myself
locationManager.distanceFilter = 1.0f; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
But the location is not updating after every meter. It updates but not regularly.
Thanks for Help!
It doesn't work like that. AGPS, which is what iPhone uses, has limited accuracy which depends on many factors. It uses GPS, Wi-Fi and Cell Towers triangulation and at any given moment it can use any combination of these. So, when GPS signal is lost and there is no Wi-Fi hotspots around you could be getting location based on Cell Towers location which is very inaccurate (a few hundred meters). It could be worse than that, you could be getting cached location which is nowhere near your current location. And even when you have GPS signal you can't expect to get 1 meter accurate location everywhere you go. GPS accuracy itself depends on many factors.
Use kCLLocationAccuracyBestForNavigation always. There is no real battery usage difference between that and kCLLocationAccuracyBest, they both use the GPS at top speed. The main difference is in the post-processing that Apple does.So you can try the kCLLocationAccuracyBestForNavigation.
I have code that creates a geofence on my iPhone that will trigger some code to be executed when didExitRegion gets called. However, I have found that when I have WiFi switched off that didExitRegion never gets triggered.
Is WiFi required for monitoring region changes on iOS?
My desired accuracy is set to kCLLocationAccuracyHundredMeters.
I am testing on iOS 6.1 and iPhone 4.
Here is my code for setting up location monitoring:
- (id)init {
self = [super init];
if (self) {
CLLocationManager *manager = [[CLLocationManager alloc] init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
manager.distanceFilter = RADIUS/10.0;
manager.headingFilter = kCLHeadingFilterNone;
self.locationManager = manager;
self.authorizationStatus = [CLLocationManager authorizationStatus];
}
return self;
}
Thanks
iOS devices use three methods to discover user location. From (usually) most accurate to least accurate they are:
GPS hardware
By identifying nearby wifi networks
Cell Tower Triangulation
If your app doesn't use GPS or is not running (ie. has previously been terminated), the device will attempt to use methods 2 and 3 above to locate the user. So the device's ability to locate the user (when the GPS hardware is not in use or there is a weak GPS signal) depends on the availability of wifi networks and cell towers. The more wifi networks and cell towers, the better the location accuracy. Therefore, when a user enters or exits a monitored region (ie. crosses a "geofence"), it is impossible to predict exactly when the user will receive the notification if at all. (Of course, if the region in question is always the same, the device will more or less locate the user with the same degree of accuracy on each occasion).
Here's the relevant documentation from the Location Awareness Programming Guide:
The specific threshold distances are determined by the hardware and the location technologies that are currently available. For example, if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.
So, wifi is not required for region monitoring to work, but with it enabled, your device will have a better chance in determining whether or not the user has crossed a region's geofence.
If you turn off WiFi, your location accuracy lowers. If you don't have GPS signal(inside some buildings), you will not get any location updates. Have you tried this when you are outside, or if you used the location simulator to test?
Also, WiFI is not required for geofence function if you have GPS(iPhones or iPad with sims).
Weird weird stuff can happen without wifi using core location. To help in your case I would get rid of the distance filter, that can mess with things and it is not very helpful. I would probably only use kCLLocationAccuracyBest for anything where I need the accuracy required to set up a geofence. Using other accuracies and filters for me would sometimes through the gps meter off by 1000 meters and take a minute or two to correct itself. If this is too much battery then set up a system where it turns off and on based on how far away it is from the fence.
So I have an iPhone app which should aid the user to find a convenient walkway from his/her own position to a given destination. As I have learnt, MKMapView does not provide an easy way to infer a preferred walking route from A to B.
I can live with terminating my own app and launch the native map application on the iPhone, but in that case I would like to equip the map application with two coordinates so that the user can find his/her way.
Any suggestions to how I should go about this task?
To launch the native map app use:
NSString *googleMapsURL = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f&daddr=%1.6f,%1.6f",
start.latitude, start.longitude, destination.latitude, destination.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:googleMapsURL];
where start is the user location and destination is, well, the destination. For walking directions, you can add &dirflg=w (still in beta according to wiki). Here are some more parameters you can use.