Swift iOS GoogleMaps CLLocationManager didUpdateLocations not updating camera - swift

I'm new to iOS and am building a very simple iOS using swift 5.7.2 and XCode 14.2.
The app basically needs to show a Google Map View as the user's device travels around. I have successfully made the view and enabled location service and the Map now shows my location on the map. The blue icon also tracks my location as I move around.
However, even though the blue icon representing my position moves around, the map itself doesn't move around and that can result in my position being outside of the map if I have travelled far enough.
My UIViewController is:
import UIKit
import AVKit
import GoogleMaps
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var manager: CLLocationManager?
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager?.delegate = self
manager?.desiredAccuracy = kCLLocationAccuracyBest
manager?.requestAlwaysAuthorization()
manager?.startUpdatingLocation()
let currentCoordinate = manager?.location?.coordinate
let viewBounds = self.view.bounds
let screenCenter = CGPoint(x: viewBounds.midX, y: viewBounds.midY)
let camera = GMSCameraPosition.camera(withLatitude: currentCoordinate?.latitude ?? 51.0447, longitude: currentCoordinate?.longitude ?? -114.0719, zoom: 9.0)
let navView = GMSMapView.map(withFrame: CGRect(x: 130, y: 10, width: viewBounds.maxX - 135 * 2, height: viewBounds.maxY - 20), camera: camera)
navView.isMyLocationEnabled = true
self.view.addSubview(navView)
}
}
And the app looks like:
What I think is wrong:
I am not using didUpdateLocations of locationManager to update the camera position as I am not sure what's the proper way of doing it. Throwing this code inside UIViewController doesn't work:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue:CLLocationCoordinate2D = manager.location!.coordinate
print(locValue)
}
What's the proper way of doing it?
Thanks!

The signature is wrong (it's Swift 2 outdated for a long time).
Please have a look at a the documentation, the current signature is
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last!
print(location.coordinate)
}
and the updated locations are in the locations parameter.
And to avoid the optional replace
var manager: CLLocationManager?
with
let manager = CLLocationManager()
and remove manager = CLLocationManager() and the question marks

Related

Obtaining user location not functioning in Xcode

Good evening, I am trying to allow users to locate themselves on a map. When I run the app and access my google maps view, I get the error message "this app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an “NSLocationWhenInUseUsageDescription” key with a string value explaining to the user how the app uses this data" and the map is set a default state.
I have put
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs your current location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your current location</string>
in my info.plist, but it tells me that I need to put in NSLocationWhenInUseUsageDescription in order to access location. I already have put it in and it still won't show the user location! Am I leaving something out or is this a bug? it worked fine for me before I updated to the newest version of Xcode.
My code that enables google maps is as follows,
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationManager.delegate = self
locationManager.stopUpdatingLocation()
let location = locations.last
let lat = (location?.coordinate.latitude)!
let long = (location?.coordinate.longitude)!
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 17.0)
self.myMapView.animate(to: camera)
showPartyMarkers(lat: lat, long: long)
}
func initGoogleMaps() {
let camera = GMSCameraPosition.camera(withLatitude: 40.014281, longitude: -83.030914, zoom: 17.0)
self.myMapView.camera = camera
self.myMapView.delegate = self
self.myMapView.isMyLocationEnabled = true
}
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
let lat = place.coordinate.latitude
let long = place.coordinate.longitude
showPartyMarkers(lat: lat, long: long)
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 17.0)
myMapView.camera = camera
txtFieldSearch.text=place.formattedAddress
Add new records in your new InfoPlist.strings file.
<key>NSLocationAlwaysUsageDescription</key>
<string>app need your location for finding a place</string>
add lines in viewdidload
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
delete your app from simulator and run again.
Add below keys in plist.
Privacy - Location Always and When In Use Usage Description
Privacy - Location When In Use Usage Description
EDIT
I am not seeing Initialisation for locationManager.
Use below code to initialise:
/// CLLocationManager object
var locationManager: CLLocationManager = {
let manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
return manager
}()
After Init start updating location, for that add below lines in viewDidload
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
I found the answer after reposting the question. If anyone is having this issue as well, what you want to do is click on your projects target build settings, click on info (Left of build settings) and you want to make sure the Custom iOS Target Properties have the same info as your regular p-list. If it does not, simply click the plus sign, and add them in. This should fix the problem because it has with mine. I hope you all find this useful.

Google Maps strange behavior swift 4 ios

Update: Dose it have to do anything with language? as my app is sporting English and Arabic.
Hi everyone I am struggling with this since days and I have tried everything but can not find any solution, the problem is when I run the app through xCode it all works fine like in the following screenshot.
Then when i unplug the device and reopen the app it stops working, the app is running fine but i dont see any map but just the markers like the following screenshot.
Any help will be appreciated.
AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GMSServices.provideAPIKey(googleApiKey)
GMSPlacesClient.provideAPIKey(googleApiKey)
return true
}
ViewController
//Step 1
#IBOutlet weak var mapview: GMSMapView!
//Step 2
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.mapview.settings.scrollGestures = true
self.mapview.settings.zoomGestures = true
self.mapview.isMyLocationEnabled = true
self.mapview.settings.myLocationButton = true
self.mapview.delegate = self
self.mapview.layoutIfNeeded()
}
}
//Step 3 After we have the current location items are loaded from server by user location and the markers are added in GetBusinesses function
extension ItemsList: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard status == .authorizedWhenInUse else {
return
}
self.locationManager.startUpdatingLocation()
self.mapview.camera = GMSCameraPosition(target: (self.locationManager.location?.coordinate)!, zoom: 14, bearing: 0, viewingAngle: 0)
self.GetBusinesses(data: "&isOpen=2&cat=\(Prefrences.getSelectedCategoryId())")
}
}
to show map in custom views you have to do it that way,
let camera = GMSCameraPosition.camera(withLatitude: lat , longitude: long, zoom: 15.0)
let mapView = GMSMapView.map(withFrame: CGRect(x: 2, y: 2, width: self.MapView.frame.width - 4, height: self.MapView.frame.height - 2), camera: camera)
self.MapView.addSubview(mapView)
self.MapView.clipsToBounds = true
self.MapView.contentMode = .center
you need to create a mapView using the created mapView on the storyboard frame and add it as a subView in the main MapView you created
Okay so after struggling many days and trying every stupid possible way to fix it, I finally found a solution to it. The main problem was if your app is supporting multiple languages then google map will show this kind of behaviour. Following are the steps to fix it.
Step 1:
If you have the GMSMapView view in your viewController, break the outlets of your GMSMapView since it will be created dynamically.
Step 2:
Set the application language as per the user settings.
Step 3:
Create custom GMSMapView object set delegate methods and other necessary settings and add it to its container.
That's it, you are good to go. What I understood from this is that you have to set your app language first before creating the GMSMapView (I can be wrong as well). If anyone knows why this method is working kindly explain it.
//Our Custom MapView Var
var mapview: GMSMapView!
//View viewDidLoad() function
override func viewDidLoad() {
super.viewDidLoad()
/*
TODO:
Get selected language from preferences and set accordingly.
*/
UserDefaults.standard.set(["en"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
let camera = GMSCameraPosition.camera(withLatitude: 55.277397,
longitude: 25.199514,
zoom:12)
self.mapview = GMSMapView.map(withFrame: self.mMapContainer.bounds, camera: camera)
self.mapview.delegate = self
self.mapview.isMyLocationEnabled = true
self.mapview.settings.myLocationButton = true
self.mapview.isMyLocationEnabled = true
self.mapview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mMapContainer.addSubview(self.mapview)
}

SWIFT: How to make an app zoom to your current location on launching?

I'm trying to build an app that when you open it it zooms to your current location. Below is my code so far.
class MapVC: UIViewController {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
mapView.zoomToUserLocation()
}
}
extension MKMapView {
func zoomToUserLocation() {
print(userLocation.location?.coordinate)
guard let coordinate = userLocation.location?.coordinate else { return }
let region = MKCoordinateRegionMakeWithDistance(coordinate, 10000, 10000)
setRegion(region, animated: true)
}
}
This code does not solve the problem. I believe this is because the app doesn't have time after receiving location authorisation to obtain the user location. I'm looking to write a function that would wait for the app to have a location and then call the zoomToUserLocation function. I've already tried this with a do-while loop which didn't work. I could set a delay but that would mean the zoom was done at a specific time and instead I want the zoom to be done as soon as possible. I've found solutions to this in objective C but couldn't translate it.
This method might be helpful setUserTrackingMode(_:animated:), but I think that's not what you are looking for.
The solution that may fit best for you is to implement locationManager(_:didChangeAuthorization:) and locationManager(_:didUpdateLocations:) on the CLLocationManager's delegate. Then you call zoomToUserLocation() in didUpdateLocations.
Another observation, is that you shouldn't animate the map inside viewDidLoad() 'cause the view it not on screen yet. This should be done in viewDidAppead().
you need both a span and a region...the span allows you to set how far you want to zoom in...
let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
if let center = location?.coordinate {
let region = MKCoordinateRegion(center: center, span: span)
self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true

Printing user location distance in meters from marker every X seconds with Timer, in Swift 3

Disclaimer: very beginner level coder here, so excuse any "obvious" mistakes.
I am trying to build an app that shows to user how close they are to a marker.
I have a GoogleMaps map view and I want to refresh user location continuously (every say 3 seconds). calculate and print its linear distance (in meters) from the marker, and set that to my left navigation item button.
I tried doing this through GoogleMaps to no avail. So tried with CLLocation and CoreLocation.
Problem is, I get first value in meters (15m), second value (9m) 3 seconds later, then every other 3 second iteration of my timer only gives 9m forever, no matter if I move around (and my googlemaps view does update successfully the blue user position dot as I move around, laptop and linked ipad in hand).
What I am doing is have my timer fire off "findDistance" function every 3 seconds. The "findDistance" function runs locationmanager (which sets globalUserLocation to current one - if I am not doing something wrong), calculates distance and sets it to GlobalDistance, then updates the left navigation button item to that new distance.
But it seems like the user location is only updated twice (instead of every 3 seconds, forever).
What am I doing wrong? Any help would be greatly appreciated
I have added all the plist requirements, and here is my code:
import UIKit
import GoogleMaps
import CoreLocation
import MapKit
class googleMaps: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let locationmanager = CLLocationManager()
var globalDistance: CLLocationDistance = 0
var mapView: GMSMapView? = nil
var globalUserLocation = CLLocation(latitude: 40.085260, longitude: 22.601468)
override func viewDidLoad() {
super.viewDidLoad()
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(googleMaps.findDistance), userInfo: nil, repeats: true)
self.locationmanager.delegate = self
self.locationmanager.desiredAccuracy = kCLLocationAccuracyBest
self.locationmanager.startUpdatingLocation()
timer.fire()
GMSServices.provideAPIKey("**mykeyhere**")
let camera = GMSCameraPosition.camera(withLatitude: 40.085260 , longitude: 22.601468, zoom: 40)
mapView = GMSMapView.map(withFrame: CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 200, height: 500)), camera: camera)
mapView?.isMyLocationEnabled = true
view = mapView
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "\(globalDistance)", style: UIBarButtonItemStyle.plain, target: self, action: #selector(googleMaps.next as (googleMaps) -> () -> ()))
mapView?.mapType = kGMSTypeNormal
self.mapView?.settings.myLocationButton = true
self.mapView?.settings.compassButton = true
}
func locationmanager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
globalUserLocation = locations.last!
}
func findDistance(){
locationmanager
let currentLat = locationmanager.location!.coordinate.latitude
let currentLong = locationmanager.location!.coordinate.longitude
globalUserLocation = CLLocation(latitude: currentLat, longitude: currentLong)
let myMarker = CLLocation(latitude: 40.085260, longitude: 22.601468)
if globalUserLocation != nil {
let distance = globalUserLocation.distance(from: myMarker)
print(distance)
globalDistance = distance
navigationItem.leftBarButtonItem?.title = "\(globalDistance)"
}
}

Wrong Location - located in San Francisco and not in France

I am in France, and when I try my new func locationManager function, my map view locate me in San Francisco. Any idea?
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled())
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let location = locations[locations.count-1] as CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.map.setRegion(region, animated: true)
}
I am using the simulator.
The iOS Simulator defaults to US - San Fran, and does not give you an estimate of your Mac's actual location.
However you can simulate movement or even a specific location like so:
Under the Debug menu in the Simulator, the last entry is "Location"; this gives you a sub menu with:
None
Custom Location
Apple Stores
Apple
City Bicycle Ride
City Run
Freeway Drive
Custom Location lets you enter a Lat/Long value.
Bicycle ride, City Run, and Freeway Drive are simulation of a moving location (in Cupertino, of course).
In addition to Woodstock's answer, you can also set a default location in the scheme. It's in Run/Options. There's an option to allow Location simulation and a bunch of standard defaults you can use for testing. For even more option, you can add a GPX file to your project.