I'm getting the users GPS Location like this:
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
//manager.requestAlwaysAuthorization()
//manager.requestWhenInUseAuthorization()
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations: [AnyObject]) { // Updated to current array syntax [AnyObject] rather than AnyObject[]
println("locations = \(locations)")
}
The commented-out functions seem not to exist for os x applications. It still works for me so that's fine.
But every time I run the code it asks for permission to use location.
Is it possible to store the permission somewhere, so it only asks on the first execution?
Quoting Apple's documentation:
Call the authorizationStatus class method to get the current authorization status for your app.
If the authorization status is kCLAuthorizationStatusRestricted or kCLAuthorizationStatusDenied, your app is not permitted to use location services and you should abort your attempt to use them.
Your code on OS X should look like this:
override func viewDidLoad() {
super.viewDidLoad()
let status = CLLocationManager.authorizationStatus()
if status == .Restricted || status == .Denied {
// User permission not given
return
}
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
}
Permission is managed centrally by Mac OS X. The first time you call startUpdatingLocation, it will ask for permission then remembers what the user has decided.
Related
How can I use Core Location's locationManagerDidChangeAuthorization(_:) method to check authorization status and report user location at the press of a button (called in #IBAction) below:
My issue here is that when I run the code in the simulator, CoreLocation doesn't pop up with an alert to ask the user for permission when the button is pressed.
class CurrentLocationViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
// Button to check authorization status and start sending location update to the delegate
#IBAction func getLocation() {
locationManagerDidChangeAuthorization(locationManager)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
// Delegate method to check authorization status and request "When In Use" authorization
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let authStatus = manager.authorizationStatus
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
}
EDIT: Using the deprecated authorizationStatus() class method in the #IBAction method instead of the locationManagerDidChangeAuthorization(_:) method allows me to get the pop up when the button is pressed in the simulator. I'm still trying to figure out why this modification works whereas my code above doesn't.
#IBAction func getLocation() {
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
...
You're code works - but have you remembered to add the privacy usage descriptions to the info.plist file?
Add these two entries in the file with your own explanation in the value field, then it should popup in the simulator:
Privacy - Location Always and When In Use Usage Description
Privacy - Location When In Use Usage Description
My app seems to work fine on each use except the first one.
I ask for user authorization and I have the appropriate keys in the plist but the rest of viewDidLoad after the lines requesting authorization don't execute. I have attached the breakpoints below and breakpoint 2 isn't hit on the first time the app is used.
I'm pretty sure after authorization is given it just jumps to the func locationManager in the extension.
I could wait till the very end to ask for authorization until everything else is set but not sure if this is the best, or only way, out.
Thanks,
class MapController: UIViewController, GMSMapViewDelegate {
var locationManager = CLLocationManager()
var currentLocation: CLLocation?
#IBOutlet var mapView: GMSMapView!
override func viewDidLoad(){
super.viewDidLoad()
locationManager = CLLocationManager()
--------------------------> breakpoint 1
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
-------------------------> breakpoint 2
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
locationManager.delegate = self
guard let lat = locationManager.location?.coordinate.latitude else {return}
guard let lng = locationManager.location?.coordinate.longitude else {return}
mapView.settings.compassButton = true
mapView.settings.myLocationButton = true
mapView.isMyLocationEnabled = true
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 1)
mapView.camera = camera
mapView.delegate = self
getData()
}
extension MapController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location: CLLocation = locations.last else {return}
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 1)
mapView.animate(to: camera)
}
}
Why do you request authorisation to two different things? If you request and get always authorisation, you don't need to request when in use authorisation, since this is only a subset of always authorisation.
Also, these are both asynchronous functions, so you cannot execute location based code right after them, since if you don't have authorisation yet, the code right after requestAuthorization() will be executed before you actually got authorisation and hence the functions won't be called, since you don't have authorisation yet.
You have to check the authorisation status before calling any location related code, such as locationManager.startUpdatingLocation() and only execute the location related code if the status is authorised. If it is not authorised, you have to implement CLLocationManagerDelegate's locationManager(_:didChangeAuthorization:) function and call the location related call inside that function after checking that the result of the change is an authorised status.
In my DC Metro tracking application, I use CoreLocation to select the Metro station nearest the user and also present a list of stations near them.
It works perfectly in macOS 10.11, but I'm having trouble getting it to work on macOS 10.10. To debug this, I inserted a line in the locationManager(_:didUpdateLocations:) method in TodayViewController.swift to print the location fetched by the application.
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]) {
LocationManager.sharedManager.stopUpdatingLocation()
print(LocationManager.sharedManager.location)
...
}
On El Capitan, this outputs the following to the console (success):
Optional(<+38.92208178,-77.22920176> +/- 65.00m (speed -1.00 mps / course -1.00) # 8/18/16, 5:04:37 PM Eastern Daylight Time)
On Yosemite, it just outputs nil.
I have also tried to simulate my location to no avail.
Does anyone have any suggestions? Location services are enabled on the Yosemite machine, and I know that it is working because the Weather Notification Center widget is correctly fetching its location.
Thank you!
More relevant code:
override func viewWillAppear() {
super.viewWillAppear()
...
switch CLLocationManager.authorizationStatus() {
case .Authorized:
if !didSelectStation {
selectedStationLabel.stringValue = "Determining closest station..."
}
LocationManager.sharedManager.startUpdatingLocation()
case .NotDetermined:
getCurrentLocationButton.hidden = false
mainPredictionView.hidden = true
default: // Denied or Restricted
WMATAfetcher.getPredictionsForSelectedStation()
}
}
class LocationManager {
static let sharedManager: CLLocationManager = {
let locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 100.0
return locationManager
}()
}
I also have a button, getCurrentLocationButton, that calls startUpdatingLocation()
#IBAction func getCurrentLocation(sender: NSButton) {
LocationManager.sharedManager.startUpdatingLocation()
}
Have you tried accessing location before calling stopUpdatingLocation()?
I seem to be having a little trouble getting tvOS to prompt the user for location data authorization. I literally copied and pasted working code from iOS and it seems to not be prompting the user. I am using the code listed below as well as the NSLocationWhenInUseUsageDescription key with a string value. The only difference in the api that I see is on iOS it uses startupdatinglocation() and on tvOS it uses requestLocation() (similar to watchOS) I've stepped through the problem and it is infact hitting requestWhenInUseAuthorization() but simply doesn't prompt the user.
Any idea what is going on?
import UIKit
import CoreLocation
class ViewController: UIViewController {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.locationServicesEnabled(){
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.NotDetermined{
locationManager.requestWhenInUseAuthorization()
}
else if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse{
locationManager.requestLocation()
}
}
}
It turns out that a CFBundleDisplayName key and $(PRODUCT_NAME)value is needed in order for the prompt to display.
I have CoreLocation in my Swift app. When I run this in simulator or in a device, this crash and not show the permissions to access CoreLocation.. I have all code necessary to implement this: request in code, NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in plist...
I'm reading iOS app doesn't ask for location permission but I can't make that this show.
var location: CLLocationManager!
let status = CLLocationManager.authorizationStatus()
location=CLLocationManager()
if(status == CLAuthorizationStatus.NotDetermined) {
self.location.requestAlwaysAuthorization();
}
else {
location.startUpdatingLocation()
}
location.delegate = self
location.desiredAccuracy=kCLLocationAccuracyBest
self.location.startMonitoringSignificantLocationChanges()
print(location.location.coordinate.latitude) //Here crash
print(location.location.coordinate.longitude)
What other things can I make for show this?
Thanks!
Here is a code snippet from my app:
let locationManager = CLLocationManager()
...
locationManager.delegate = self
locationManager.activityType = CLActivityType.Fitness
locationManager.distanceFilter = 10 // 10m
if ( UIDevice.currentDevice().systemVersion == "8.0" ) {
locationManager.requestAlwaysAuthorization()
}
// get current location
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized {
locationManager.startUpdatingLocation()
}
The prompt only shows if the status is .NotDetermined. There are other statuses though that would prevent the location services from working (all but .Authorized) when the prompt does not get displayed. You should check for these.
Also, the requestAlwaysAuthorization does not return immediately and you need to implement
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus)
You have to add a row to info.plist file
NSLocationWhenInUseUsageDescription which contains a string.
That string will be displayed when the alert pops up asking user's permission.