Set location simulator City/GPX during Runtime - ios

Is there a method to programmatically change the location simulator city during runtime? For example this would allow tests to simulate London or Tokyo.
The image below shows how to switch between locations (GPX files) manually. How can I achieve this result programmatically while the app is running?

Alternate way to set location is by swizzling 'location' of 'CLLocationManager' class. In obj-c,
+(void) load {
// replace 'location' with 'custom_location' method
}
Then implement custom_location method with whatever the location you want to set by simply changing 'kMockedLatitude' and 'kMockedLongitude' variables.
//Portland, USA
CLLocationDegrees kMockedLatitude = 45.52306;
CLLocationDegrees kMockedLongitude = -122.67648;
-(CLLocation *)custom_location
{
return [[CLLocation alloc] initWithLatitude:kMockedLatitude longitude:kMockedLongitude];
}
This will work even in iOS device.

Related

Flutter app does not grab location afgsr gos is turned off then on

My application collects location data when the user presses on a certain button, but if the user turns gps option off then turns it back the location no more works even if the gps is enabled.How to handle such a thing in flutter??
As per example in this link https://pub.dartlang.org/packages/location you should put add below code in button's click event.
var location = new Location();
// Platform messages may fail, so we use a try/catch PlatformException.
try {
currentLocation = await location.getLocation;
} on PlatformException {
currentLocation = null;
}

Google Maps Start at User Location

I am using Firebase and Google Maps within my app for user accounts and for the main map view. In my app, I want it to start at the user's location and then have them be able to move the map around, but there are a few issues.
Once the user is authenticated via. Firebase, I have it try to get the users location, but it usually returns nil even when I have location services enabled for the app. Here's my code for that:
if let mylocation = mapView.myLocation {
print("User's location: \(mylocation)")
} else {
print("User's location is unknown")
}
This is in my viewDidLoad function also. I do have the code for asking permission to use location as well as the Privacy statement in my Info.plist file.
If my map happens to load and the user location is found, I try to have it center the view on the user's location. However, it can't get the user's location in time, or so it seems, and the map loads at some other location and it won't update to the user's location.
So here's my question
Is there any way to load the map and have it update to the user's location without it being stuck there for the entirety of the apps use? An example of what I want is basically a Google Maps clone where it starts at the user's location and they are able to interact with the map without it trying to consistently update the map to the user's location. If not, is there a way to wait for the location to be found before loading the map? I tried using GCD (Grand Central Dispatch), but that didn't work. I feel like that isn't my best option, waiting for the location to load before displaying the map that is, because there are many issues that could happen with it. If neither of these are options, what would you do? Thanks!
If My Location is enabled, reveals where the user location dot is being
drawn. If it is disabled, or it is enabled but no location data is available,
this will be nil. This property is observable using KVO.
Since the myLocation on the GMSMapView is observable with KVO to observe this value should solve your problem.
Here some example code:
Add self as an observer for the myLocation property of your GMSMapView instance.
self.mapview.addObserver(self, forKeyPath: "myLocation", options: NSKeyValueObservingOptions.new, context: nil)
Here you handle the changes:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let update = change, let myLocation = update[NSKeyValueChangeKey.newKey] as? CLLocation else {
return
}
self.mapView.camera = GMSCameraPosition.camera(withTarget: myLocation.coordinate, zoom: self.defaultTrackingZoom)
}
DonĀ“t forget to remove your observer somewhere e.g. deinit or viewWillDisappear
deinit
{
self.mapView.removeObserver(self, forKeyPath: "myLocation")
}
In this example the map position is getting updated every time the user position has changed. If you need that position only once at start you could add a flag like myLocationFound and check that in the observeValue:forKeyPath
Hope that helps.

Being a good citizen displaying MKRouteSteps

In lack of a better title...
I'm am writing a custom turn-by-turn implementation in an app used for tracking as well as giving directions using CLLocation and MKMapView.
Getting a route for a given address, displaying it with the returned polyline, getting an ETA and a distance and displaying those all seems fairly trivial and easily implemented. One thing that there isn't a lot of guidance on though, is how to display MKRouteStep's returned in the MKRoute object. All guides online either don't bother mentioning them, or skip over them fairly easily by simply displaying them at once in a table view. Obviously not the most gracious solution, and in my opinion a critical part that's missing.
One solution I did find (can't find the SO answer I saw it in) mentioned creating a CLRegion for each step. So I wen't ahead and created my own implementation of it:
private func drawRouteOnMap() {
viewModel.getRouteForDelivery() { route in
if let route = route {
self.polyline = route.polyline
self.mapView.addOverlay(route.polyline, level: .AboveRoads)
//Add the route steps to the currentRouteSteps array for later retrieval
self.currentRouteSteps = route.steps
//Set the routeStepLabels text property to the first step of the route.
if let step = route.steps.first {
self.routeStepLabel.text = step.instructions
}
//Iterate over the steps in the `MKRoute` object. Create each region to monitor with the identifier set to an Int
var i = 0
for step in route.steps {
let coord = step.polyline.coordinate
let region = CLCircularRegion(center: coord, radius: 20.0, identifier: "\(i)")
self.locationManager.startMonitoringForRegion(region)
i += 1
}
}
}
}
Then I can listen to the func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {} delegate method
private func updateUIForRegion(oldRegion:CLRegion) {
if let regionID = Int(oldRegion.identifier),
steps = currentRouteSteps {
//Fetch the step for the next region
let step = steps[regionID + 1]
routeStepLabel.text = step.instructions
}
}
Then when we exit the view controller
#IBAction func shouldDismissDidPress(sender: AnyObject) {
for (_, region) in locationManager.monitoredRegions.enumerate() {
locationManager.stopMonitoringForRegion(region)
}
dismissViewControllerAnimated(true, completion: nil)
}
This all works fairly well actually. But where things start to fall apart is if a user presses the home button when in the turn by turn navigation VC or if the app crashes. The app will not stop monitoring the regions set up until the locationManager is told to stop monitoring for them, even if the app is force closed. I wouldn't want the app to terminate all the region monitoring anyways, as the navigation wouldn't work when the user resumes the app. It just feels like the region monitoring isn't really the correct way to display the MKRouteStep's, but I'm out of ideas how to do it in another way.
Any ideas / better implementations are welcomed
So, first, the way that works is by definition the most elegant way - so if you have some code that handles every possibility, then by all means go for it!
With that in mind, for cases where there isn't a frank crash but your app is closed could you use one of the many delegate calls in AppDelegate to cease your monitoring?

Can you stop regions from persisting between launches with CLLocationManager?

Is there a way to prevent CLLocationManager from persisting monitored regions between launches? Every time the app is launched I need to add a new set of monitored regions and the old ones are no longer useful. Is there a way to either prevent them from persisting or clear all of the old ones at launch time?
Of course you can clear all the regions currently monitored:
+(void)clearRegionWatch
{
for(CLRegion *region in [[WGLocation shared].locationManager monitoredRegions]){
[[WGLocation shared].locationManager stopMonitoringForRegion:region];
}
}
If you had a specific identifier that you wanted to remove:
+(void)clearRegionWatchForKey:(NSString *)key
{
for(CLRegion *region in [[WGLocation shared].locationManager monitoredRegions]){
if([region.identifier isEqualToString:key]){
[[WGLocation shared].locationManager stopMonitoringForRegion:region];
}
}
}
You can copy the internals of the function into an appropriate place in your application. I've copied them from my shared manager class.
In SWIFT 4
you can stop all the regions from being monitored like
let monitoredRegions = locationManager.monitoredRegions
for region in monitoredRegions{
locationManager.stopMonitoring(for: region)
}

Get Altitude, Bearing, speed and GPS Accuracy

Hy guys, i need to find altitude, bearing and gps accuracy in my iPhone app. i've done this on my android app. in android, i did it like this :
public void onLocationChanged(Location location) {
if (isBetterLocation(location, lastValidLocation)
&& isEnable) {
lastValidLocation = location;
longitude = location.getLongitude();
latitude = location.getLatitude();
altitude = location.getAltitude();
speed = location.getSpeed();
accuracy = location.getAccuracy();
bearing = location.getBearing();
locationProvider = location.getProvider();
onPositionChanged(
LocationService.this,
new GeoPoint(location.getLongitude(), location
.getLatitude()));
}
}
how can i do the same thing in iOS ?
i've tried to get it from CLLocation, but it return null/0,0000/-1.0000 ..
btw, i get this result when i test it on iOS Simulator.
Thanks.
Regards.
The simulator is not a good place to test Core Location stuff. It only simulates a specific location but if you want to test speed, bearing etc. you're better of trying on a real device.
You need to use the class CLLocationManager (Apple doc) and fetch the data using the delegate protocol available. For example, if you want the heading you implement the method locationManager:didUpdateHeading: and call the method startUpdatingHeading on the location manager.

Resources