i have been using the significant event location manager on ios, but it seems it does not based on cell change as claimed.
i used a simple application utilising significant location event, but i could not get a repeatable, consistent or sensitive response from the ios sdk.
i plotted the route (blue line), the cell towers(place mark) and a 1000m2 grid(blue square) on the map below.
map showing route
the route was 5000m in distance.
i drove it 3 times.
test1. received 2 sig events
test2. none
test3. received 1 sig events
before u complain that my test is too small, i have been monitoring other test routes for days and all show the inconsistent shape.
i was expecting the sig event to be based on cell tower switching. so i used a jailbreak app called 'signal' to identify what is the active cell. (NB.it is surprising which cell is active. Not what i would expect.)
From monitoring the 'signal' application, the cells switched around 6-7 times from what i noticed.
yet i did not received 6-7 sig events. So i cant see any correlation between cell switching and significant events.
so i have the following questions
Q1. what is the significant event trigger?
Q2. why are the result unreliable/inconsistent.
Q3. how can i get make my app receive consistent and sensitive significant event to 500m?
This is the code that is running in the test app
-(void)initLocationManager {
if (locationManager == nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[locationManager stopUpdatingLocation];
[locationManager startMonitoringSignificantLocationChanges];
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self initLocationManager];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"%#", newLocation);
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PositionUpdate" object:nil];
}
-lp
Significant Location changes are determined by iOS and there is nothing you can do to change their granularity directly. Note that it's only in iOS 4 that only the cell tower locations are used. Future versions of the operating system will improve this.
But as a workaround you could switch on normal CoreLocation position updates when the app get's woken/started by a significant location change. And then once you have the perfect result, disable Location Monitoring again to allow the app to go back to hibernation.
I just did a 3 kilometer test walk in fairly-central San Francisco with my app, and got zero Significant Change location events as well. I have a toggle in my app to change to normal polling with kCLLocationAccuracyHundredMeters and got 40+ events over the same distance.
Echoing the sentiments of various other answers herein and elsewhere, I'm holding off on Significant Change until iOS 5. I think the best thing to do right now is roll-your-own business logic to poll the old Core Location way, and ratchet frequency down gradually over time (or something) to be battery friendly.
Seems like in iOS 4, Significant Change is better suited for being able to tell which end of your commute you're at than which block (or even zip code) you're on.
I'm not sure if you have already looked at this - but the WWDC 2010 session 115 (Using Core Location in iOS) might give you a better idea of the the significant location change API.
Related
I have developed both iPhone & iPad application which supports for iOS 5 and iOS 6
in that application i have grabbed user current location using CLLocationManager.
when i want to stop updating receiving GPS coordinates. I have called stopUpdatingLocation
method to stop calling didUpdateToLocation method. It was woking completely fine with iOS 5 and 6 But unfortunately its not working with iOS 7.
Seems that stopUpdatingLocation method is not working .Any particular reason. ??
i had a keep a variable to monitor the life cycle of didUpdateToLocation method and stop executes it.
One thing might be possible is,
Your current location blue dot moving on your map is because you set the MKMapView's showsUserLocation to YES. It will track until you set it to NO.
Second thing,
You might be setting below thing to stop calling that method
locationManager = nil;
That does not stop monitoring, but what it does, not to refer the location manager, So now its not possible to stop monitoring.
Instead add below code & then see what happen
[locationManager stopUpdatingLocation];
locationManager=nil;
Hope it helps..
#tdevoy - Here is sample
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
latitude = location.coordinate.latitude;
longtitude = location.coordinate.longitude;
//stops updating current user location update
[locationManager stopUpdatingLocation];
}
Have a simple app that gets gps location. I would like to get a gps location before the app initialises. It seems for me that GPS location is updated asynchronously and I do get the app screen on the background loading while the question pops up: "allow appliction to use your current location?"
Well, how can I make a callback (sorry, coming from Ruby / JS background) to wait until I get the current location.
The code:
- (void)viewWillAppear:(BOOL)animated
{
// Set the main view to utilize the entire application frame space of the device.
// Change this to suit your view's UI footprint needs in your application.
CLController = [[CoreLocationController alloc] init];
CLController.delegate = self;
[CLController.locMgr startUpdatingLocation];
self.view.frame = [[UIScreen mainScreen] applicationFrame];
[super viewWillAppear:animated];
}
in CoreLocationController.m
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Update location");
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) {
[self.delegate locationUpdate:newLocation];
[self.locMgr stopUpdatingLocation];
# => wait initialisation until this point and than continue
You really just need to get your app up and running.
There are two things I would try (simultaneously) to handle the delay:
misdirection! Start with another screen open. Get the user interested in something else. One tap's worth of delay might be all you need to get a fix particularly if this is not a first run. On the first run when you know it will take a little time, run a little tutorial that will occupy the time.
start with the last location - this may not be right for you if inaccurate position information could be harmful but you could store the last location received when the app exits and use it as your current position when you start the app again. Of course you want to indicate that the location is a guess at best so you might want to draw your own position dot with uncertainty circle, indicating that the whole map is the uncertain area - until you get your first GPS fix and then you can begin drawing real position updates.
I think an artificial delay where you do nothing while waiting for the location to update is going to be a worse user experience than accepting that it will take a short time and trying to do as much as you can in that time.
Is it possible to make use of geo-based push notifications on iOS when the application is killed (not in the background)?
I am interested in building an app, where the user will choose a position on a map, and then if he/she for example is close to that area a local geo-based push notification would be triggered.
However is this "idea" even possible? Can the GPS run and compare coordinates when the app is killed and run and notify the user when is in place? Is there a tutorial/article/more information of any kind on the subject that i could read?
Most of the information I read online were more like general ideas of implementing without anything specific though on the matter.
For tracking a user's location while the app is not running (ie. has previously been terminated), there are two options:
From the iOS app programming guide under "Tracking the User's Location":
The significant-change location service is highly recommended for apps that do not need high-precision location data. With this service, location updates are generated only when the user’s location changes significantly; thus, it is ideal for social apps or apps that provide the user with noncritical, location-relevant information. If the app is suspended when an update occurs, the system wakes it up in the background to handle the update. If the app starts this service and is then terminated, the system relaunches the app automatically when a new location becomes available. This service is available in iOS 4 and later, and it is available only on devices that contain a cellular radio.
However, according to the CLLocationManager class reference, it's not too accurate and updates are infrequent:
Note: Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
Region Monitoring works in a similar way - including restarting the app after being terminated - but with higher accuracy (depending on availability of Wifi networks and cell towers):
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.
Another region monitoring consideration is that (according to the CLLocationManager class reference) region entry and exit notifications might only be received 3-5 minutes or so after crossing the region's boundaries.
Depending on the actual requirements, region monitoring could be used for obtaining a "rough" location and then when the user is within a specific region, start up the more accurate GPS based service on the location manager. When the user leaves the region of interest, turn off the GPS service to preserve battery and revert to the rough location monitoring service (ie. region monitoring) once again. Here's a basic implementation:
SomeViewController.m:
...
#interface SomeViewController () <CLLocationManagerDelegate>
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) CLRegion *someRegion;
#end
#implementation SomeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
CLLocationDistance radius = 10; // 10 metre sensitivity
self.someRegion = [[CLRegion alloc] initCircularRegionWithCenter:someCoordinates radius:radius identifier:#"Smithtown Dry Cleaners"];
self.locationManager.delegate = self;
[self.locationManager startMonitoringForRegion:self.someRegion];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
[self.locationManager stopUpdatingLocation];
}
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation* location = [locations lastObject];
// If the user's current location is not within the region anymore, stop updating
if ([self.someRegion containsCoordinate:location.coordinate] == NO) {
[self.locationManager stopUpdatingLocation];
}
NSString *locationData = [NSString stringWithFormat:#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude];
NSLog(#"%#", locationData);
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = locationData;
localNotification.alertAction = #"Location data received";
localNotification.hasAction = YES;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
Remember to add the appropriate entries to the application's plist file so the app will run in the background with access to the appropriate resources:
MyApp-Info.plist:
<key>UIBackgroundModes</key>
<array>
...
<string>location</string>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
...
<string>location-services</string>
<string>gps</string>
</array>
The above code assumes the use of iOS6 and ARC
I'm not getting any location callbacks on either sim or device. I've got this code being called:
- (void)startLocationCallbacks: (NSObject*) ignore
{
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = MINIMUM_METERS;
[locationManager startUpdatingLocation];
NSLog(#"[DEBUG] [locationManager startUpdatingLocation] (%#, %#)", locationManager, locationManager.delegate);
}
and log statements at the top of both
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
and
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
but neither log statement ever gets called. Location Notifications are enabled for my app (as shown in Settings, plus I said "allow.")
What are some possible reasons that I'm not getting location updates?
Config/other info:
I have allocated locationManager, and saved it in a retain property.
I have called startUpdatingLocation
I'm using 4.1 SDK
Problem is on both Sim & iPod-touch (2nd Gen) & iPhone-3, all running 4.1
Location notifications are allowed in my app (both as indicated in Settings and because I clicked "allow" in the alert.)
I've used CLLocationManager successfully before (in many shipping apps!) This is a real hair-puller for me.
Thanks!
Whew! Ok, I found it.
It turns out that one of the ways to make a CLLocationManager not fire off location callbacks is to do all the set-up in not-the-main-thread. When I moved my setup routine to a performSelectorOnMainThread, all worked exactly as expected.
What a nightmare!
Hope this answer helps others...
Edit/clarification:
Originally, I had something like this:
- (BOOL) appDidFinishLaunchingWithOptions: (NSDictionary*) options
{
// ...[app setup, snip]
[NSThread detachNewThreadSelector: #selector(postLaunchSetupThread) toTarget: self withObject: nil];
}
- (void)postLaunchSetupThread
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// ...[other setup, snip]
[self setupLocationManager];
[pool release];
}
- (void)setupLocationManager
{
self.myLocationManager = [[[CLLocationManager alloc] init] autorelease];
[myLocationManager startLocationUpdates];
}
But calling setupLocationManager in a thread prevented the callbacks. So my fix was to move the line
[self setupLocationManager];
out of the thread and back into appDidFinishLaunchingWithOptions
Actually you can run it from another thread as well.
From Apple documentation:
Configuration of your location manager object must always occur on a
thread with an active run loop, such as your application’s main
thread.
Just make sure your run loop is running on that thread, and the CLLocationManager events are dispatched.
More about run loop:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
For iOS 8
1) I placed these lines right after I init'd the location manager.
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
2) I added NSLocationAlwaysUsageDescription to the plist and set it to a string and added a message.
3) In my target, I clicked on Capabilities tab, and then turned on Background Modes and checked "Location Updates" and "Uses Bluetooth LE accessories"
This worked for me
// check out this
//...CLLocationManager does n't call delegate method properly
//...after lot of R&D I'm using a watchdog method it calls "
https://stackoverflow.com/questions/7156920/didupdatetolocation-doesnt-gets-called-immediately/14605889#14605889
In my case it was because of my device was unable to determine location - while staying indoors GPS signal was unavailable and wi-fi was also disconnected so location manager just wasn't able to receive any location data and delegate was never called.
Once I've connected wi-fi it worked (I guess moving outdoors should also do the trick in that case, but sometimes it is not very convenient way :) )
I have a few questions about CoreLocation and GPS.
First, what method in core location is used to continually get the users current coordinates? And at what interval should these be retrieved?
Second, should these coordinates be pushed into a NSMutableArray each time they are received, so that the array of coordinates will represent the users path?
Thanks, just wanting to get started getting me mind around this.
A very abbreviated version:
First, adopt the <CLLocationManagerDelegate> protocol in your .h, and #import <CoreLocation/CoreLocation.h>.
Then in .m go:
- (void)viewDidLoad {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
CLLocationCoordinate2D here = newLocation.coordinate;
NSLog(#"%f %f ", here.latitude, here.longitude);
}
Your -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation method will get pinged every time Core Location has something to say to you, which should happen every few seconds. those CLLocation objects contain info about accuracy, so you can screen for good points in that method.
Be sure to call [locationManager stopUpdatingLocation] and then [locationManager release] at some point!
Good luck finding yourself!
The best way to is read the CLLocationManager Class Reference, which links to several example projects. The short version:
Set the delegate property to a class that will receive location updates.
Implement the CLLocationManagerDelegate protocol in the delegate.
Call the appopriate methods to start updating location and/or heading.
You are able to define what range is acceptable for accuracy as well as how often you wish to receive automatic updates (based on a distance from last point mechanism). Also you can just turn off the location manager and turn it back on at will thru some use of a timer.
As for saving the locations to build a path, its not that simple. You will continually get GPS locations at first until the desired accuracy is achieved, and for any points in the future you may get more than one that is inaccurate before you get a good location. So building a list of these points will basically just be a list of their path, along with a lot of extra points.
You could solve this by saving only those points that have the accuracy you desire, but its an imperfect world in this respect.
Best case I would suggest you keep two lists, one is the path and the other is a running list of locations where you are comparing until you get a highly accurate location, then putting that on your path list.
Some of the example projects do things along these lines, do check them out.
You will have to do the following:
If device cannot access internet
Get co-ordinates from GPS device
Send these co-ordinates via SMS
Receive and decode SMS message at the SMS gateway you have to configure to receive info from device.
Update the info on the application database or any other store you are using
Update the position on map with latest info
If device can access internet
Get co-ordinates from GPS device
Connect to application server (may be some service) and upload information
Update the info on the application database or any other store you are using
Update the position on map with latest info