I've been doing some research about CoreLocation. Recently, I encountered a problem that has been covered elsewhere, but in Objective C, and for iOS 8.
I feel kinda silly asking this, but how can you check if location services are enabled using swift, on iOS 9?
On iOS 7 (and maybe 8?) you could use locationServicesEnabled(), but that doesn't appear to be working when compiling for iOS 9.
So how would I accomplish this?
Thanks!
Add the CLLocationManagerDelegate to your class inheritance and then you can make this check:
Import CoreLocation Framework
import CoreLocation
Swift 1.x - 2.x version:
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .NotDetermined, .Restricted, .Denied:
print("No access")
case .AuthorizedAlways, .AuthorizedWhenInUse:
print("Access")
}
} else {
print("Location services are not enabled")
}
Swift 4.x version:
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined, .restricted, .denied:
print("No access")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
}
} else {
print("Location services are not enabled")
}
Swift 5.1 version
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined, .restricted, .denied:
print("No access")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
#unknown default:
break
}
} else {
print("Location services are not enabled")
}
iOS 14.x
In iOS 14 you will get the following error message:
authorizationStatus() was deprecated in iOS 14.0
To solve this, use the following:
private let locationManager = CLLocationManager()
if CLLocationManager.locationServicesEnabled() {
switch locationManager.authorizationStatus {
case .notDetermined, .restricted, .denied:
print("No access")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
#unknown default:
break
}
} else {
print("Location services are not enabled")
}
In objective-c
you should track user already denied or not determined then ask for permission or sent user to Setting app.
-(void)askEnableLocationService
{
BOOL showAlertSetting = false;
BOOL showInitLocation = false;
if ([CLLocationManager locationServicesEnabled]) {
switch ([CLLocationManager authorizationStatus]) {
case kCLAuthorizationStatusDenied:
showAlertSetting = true;
NSLog(#"HH: kCLAuthorizationStatusDenied");
break;
case kCLAuthorizationStatusRestricted:
showAlertSetting = true;
NSLog(#"HH: kCLAuthorizationStatusRestricted");
break;
case kCLAuthorizationStatusAuthorizedAlways:
showInitLocation = true;
NSLog(#"HH: kCLAuthorizationStatusAuthorizedAlways");
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
showInitLocation = true;
NSLog(#"HH: kCLAuthorizationStatusAuthorizedWhenInUse");
break;
case kCLAuthorizationStatusNotDetermined:
showInitLocation = true;
NSLog(#"HH: kCLAuthorizationStatusNotDetermined");
break;
default:
break;
}
} else {
showAlertSetting = true;
NSLog(#"HH: locationServicesDisabled");
}
if (showAlertSetting) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:#"Please enable location service for this app in ALLOW LOCATION ACCESS: Always, Go to Setting?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Open Setting", nil];
alertView.tag = 199;
[alertView show];
}
if (showInitLocation) {
[self initLocationManager];
}
}
Implement alertView Delegate then sent user to enable location service if already deny by user.
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 199) {
if (buttonIndex == 1) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
return;
}
}
Init Location Manager
-(void)initLocationManager{
self.locationManager = [[CLLocationManager alloc] init];
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
}
Please note kCLAuthorizationStatusAuthorizedAlways and kCLAuthorizationStatusAuthorizedWhenInUse is difference.
Here is the format Apple recommends.
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
// Request when-in-use authorization initially
break
case .restricted, .denied:
// Disable location features
break
case .authorizedWhenInUse, .authorizedAlways:
// Enable location features
break
}
Here is a complete example.
This includes an AlertView with a button to take the user to the Settings screen if previously denied access.
import CoreLocation
let locationManager = CLLocationManager()
class SettingsTableViewController:CLLocationManagerDelegate{
func checkUsersLocationServicesAuthorization(){
/// Check if user has authorized Total Plus to use Location Services
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
// Request when-in-use authorization initially
// This is the first and the ONLY time you will be able to ask the user for permission
self.locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
break
case .restricted, .denied:
// Disable location features
switchAutoTaxDetection.isOn = false
let alert = UIAlertController(title: "Allow Location Access", message: "MyApp needs access to your location. Turn on Location Services in your device settings.", preferredStyle: UIAlertController.Style.alert)
// Button to Open Settings
alert.addAction(UIAlertAction(title: "Settings", style: UIAlertAction.Style.default, handler: { action in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)")
})
}
}))
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
break
case .authorizedWhenInUse, .authorizedAlways:
// Enable features that require location services here.
print("Full Access")
break
}
}
}
}
SWIFT (As of July 24, 2018)
if CLLocationManager.locationServicesEnabled() {
}
this will tell you if the user has already selected a setting for the app's location permission request
It is just a 2 line function in Swift 4:
import CoreLocation
static func isLocationPermissionGranted() -> Bool
{
guard CLLocationManager.locationServicesEnabled() else { return false }
return [.authorizedAlways, .authorizedWhenInUse].contains(CLLocationManager.authorizationStatus())
}
For swift3.0 and above ,
if frequent checks are made for the availability of location services, create a class like below,
import CoreLocation
open class Reachability {
class func isLocationServiceEnabled() -> Bool {
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
return false
case .authorizedAlways, .authorizedWhenInUse:
return true
default:
print("Something wrong with Location services")
return false
}
} else {
print("Location services are not enabled")
return false
}
}
}
and then use it like this in your VC
if Reachability.isLocationServiceEnabled() == true {
// Do what you want to do.
} else {
//You could show an alert like this.
let alertController = UIAlertController(title: "Location
Services Disabled", message: "Please enable location services
for this app.", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default,
handler: nil)
alertController.addAction(OKAction)
OperationQueue.main.addOperation {
self.present(alertController, animated: true,
completion:nil)
}
}
When you call -startLocation, if location services were denied by the user, the location manager delegate will receive a call to - locationManager:didFailWithError: with the kCLErrorDenied error code. This works both in all versions of iOS.
In Swift 3.0
if (CLLocationManager.locationServicesEnabled())
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if ((UIDevice.current.systemVersion as NSString).floatValue >= 8)
{
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
}
else
{
#if debug
println("Location services are not enabled");
#endif
}
To ask for permission for location services you use:
yourSharedLocationManager.requestWhenInUseAuthorization()
If the status is currently undetermined an alert will show prompting the user to allow access. If access is denied your app will be notified in the CLLocationManagerDelegate, likewise if permission is denied at any point you will be updated here.
There are two separate statuses you need to check to determine the current permissions.
If the user has the general location services enabled or not
CLLocationManager.locationServicesEnabled()
If the user has granted the correct permission for your app..
CLLocationManager.authorizationStatus() == .authorizedWhenInUse
You could add an extension is a handy option:
extension CLLocationManager {
static func authorizedToRequestLocation() -> Bool {
return CLLocationManager.locationServicesEnabled() &&
(CLLocationManager.authorizationStatus() == .authorizedAlways || CLLocationManager.authorizationStatus() == .authorizedWhenInUse)
}
}
Here it is being accessed when the user has first requested directions:
private func requestUserLocation() {
//when status is not determined this method runs to request location access
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.authorizedToRequestLocation() {
//have accuracy set to best for navigation - accuracy is not guaranteed it 'does it's best'
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
//find out current location, using this one time request location will start the location services and then stop once have the location within the desired accuracy -
locationManager.requestLocation()
} else {
//show alert for no location permission
showAlertNoLocation(locationError: .invalidPermissions)
}
}
Here is the delegate:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if !CLLocationManager.authorizedToRequestLocation() {
showAlertNoLocation(locationError: .invalidPermissions)
}
}
Swift 5.2
First, set up User class as a CLLocationManager delegate:
import SwiftUI
import CoreLocation
class User: NSObject, ObservableObject {
let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.requestLocation()
manager.startUpdatingLocation()
}
}
extension User: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
print("Location services authorization request")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Location updated")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Failed to find user's location: \(error.localizedDescription)")
}
}
Then in a view:
if (user.manager.authorizationStatus == .denied) {
print("Location authorization denied, displaying sheet.")
}
Here is my solution:
import CoreLocation
import Combine
class LocationManager: NSObject, CLLocationManagerDelegate {
static let shared = LocationManager()
private (set) var didChangeLocationAuthorization: CurrentValueSubject<CLAuthorizationStatus, Never> = .init(.notDetermined)
private let manager = CLLocationManager()
private let notificationCenter = NotificationCenter.default
var authorizationStatus: CLAuthorizationStatus = .notDetermined
private override init() { }
func checkLocationService() {
setupLocationManager()
checkLocationManagerAuthorization()
}
private func setupLocationManager() {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
}
private func checkLocationManagerAuthorization() {
authorizationStatus = manager.authorizationStatus
switch authorizationStatus{
case .notDetermined:
print("::: -> Location: notDetermined")
manager.requestWhenInUseAuthorization()
case .authorizedAlways, .authorizedWhenInUse:
print("::: -> Location: authorizedWhenInUse")
manager.startUpdatingLocation()
case .denied, .restricted:
print("::: -> Location: denied")
default:
break
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationManagerAuthorization()
didChangeLocationAuthorization.send(manager.authorizationStatus)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
manager.stopUpdatingLocation()
}
}
Use like this:
LocationManager.shared.checkLocationService()
LocationManager.shared.didChangeLocationAuthorization
.sink { [weak self] authorization in
print("::: Location Permission: \(authorization)")
}.store(in: &cancelBag)
Related
I have implemented a location authorization callback function and it works, but looking over the code I seem to have got the function to trigger but never actually use the function as intended. Please can you comment on how bad I am being and if it is acceptable to do what I have done.
import UIKit
import CoreLocation
class ViewController___Main_menu: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
print("services are enabled")
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
print("Not determined")
case .restricted:
print("Resticted")
case .denied:
print("Denied")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
#unknown default:
print("unknown error")
}
} else {
print("not enabled")
}
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus){
print("Status: \(status)")
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
print("Not determined")
case .restricted:
print("Resticted")
case .denied:
print("Denied")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
#unknown default:
print("unknown error")
}
}
}
It's looks like you're requesting access to location services and straight after that checking what the authorization status is, expecting it to be available immediately. This isn't the way it works. When you request location with locationManager.requestWhenInUseAuthorization the request happens asynchronously.
When the location status changes then it will call to the function you're included locationManager(_:didChangeAuthorization) with the new status. This will happen when the user taps "Allow" or "Deny" on the prompt that appears. It can also happen when they go into the settings and change the permissions there
So to make it more clear, check and log the authorization status before requesting location. Use the following methods to know if the location request succeeded or failed:
func locationManager(CLLocationManager, didUpdateLocations: [CLLocation])
func locationManager(CLLocationManager, didFailWithError: Error)
You would use the CLLocationManager.locationServicesEnabled() check to wrap the request for location services. If location is turned off for the device then requesting location will just cause an error.
I am facing the issues while fetching users location on Apple Watch. When I try to run on simulator I am not able to get the location but running on actual watch it returns me location. But there are some cases which don't return me location. Why does that happen?
Also, how should I do entries for location access in info.plist? Currently I have added to both iPhone and Apple Watch app.
This is how I request location.
func requestLocation() {
guard !isRequestingLocation else {
manager.stopUpdatingLocation()
isRequestingLocation = false
return
}
let authorizationStatus = CLLocationManager.authorizationStatus()
switch authorizationStatus {
case .notDetermined:
print("notDetermined")
isRequestingLocation = true
manager.requestWhenInUseAuthorization()
case .authorizedWhenInUse, .authorizedAlways:
print("authorizedWhenInUse")
isRequestingLocation = true
manager.requestLocation()
infoLabel.setText("Fetching Location...")
case .denied:
print("denied location")
case .restricted:
print("restricted location")
}
}
Below delegate method returns me location when found.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard !locations.isEmpty else { return }
DispatchQueue.main.async {
self.currentLocation = locations.last!.coordinate
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
DispatchQueue.main.async {
print(error.localizedDescription)
self.currentLocation = nil
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
DispatchQueue.main.async {
guard self.isRequestingLocation else { return }
switch status {
case .authorizedWhenInUse:
manager.requestLocation()
case .denied:
print("Auth Denied")
self.currentLocation = nil
default:
print("Auth Default")
self.currentLocation = nil
}
}
}
I have requestAlwaysAuthorization and I need to track users every time if user doesn't accept to requestAlwaysAuthorization I want to do exit in app ?
How can I do it ?
My codes under below.
import CoreLocation
public var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let altitudeG = locations.last?.altitude
let longitudeG = locations.last?.coordinate.longitude
let latitudeG = locations.last?.coordinate.latitude
print("\(altitudeG) \(longitudeG) \(latitudeG)")
}
In error case this delegatemethod is called:
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error)
// handle not authorized error here. You might want to quit on specific errors (unauthorized) only. Check the error.
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
}
You can also check the current permissions state before letting CLLocationManager fail:
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
}
} else {
print("Location services are not enabled")
}
taken from this answer.
Opinion based: I consider quitting the app instead of giving the user a understandable feedback very bad UX.
Above answer is also good, I just tried to make it bit easy way with methods. Also, if you are working with hardware devices like beacons then you must access the location AuthorizedAlways.
Check if location services are enabled
public func isLocationEnabled()-> Bool {
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .NotDetermined, .Restricted, .Denied , .AuthorizedWhenInUse :
showLocationServiceNotEnabledAlert()
return false
case .AuthorizedAlways: // As of now we check for only "Always", not for "When In Use" this should be fixed according to the requirements
return true
}
}
return false
}
Alert For User to on the service And redirect to Settings
func showLocationServiceNotEnabledAlert() {
let title = "Your Title"
let message = "Your Message"
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let settingsAction = UIAlertAction(title: "Settings".localized, style: .Default) { (alertAction) in
if let appSettings = NSURL(string: UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(appSettings)
}
}
alertController.addAction(settingsAction)
let cancelAction = UIAlertAction(title: "Cancel".localized, style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
UIApplication.sharedApplication().delegate?.window!?.currentViewController?.presentViewController(alertController, animated: true, completion: nil)
}
With CoreLocation.Foundation added to the BuildPhase and imported at the top of the file, I can get location information if I put the following into a view controller with a button:
#IBAction func locationButton(sender: AnyObject) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
It goes on to locationManager didUpdateLocations with a CLGeocoder().reverseGeocodeLocation completionHandler that displays the location info in another function - this works.
BUT, it doesn't work when I try to transfer this same code in my data model. I set up the model with the following:
import CoreLocation
class Record: NSObject, CLLocationManagerDelegate
{
let locationManager = CLLocationManager()
Because there's no button, I've put the locationManager code into:
override init()
{
iD = NSUUID().UUIDString
super.init()
if (CLLocationManager.locationServicesEnabled())
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
switch CLLocationManager.authorizationStatus() {
case .AuthorizedWhenInUse, .AuthorizedAlways:
locationManager.startUpdatingLocation()
case .NotDetermined:
locationManager.requestWhenInUseAuthorization() // or request always if you need it
case .Restricted, .Denied:
print("tell users that they need to enable access in settings")
default:
break
}
print("Location services available")
if CLLocationManager.authorizationStatus() == .NotDetermined
{
print("Still Not Determined")
}
} else { print("Location services not available") }
}
I get 'Location services available'. But the following code never prints anything to console, nor does it call the function toSetLocationStamped.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
print("started location man")
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: //pass the location co-ordinates
{
(placemarks, error) -> Void in
if (error != nil)
{
println("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0 //process the location array (placemarks)
{
let pm = placemarks[0] as! CLPlacemark
self.toSetLocationStamped(pm)
print("got here")
} else
{
println("Problem receiving data from geocoder")
}
})
}
If I put a deinit the class Record, with a simple print log, there is no output.
deinit
{
print("deinit")
}
I'm initializing a dummyRecord: Record from a required init in MasterViewController class:
class MasterViewController: UITableViewController
{
var records = [Record]()
var subjectDescription: String?
// weak var delegate: MonsterSelectionDelegate? // property for object conforming to MSDelegate
required init(coder aDecoder: NSCoder) // // coder because class is loaded from Storyboard
{
super.init(coder: aDecoder)
var dummyRecord1 = Record()
dummyRecord1.details = "All was very good and strong with a little bit of lemon on the side of the hill."
dummyRecord1.dateTimeEntered = NSDate(dateString: "2015-07-22")
dummyRecord1.subject = "Clouds"
dummyRecord1.locationEntered = "Drittelsgasse 1, 69493 Großsachsen, Germany."
dummyRecord1.photos.append(UIImage(named: "zombies.jpg")!)
records.append(dummyRecord1)
}
After you call
self.locationManager.requestWhenInUseAuthorization()
you cannot immediately start updating location. That call is asynchronous.
Here is how you should properly do it:
1) Check the authorisation status:
switch CLLocationManager.authorizationStatus() {
case .AuthorizedWhenInUse, .AuthorisedAlways:
locationManager.startUpdatingLocation()
case .NotDetermined:
locationManager.requestWhenInUseAuthorization() // or request always if you need it
case .Restricted, .Denied:
// tell users that they need to enable access in settings
default:
break
}
2) If you have previously authorised your app this should update location. However, if you didn't a popup will appear. In order to respond to the change in the authorisation status you need to add another function:
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if (status == .AuthorizedAlways) || (status == .AuthorizedWhenInUse) {
locationManager.startUpdatingLocation()
}
}
When I run the code, the window pops asking for permission to use location but disappears almost immediately, not giving the user a chance to click "Allow". Is there a way to force this action before proceeding?
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
var map:MKMapView?
var manager:CLLocationManager!
convenience init(frame:CGRect){
self.init(nibName: nil, bundle: nil)
self.view.frame = frame
self.map = MKMapView(frame: frame)
self.map!.delegate = self
self.view.addSubview(self.map!)
}
override func viewDidLoad() {
super.viewDidLoad()
// Core Location
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus){
print("The authorization status of location services is changed to: ")
switch CLLocationManager.authorizationStatus(){
case .Denied:
println("Denied")
case .NotDetermined:
println("Not determined")
case .Restricted:
println("Restricted")
default:
println("Authorized")
}
}
func displayAlertWithTitle(title: String, message: String){
let controller = UIAlertController(title: title,
message: message,
preferredStyle: .Alert)
controller.addAction(UIAlertAction(title: "OK",
style: .Default,
handler: nil))
presentViewController(controller, animated: true, completion: nil)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if CLLocationManager.locationServicesEnabled(){
switch CLLocationManager.authorizationStatus(){
case .Denied:
displayAlertWithTitle("Not Determined",
message: "Location services are not allowed for this app")
case .NotDetermined:
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
case .Restricted:
displayAlertWithTitle("Restricted",
message: "Location services are not allowed for this app")
default:
println("Default")
}
} else {
println("Location services are not enabled")
}
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
var userLocation:CLLocation = locations[0] as! CLLocation
var latitude:CLLocationDegrees = userLocation.coordinate.latitude
var longitude:CLLocationDegrees = userLocation.coordinate.longitude
var latDelta:CLLocationDegrees = 1.0
var lonDelta:CLLocationDegrees = 1.0
var span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
var location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
var region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
map!.setRegion(region, animated: true)
manager.stopUpdatingLocation()
}
Please try this:
import UIKit
import GoogleMaps
import CoreLocation
class StartViewController: UIViewController,CLLocationManagerDelegate,GMSMapViewDelegate {
var locationManager: CLLocationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
setupLocationManager()
}
func setupLocationManager() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationHandler()
}
func locationHandler() {
if CLLocationManager.locationServicesEnabled() == true {
if (CLLocationManager.authorizationStatus() == .denied) {
// The user denied authorization
} else if (CLLocationManager.authorizationStatus() == .authorizedAlways) {
// The user accepted authorization
} else if (CLLocationManager.authorizationStatus() == .notDetermined){
// The user not determiend authorization
}else if (CLLocationManager.authorizationStatus() == .authorizedWhenInUse){
// In use
}else{ }
}else{
//Access to user location permission denied!
}
}
}//class
Be successful.
It's because you're calling manager.startUpdatingLocation() before you get the result from the manager.requestWhenInUseAuthorization(). Even though you call requestWhenInUseAuthorization, you're updating the user's location before you ever get the result of that method (I had the exact same question as you, actually!)
The answer to that question explains the solution well. Basically, you'll need to implement the locationManager:didChangeAuthorizationStatus delegate method, which is called any time the authorization status changes based on user input. If the user did authorize tracking, then you can call manager.startUpdatingLocation().
Also, for a Swift example of how to implement these methods, take look at this guide.