获取用户当前位置/坐标

235

我该如何存储用户的当前位置并在地图上显示该位置?

我能够在地图上显示预定义的坐标,但我不知道如何从设备接收信息。

此外,我知道我必须将一些项添加到Plist中。我该如何做到这一点?

16个回答

255

要获取用户当前位置,您需要声明:

let locationManager = CLLocationManager()

viewDidLoad() 方法中,你需要像这样实例化 CLLocationManager 类:

// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization() 

// For use in foreground
self.locationManager.requestWhenInUseAuthorization()

if CLLocationManager.locationServicesEnabled() {
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
    locationManager.startUpdatingLocation()
}

然后在CLLocationManagerDelegate方法中,您可以获取用户当前位置的坐标:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
    print("locations = \(locValue.latitude) \(locValue.longitude)")
}
在info.plist中,您将需要添加NSLocationAlwaysUsageDescription和您的自定义警告消息,例如:AppName(演示应用程序)想要使用您的当前位置。

72
不要忘记导入 MapKit 库和 CoreLocation 库,并在类定义中添加 CLLocationManagerDelegate - Lukesivi
8
如果这看起来像 Objective-C 对您来说,那么您从未见过 Objective-C(也没有 Swift)。 - Martin Marconcini
6
你忘了提到CLLocationManagerDelegate协议的实现。 - ssinad
17
NSLocationAlwaysUsageDescription已更名为Privacy - Location Always Usage Description - Saoud Rizwan
7
你必须将locationManager声明为全局变量,而不是在viewDidLoad中声明为局部变量。 - chengsam
显示剩余9条评论

105

你应该执行以下步骤:

  1. CoreLocation.framework添加到BuildPhases -> Link Binary With Libraries中(自XCode 7.2.1起不再需要)
  2. 在你的类(很可能是ViewController.swift)中导入CoreLocation
  3. 在你的类声明中添加CLLocationManagerDelegate
  4. NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription添加到plist文件中
  5. 初始化位置管理器:

    locationManager = CLLocationManager()
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    locationManager.startUpdatingLocation()
    
  6. 通过以下方式获取用户位置:

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let locValue:CLLocationCoordinate2D = manager.location!.coordinate
        print("locations = \(locValue.latitude) \(locValue.longitude)")
    }
    

3
新功能:func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) - user523234
逐步回答。但请更新它。现在它不能工作。 - Dheeraj D
第五步完全错了。即使已经授权,它也不必要地请求授权。而且在确定用户是否有权限之前,它就开始更新位置。 - HangarRash

70

更新支持iOS 12.2Swift 5

您必须在plist文件中添加以下隐私权限

<key>NSLocationWhenInUseUsageDescription</key>
<string>Description</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Description</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>Description</string>

这就是我目前的状况

在Swift 2.0中获取当前位置并在地图上显示

确保您已将CoreLocationMapKit框架添加到您的项目中(在XCode 7.2.1中不需要此步骤)

import Foundation
import CoreLocation
import MapKit

class DiscoverViewController : UIViewController, CLLocationManagerDelegate {
    
    @IBOutlet weak var map: MKMapView!
    var locationManager: CLLocationManager!
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
       
        if (CLLocationManager.locationServicesEnabled())
        {
            locationManager = CLLocationManager()
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 
    {
    
        let location = locations.last! 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)
    }
}

这是结果屏幕

一张地图截图, 以孟买为中心


我运行了你的代码,但是出现了一个空白的白屏。是否需要在Storyboard中添加视图或其他内容? - ThisClark
1
在Swift 4中,这对我非常有效,只需要添加一个下划线(由Xcode提示),所以locationManager行变成了:func locationManager(_ manager:CLLocationManager,didUpdateLocations locations:[CLLocation]) - Elijah Lofgren
viewDidLoad 中的代码完全错误。即使已经授权,它也不必要地请求授权。而且在确定用户是否有权限之前就开始更新位置了。 - HangarRash

40

导入类库,例如:

import CoreLocation

设置代理:

CLLocationManagerDelegate

像这样使用变量:

var locationManager:CLLocationManager!

在viewDidLoad()方法中,编写以下优美的代码:

 locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()

    if CLLocationManager.locationServicesEnabled(){
        locationManager.startUpdatingLocation()
    }

编写CLLocation代理方法:

    //MARK: - location delegate methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let userLocation :CLLocation = locations[0] as CLLocation

    print("user latitude = \(userLocation.coordinate.latitude)")
    print("user longitude = \(userLocation.coordinate.longitude)")

    self.labelLat.text = "\(userLocation.coordinate.latitude)"
    self.labelLongi.text = "\(userLocation.coordinate.longitude)"

    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(userLocation) { (placemarks, error) in
        if (error != nil){
            print("error in reverseGeocode")
        }
        let placemark = placemarks! as [CLPlacemark]
        if placemark.count>0{
            let placemark = placemarks![0]
            print(placemark.locality!)
            print(placemark.administrativeArea!)
            print(placemark.country!)

            self.labelAdd.text = "\(placemark.locality!), \(placemark.administrativeArea!), \(placemark.country!)"
        }
    }

}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("Error \(error)")
}

现在设置访问位置的权限,因此将这些键值添加到您的info.plist文件中

 <key>NSLocationAlwaysUsageDescription</key>
<string>Will you allow this app to always know your location?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Do you allow this app to know your current location?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Do you allow this app to know your current location?</string>

enter image description here

100%工作正常,已测试


我有另一种语言,但它不起作用。我只想要英语。 - Maulik shah
viewDidLoad 中的代码是错误的。即使已经授权,它也不必要地请求了授权。这会导致在主线程上调用 locationServicesEnabled() 时出现运行时警告。 - HangarRash

28
首先导入Corelocation和MapKit库:
import MapKit
import CoreLocation

继承CLLocationManagerDelegate到我们的类中。
class ViewController: UIViewController, CLLocationManagerDelegate

创建一个locationManager变量,这将是您的位置数据。
var locationManager = CLLocationManager()

创建一个函数来获取位置信息,具体来说,这个确切的语法是可行的:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

在您的函数中创建一个常量,表示用户当前位置。
let userLocation:CLLocation = locations[0] as CLLocation // note that locations is same as the one in the function declaration  

停止更新位置,这将防止您的设备在移动时不断更改窗口以使您的位置居中(如果您希望其以其他方式运作,则可以忽略此操作)。
manager.stopUpdatingLocation()

从你刚刚定义的userLocation中获取用户坐标:
let coordinations = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude,longitude: userLocation.coordinate.longitude)

定义您想要地图缩放的程度:

let span = MKCoordinateSpanMake(0.2,0.2) 将这两个组合起来以获取区域:

let region = MKCoordinateRegion(center: coordinations, span: span)//this basically tells your map where to look and where from what distance

现在设置区域并选择是否要使用动画前往该区域。
mapView.setRegion(region, animated: true)

关闭你的函数 }

从你的按钮或其他你想要设置locationManagerDelegate为self的方式

现在允许位置被显示

指定准确度

locationManager.desiredAccuracy = kCLLocationAccuracyBest

授权。
 locationManager.requestWhenInUseAuthorization()

要授权位置服务,您需要将以下两行添加到您的 plist 中。

enter image description here

获取位置:
locationManager.startUpdatingLocation()

将其展示给用户:
mapView.showsUserLocation = true

这是我的完整代码:
import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    @IBOutlet weak var mapView: MKMapView!
    
    var locationManager = CLLocationManager()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

  
    @IBAction func locateMe(sender: UIBarButtonItem) {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        
        mapView.showsUserLocation = true
        
    }
    
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let userLocation:CLLocation = locations[0] as CLLocation
        
        manager.stopUpdatingLocation()
        
        let coordinations = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude,longitude: userLocation.coordinate.longitude)
        let span = MKCoordinateSpanMake(0.2,0.2)
        let region = MKCoordinateRegion(center: coordinations, span: span)
        
        mapView.setRegion(region, animated: true)
        
    }
}

这不是正确的代码。你从来没有验证用户是否有权限。每次用户点击按钮时,你都会请求授权。你在不知道用户是否有权限的情况下开始更新位置。 - HangarRash

28


1
如果您愿意,可以通过添加代码来解释您的答案。 - Krutarth Patel
19
最好使用标记语言来提供代码片段,而不是粘贴屏幕截图。 - Nicholas Allio

22

Swift 3.0

如果您不想在地图上显示用户位置,但只想将其存储在Firebase或其他地方,请按照以下步骤操作:

import MapKit
import CoreLocation

现在在您的VC上使用CLLocationManagerDelegate,并且您必须覆盖下面显示的最后三个方法。 您可以看到如何使用这些方法来获取当前用户位置的requestLocation()方法。

class MyVc: UIViewController, CLLocationManagerDelegate {

  let locationManager = CLLocationManager()

 override func viewDidLoad() {
    super.viewDidLoad()

    isAuthorizedtoGetUserLocation()

    if CLLocationManager.locationServicesEnabled() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
    }
}

 //if we have no permission to access user location, then ask user for permission.
func isAuthorizedtoGetUserLocation() {

    if CLLocationManager.authorizationStatus() != .authorizedWhenInUse     {
        locationManager.requestWhenInUseAuthorization()
    }
}


//this method will be called each time when a user change his location access preference.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    if status == .authorizedWhenInUse {
        print("User allowed us to access location")
        //do whatever init activities here.
    }
}


 //this method is called by the framework on         locationManager.requestLocation();
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("Did location updates is called")
    //store the user location here to firebase or somewhere 
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("Did location updates is called but failed getting location \(error)")
}

}
现在,当用户登录您的应用程序时,您可以编写下面的调用代码。当调用requestLocation()时,它将进一步调用上面的didUpdateLocations,并且您可以将位置存储到Firebase或任何其他地方。
if CLLocationManager.locationServicesEnabled() {
            locationManager.requestLocation();
 }
如果您正在使用 GeoFire,则可以按照下面的方式在 didUpdateLocations 方法中存储位置。
geoFire?.setLocation(locations.first, forKey: uid) where uid is the user id who logged in to the app. I think you will know how to get UID based on your app sign in implementation. 

最后但并非最不重要的,进入您的Info.plist,并启用“隐私-使用时获取位置”的描述。

当您使用模拟器进行测试时,它总是会给您一个在Simulator->Debug->Location中配置的自定义位置。


你好,位置在哪里(经度、纬度),位置更新频率是多少? - Cristian Mora
当调用locationManager.requestLocation时,将会触发locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])方法。其中locations是一个位置数组,您可以使用其中一个位置或让用户选择最合适的一个。locations的类型为CLLocation,您可以从该对象中获取经度和纬度。如果您仅需要一次用户信息,则不需要重新加载位置,否则可以根据需要调用requestLocation()。例如,对于搜索请求,您首先调用requestLocation(),然后根据位置给出答案。 - Lyju I Edwinson
这段代码完全错误。在主线程上调用locationServicesEnabled()会导致运行时警告。如果当前状态未知,应该在didChangeAuthorization委托方法中调用requestWhenInUseAuthorization()。你从未调用过startUpdatingLocation(当状态被授权时,应该在didChangeAuthorization委托中调用)。 - HangarRash

16

首先在您的项目中添加两个框架

1:MapKit

2:CoreLocation(自XCode 7.2.1起不再需要)

在您的类中定义

var manager:CLLocationManager!
var myLocations: [CLLocation] = []

然后在viewDidLoad方法中编写以下代码:

manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()

//Setup our Map View
mapobj.showsUserLocation = true
不要忘记在plist文件中添加这两个值。
1: NSLocationWhenInUseUsageDescription

2: NSLocationAlwaysUsageDescription

viewDidLoad中的代码完全错误。即使已经授权,它也会不必要地请求授权。而且在确定用户是否有权限之前,它就开始更新位置了。您从未设置委托,因此无法响应授权更改或位置更新。 - HangarRash

14

使用方法:

在类中定义字段

let getLocation = GetLocation()

通过简单的代码在类的函数中使用:

getLocation.run {
    if let location = $0 {
        print("location = \(location.coordinate.latitude) \(location.coordinate.longitude)")
    } else {
        print("Get Location failed \(getLocation.didFailWithError)")
    }
}

类别:

import CoreLocation

public class GetLocation: NSObject, CLLocationManagerDelegate {
    let manager = CLLocationManager()
    var locationCallback: ((CLLocation?) -> Void)!
    var locationServicesEnabled = false
    var didFailWithError: Error?

    public func run(callback: @escaping (CLLocation?) -> Void) {
        locationCallback = callback
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        manager.requestWhenInUseAuthorization()
        locationServicesEnabled = CLLocationManager.locationServicesEnabled()
        if locationServicesEnabled { manager.startUpdatingLocation() }
        else { locationCallback(nil) }
    }

   public func locationManager(_ manager: CLLocationManager,
                         didUpdateLocations locations: [CLLocation]) {
        locationCallback(locations.last!)
        manager.stopUpdatingLocation()
    }

    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        didFailWithError = error
        locationCallback(nil)
        manager.stopUpdatingLocation()
    }

    deinit {
        manager.stopUpdatingLocation()
    }
}


不要忘记在info.plist中添加“NSLocationWhenInUseUsageDescription”


2
谢谢!不要忘记在info.plist中添加“NSLocationWhenInUseUsageDescription”。 - Jonas Deichelmann

11
import CoreLocation
import UIKit

class ViewController: UIViewController, CLLocationManagerDelegate {

    var locationManager: CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
    } 

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status != .authorizedWhenInUse {return}
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
        let locValue: CLLocationCoordinate2D = manager.location!.coordinate
        print("locations = \(locValue.latitude) \(locValue.longitude)")
    }
}
由于对requestWhenInUseAuthorization的调用是异步的,因此应用程序在用户授予权限或拒绝权限后调用locationManager函数。因此,在用户授予权限时将位置获取代码放置在该函数中是适当的。这是我发现的最好的有关此问题的教程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接