在iOS開發(fā)中,定位是很多App都需要使用的功能。本文主要對(duì)iOS中的定位知識(shí)點(diǎn)進(jìn)行介紹。本文代碼環(huán)境為:Xcode 10.1 + Swift 4.2。
一、模塊與常見類
- 定位所包含的類都在
CoreLocation模塊中,所以必須導(dǎo)入import CoreLocation -
CLLocation:表示某個(gè)位置的地理信息,比如經(jīng)緯度、海拔等 -
CLLocationManager:定位管理器,可以理解為定位不能自己工作,需要有個(gè)管理者對(duì)它進(jìn)行全過(guò)程監(jiān)督。 -
CLGeocoder:地理編碼,分為兩種- 正向地理編碼:根據(jù)位置信息,獲取具體的經(jīng)緯度等信息
- 反向地理編碼:根據(jù)給定的經(jīng)緯度等信息,獲取位置信息
-
CLPlacemark:位置信息,包含的信息如國(guó)家、城市、街道等 -
CLLocationManagerDelegate:定位代理,不管是定位成功與失敗,都會(huì)有相應(yīng)的代理方法回調(diào) - 具體的工作流程
(1)CLLocationManager發(fā)起定位,定位成功或者失敗都會(huì)回調(diào)CLLocationManagerDelegate中相應(yīng)的代理方法
(2)在成功的代理方法中獲取CLLocation對(duì)象,進(jìn)而獲取經(jīng)緯度
(3)通過(guò)CLGeocoder獲取經(jīng)緯度對(duì)應(yīng)的位置信息CLPlacemark
(4)通過(guò)CLPlacemark獲取具體的位置信息
二、權(quán)限
在iOS中,隱私保護(hù)特別好,凡事需要定位的時(shí)候,第一次必須彈出對(duì)話框給用戶選擇,一共有兩種權(quán)限
- 使用時(shí)才定位權(quán)限,使用這種,必須走兩步
(1)程序中發(fā)起requestWhenInUseAuthorization
(2)在info.plist對(duì)應(yīng)的位置寫明申請(qǐng)權(quán)限的具體原因 - 一直可以定位權(quán)限,使用這種,也是兩步
(1)程序中發(fā)起requestAlwaysAuthorization
(2)在info.plist對(duì)應(yīng)的位置寫明申請(qǐng)權(quán)限的具體原因 - 配置字段說(shuō)明
- iOS 8之前只需要配置
Privacy - Location Usage Description - iOS 8 - iOS 10 只有兩個(gè)配置
Privacy - Location Always Usage Description
Privacy - Location When In Use Usage Description - iOS 11之后多了
Privacy - Location Always and When In Use Usage Description,所以iOS11之后必須配置的是
Privacy - Location When In Use Usage Description和Privacy - Location Always and When In Use Usage Description
權(quán)限原因填寫
- iOS 8之前只需要配置
注意:上架的App這個(gè)原因必須寫明確
三、模擬器定位
由于定位需要GPS,所以一般情況下,都需要真機(jī)進(jìn)行測(cè)試,筆者在教學(xué)過(guò)程中,經(jīng)常使用的是一種模擬定位,這種定位需要準(zhǔn)備一個(gè)gpx 的文件,可以取名 XXX.gpx,里面的內(nèi)容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<gpx version="1.1"
creator="GMapToGPX 6.4j - http://www.elsewhere.org/GMapToGPX/"
xmlns="http://www.topografix.com/GPX/1/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<!--安徽商貿(mào)職業(yè)技術(shù)學(xué)院 谷歌地球:31.2906511800,118.3623587000-->
<wpt lat="31.2906511800" lon="118.3623587000">
<name>安徽商貿(mào)職業(yè)技術(shù)學(xué)院</name>
<cmt>中國(guó)安徽省蕪湖市弋江區(qū)文昌西路24號(hào) 郵政編碼: 241002</cmt>
<desc>中國(guó)安徽省蕪湖市弋江區(qū)文昌西路24號(hào) 郵政編碼: 241002</desc>
</wpt>
</gpx>
將自己的定位信息填寫進(jìn)xml對(duì)應(yīng)的位置即可,然后選擇Edit Scheme,在Options中選擇自己的gpx 的文件,這樣模擬器運(yùn)行的時(shí)候就會(huì)讀取該文件的位置信息。

Edit Scheme
四、后臺(tái)定位
如果你的App需要后臺(tái)定位,可以這樣做,首先在Capabilities中打開后臺(tái)模式

后臺(tái)模式
前面說(shuō)過(guò)定位權(quán)限分兩種,針對(duì)這兩種情況,后臺(tái)定位的代碼不一樣,效果也不一樣
-
使用時(shí)才定位權(quán)限需要加上locationManager.allowsBackgroundLocationUpdates = true
開啟后臺(tái)定位,而一直可以定位權(quán)限不需要寫任何額外代碼 -
使用時(shí)才定位權(quán)限退出后,手機(jī)頂部會(huì)有藍(lán)條提示,而一直可以定位權(quán)限則沒(méi)有

后臺(tái)定位藍(lán)條提醒
五、開發(fā)步驟與示例代碼
- 導(dǎo)入
CoreLocation模塊 - 創(chuàng)建
CLLcationManager對(duì)象,設(shè)置參數(shù)和代理,請(qǐng)求定位授權(quán)并配置info.plist - 調(diào)用
CLLcationManager對(duì)象的startUpdatingLocation方法進(jìn)行定位 - 實(shí)現(xiàn)代理方法,在定位成功的方法中進(jìn)行位置信息的處理
import UIKit
import CoreLocation
class ViewController: UIViewController {
//定位需要一個(gè)CLLocationManager
lazy var locationManager:CLLocationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
setupManager()
}
func setupManager(){
//默認(rèn)情況是這樣的,每當(dāng)位置改變時(shí)LocationManager就調(diào)用一次代理。通過(guò)設(shè)置distanceFilter可以實(shí)現(xiàn)當(dāng)位置改變超出一定范圍時(shí)LocationManager才調(diào)用相應(yīng)的代理方法。這樣可以達(dá)到省電的目的。
locationManager.distanceFilter = 300
//精度 比如為10 就會(huì)盡量達(dá)到10米以內(nèi)的精度
locationManager.desiredAccuracy = kCLLocationAccuracyBest
//代理
locationManager.delegate = self
//第一種:能后臺(tái)定位但是會(huì)在頂部出現(xiàn)大藍(lán)條(打開后臺(tái)定位的開關(guān))
//允許后臺(tái)定位
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestWhenInUseAuthorization()
//第二種:能后臺(tái)定位并且不會(huì)出現(xiàn)大藍(lán)條
//locationManager.requestAlwaysAuthorization()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//發(fā)起位置更新(定位)會(huì)一直輪詢,耗電
self.locationManager.startUpdatingLocation()
}
}
extension ViewController : CLLocationManagerDelegate{
//定位成功
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
//地理編碼的類
let gecoder = CLGeocoder()
if let location = location {
//反地理編碼 轉(zhuǎn)換成 具體的地址
gecoder.reverseGeocodeLocation(location) { (placeMarks, error) in
//CLPlacemark -- 國(guó)家 城市 街道
let placeMark = placeMarks?.first
if let placeMark = placeMark{
print("\(placeMark.country!) -- \(placeMark.name!) -- \(placeMark.locality!)")
}
}
}
self.locationManager.stopUpdatingLocation()
}
//定位失敗
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
}
六、代碼運(yùn)行效果

運(yùn)行效果
