MapBox didUpdateUserLocation is never called - swift

I'm trying to respond to changes in the user's location in an iOS app using MapBox, but didUpdateUserLocation is not being called. Why isn't didUpdateUserLocation being called?
ViewController.swift
import UIKit
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
#IBOutlet weak var upButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let styleURL = NSURL(string: "mapbox://styles/jmeyers919/cj8w00yxvfrqr2rpehxd47up1") // MGLStyle.darkStyleURL()
let mapView = MGLMapView(frame: view.bounds, styleURL: styleURL as URL?)
mapView.delegate = self
mapView.logoView.isHidden = true
mapView.attributionButton.isHidden = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Note that we have changed the center coordinate to New York City for this guide
// mapView.setCenter(CLLocationCoordinate2D(latitude: 44.0475276, longitude: -123.08927319), zoomLevel: 16, animated: false)
mapView.userTrackingMode = .follow
mapView.showsUserLocation = true
view.addSubview(mapView)
self.view.bringSubview(toFront: self.upButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(mapView: AnyObject!, didUpdateUserLocation userLocation: AnyObject!) {
print("didUpdateUserLocation")
}
}

While the showsUserLocation property is set to YES, this method is called
whenever a new location update is received by the map view. This method is also
called if the map view’s user tracking mode is set to
MGLUserTrackingModeFollowWithHeading and the heading changes, or if it is set
to MGLUserTrackingModeFollowWithCourse and the course changes.
This method is not called if the application is currently running in the background. If you want to receive location updates while running in the
background, you must use the Core Location framework.

Related

Is it possible to run 2 independent ARSessions simultaneously?

Since ARKit3 it is possible to run a ARSession() that supports the back and front camera simultaneously.
For example this creates an ARConfiguration for the front camera that supports also Worldtracking.
// session for the front camera
let configuration = ARFaceTrackingConfiguration()
configuration.isWorldTrackingEnabled
sceneView.session.run(configuration)
This example creates a configuration for a back camera session with Face Tracking enabled:
// session for the back camera
let configuration = ARWorldTrackingConfiguration()
configuration.userFaceTrackingEnabled = true
sceneView.session.run(configuration)
I would like to create 2 independent ARConfigurations and ARSessions that run simultaneously. Like this:
So far i tried this code:
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
// back camera view
#IBOutlet var backView: ARSCNView!
// front camera view
#IBOutlet weak var frontView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
frontView.delegate = self
// Create a new scene for back camera
let scene = SCNScene(named: "art.scnassets/ship.scn")!
backView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// session for the back camera
let configuration = ARWorldTrackingConfiguration()
configuration.userFaceTrackingEnabled = true
backView.session.run(configuration)
// session for the front camera
guard ARFaceTrackingConfiguration.isSupported else { return }
let configurationFront = ARFaceTrackingConfiguration()
configurationFront.isLightEstimationEnabled = true
frontView.session.run(configurationFront, options: [])
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
}
The back camera stops its video feed while the front camera is working properly. Any chances to solve this ?
It would also be a solution to run one ARSession and one low level video capture session on the other camera but i am running into the same problems.

GMSPlace returns invalid coordinate (-180, -180), but name and place ID are correct

I'm trying to implement an autocomplete search on Google Maps that will show the location that the user selects on the map with a marker.
Search works fine. The problem is as follows. When I select a location from the search results, I get a GMSPlace object that has the correct name as the selected value, correct place ID (confirmed using this link), but incorrect coordinates (-180.0,-180.0, or the kCLLocationCoordinate2DInvalid constant). I tested this on multiple locations.
Most of this code was borrowed from documentation for the Places API.
import UIKit
import GoogleMaps
import GooglePlaces
class ViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var mapContainer: UIView!
var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.mapView = GMSMapView(frame: self.mapContainer.frame)
self.view.addSubview(self.mapView)
}
// Code from https://developers.google.com/places/ios-sdk/autocomplete#add_an_autocomplete_ui_control
#IBAction func searchByAddress(_ sender: Any) {
// Present the Autocomplete view controller when the button is pressed.
let autocompleteController = GMSAutocompleteViewController()
autocompleteController.delegate = self
// Specify the place data types to return.
let fields: GMSPlaceField = GMSPlaceField(rawValue: UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue))!
autocompleteController.placeFields = fields
// Display the autocomplete view controller.
present(autocompleteController, animated: true, completion: nil)
}
}
extension ViewController: GMSAutocompleteViewControllerDelegate {
// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
let position: CLLocationCoordinate2D = place.coordinate
let camera = GMSCameraPosition.camera(withLatitude: position.latitude, longitude: position.longitude, zoom: 10)
let newMapView = GMSMapView.map(withFrame: self.mapContainer.frame, camera: camera)
self.mapView = newMapView
self.view.addSubview(newMapView)
let marker = GMSMarker()
marker.position = position
marker.title = place.name
marker.map = self.mapView
viewController.dismiss(animated: true, completion: nil)
}
func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
// TODO: handle the error.
print("Error: ", error.localizedDescription)
}
// User canceled the operation.
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
viewController.dismiss(animated: true, completion: nil)
}
// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
Any help would be appreciated!
I was facing the same issue and went through the Place SDK documentation which says clearly that we should define before hand to the GMSPlaceField of what details do we need exactly and if you had followed the doc completely, it would be resulting only in the name and placeId being populated.
So while instantiating your GMSAutoCompleteViewController define in the following way.
**let fields: GMSPlaceField = GMSPlaceField(rawValue:UInt(GMSPlaceField.name.rawValue) |
UInt(GMSPlaceField.placeID.rawValue) |
UInt(GMSPlaceField.coordinate.rawValue) |
GMSPlaceField.addressComponents.rawValue |
GMSPlaceField.formattedAddress.rawValue)!
autocompleteController.placeFields = fields**

Present user location swift

I'm new to Swift, I want to show user location on map, I added MKMapView, and added an outlet, here is my code:
import UIKit
import Foundation
import MapKit
import CoreLocation
class ViewController: UIViewController ,CLLocationManagerDelegate{
#IBOutlet weak var map: MKMapView!
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span: MKCoordinateSpan = MKCoordinateSpanMake(0.01,0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
map.setRegion(region, animated: true)
self.map.showsUserLocation = true
}
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
But when I run the app on the simulator it shows me some other location on the USA. But I'm from another place that is not even close to the USA.
Your code is fine, that's because you run it on simulator, select Debug-->Simulate Location-->Choose some other location and you will see that location on the screen
Because simulator use fake location for testing purpose. you can also change that location See in the image(https://i.stack.imgur.com/2GN7x.png).
If you run on actual device it shows your current location.

Googlemaps not allowing me to locate the users location?

I am trying to create a view controller on swift that shows where the user is located. I have already implemented google maps, so now all I have to do is plug in the correct code. When doing so, I keep getting these two error messages then the app crashes. Can someone help me with figuring out a solution> any and all help is appreciated.
import UIKit
import Foundation
import Firebase
import MapKit
import GoogleMaps
import CoreLocation
class mainViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let defaults = UserDefaults.standard
let locationManager = CLLocationManager()
var mapView = GMSMapView()
var camera = GMSCameraPosition()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
GMSServices.provideAPIKey("AIzaSyBDOLisA3c-wDTbkbSssAxEb3iLw7Y5vHo")
let camera = GMSCameraPosition.camera(withLatitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!, zoom: 17)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!)
marker.snippet = "Current Location"
marker.map = mapView
self.mapView.addSubview(mapView)
view.backgroundColor = GREEN_Theme
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Welcome"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(Logout))
}
#objc func Logout() {
print("Logged Out")
do {
// I am receiving this error message on the auth.auth().signOut() "Use of unresolved identifier 'Auth'"
try Auth.auth().signOut()
defaults.set(false, forKey: "user is logged in")
let loginController = UINavigationController(rootViewController: LoginController())
present(loginController, animated: true, completion: nil)
} catch let err {
print(err.localizedDescription)
}
}
}
Your issue is that the CLLocationManager does not have enough time to fetch the info and in the meantime other functions ask for that info which its still nil.
The below will take care the issue, it also stops updating the locations all the time which can be battery draining especially considering that you have set AccuracyBest.
func getLocation(){
locationManager=CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
let lastLocation=locations[locations.count-1]
if lastLocation.horizontalAccuracy>0{
locationManager.stopUpdatingLocation()
let latitude = lastLocation.coordinate.latitude
let longitude = lastLocation.coordinate.longitude
GMSServices.provideAPIKey("AIzaSyBDOLisA3c-wDTbkbSssAxEb3iLw7Y5vHo")
// everything that is going to require the latitude and longitude from the location manager goes here
let camera = GMSCameraPosition.camera(withLatitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!, zoom: 17)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
self.view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!)
marker.snippet = "Current Location"
marker.map = mapView
self.mapView.addSubview(mapView)
}
}
Your viewDidLoad should have:
override func viewDidLoad() {
super.viewDidLoad()
getLocation()
view.backgroundColor = GREEN_Theme
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Welcome"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(Logout))
}
You are using Google Map as your map view, which means that you create an instance of the GMSMapView class. That's an object. You have one. And I assume that it's IBOutlet-wired. It comes with several delegate methods. So you may want to set its delegate. And you want your view controller to receive data from GMSMapView. So you set the delegate of that class to self (your view controller).
import UIKit
import Foundation
import Firebase
import GoogleMaps
import CoreLocation
class mainViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
// MARK: - Instance variables
private let locationManager = CLLocationManager()
// MARK: - IBOutlets
#IBOutlet weak var mapView: GMSMapView!
// MARK: - IBActions
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
mapView.isMyLocationEnabled = true
}
// MARK: - Life cycle
// MARK: - GMSMapView delegate methods
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
reverseGeocodeCoordinate(position.target) // sending data when the mapView is not moved or pinched by the finger //
}
func reverseGeocodeCoordinate(_ coordinate: CLLocationCoordinate2D) {
let geocoder = GMSGeocoder()
geocoder.reverseGeocodeCoordinate(coordinate) { response, error in
guard let address = response?.firstResult(), let lines = address.lines else {
return
}
...
...
}
}
}

Swift 4 : how to wait for a MKMapView to be loaded before adding pins

Well, the title is pretty self-explanatory. I have a little app with different views and it keeps crashing and I think it's because I'm trying to add pins on the map before the map is created (the debugger tells the object is nil). How can I wait for the map to be loaded and on the current view? Here is the code of the ViewController of my app:
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let coordinate_Mines = CLLocationCoordinate2D(latitude: 43.445258, longitude: 5.479400) //à remplacer ensuite par dernier coordonnés GPS utilisateur
let region = MKCoordinateRegionMakeWithDistance(coordinate_Mines, 1000, 1000)
mapView.setRegion(region, animated: true)
var pinCapteurTest: AnnotationPin!
pinCapteurTest = AnnotationPin(title: "Capteur de test", subtitle: "Entrée de l'école", coordinate: CLLocationCoordinate2D(latitude: 43.445202, longitude: 5.479456)) //coord capt test
mapView.addAnnotation(pinCapteurTest)
}
}
and here is my MainStoryBoard :
enter image description here
Thanks guys :)
You can extend ViewController with MKMapViewDelegate and the below method is where you can add annotations.
public func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
}
Set the mapView delegate to self in your viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}