版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.10.13 星期六 |
前言
很多的app都有定位功能,比如说滴滴,美团等,他们都需要获取客户所在的位置,并且根据位置推送不同的模块数据以及服务,可以说,定位方便了我们的生活,接下来这几篇我们就说一下定位框架
CoreLocation
。感兴趣的可以看我写的上面几篇。
1. CoreLocation框架详细解析 —— 基本概览(一)
2. CoreLocation框架详细解析 —— 选择定位服务的授权级别(二)
3. CoreLocation框架详细解析 —— 确定定位服务的可用性(三)
4. CoreLocation框架详细解析 —— 获取用户位置(四)
5. CoreLocation框架详细解析 —— 监控用户与地理区域的距离(五)
6. CoreLocation框架详细解析 —— 确定接近iBeacon(六)
7. CoreLocation框架详细解析 —— 将iOS设备转换为iBeacon(七)
8. CoreLocation框架详细解析 —— 获取指向和路线信息(八)
9. CoreLocation框架详细解析 —— 在坐标和用户友好的地名之间转换(九)
开始
首先看一下写作环境
Swift 4.2, iOS 12, Xcode 10
iOS具有非常强大的API,可用于跟踪用户位置和使用地图。您可能正在为当地的咖啡馆制作应用程序,并希望在附近时通知用户特别优惠。或者,你正在制作音乐播放器,并且当用户进入健身房时你想要开始播放一些有弹性的节拍。但是,始终跟踪位置可以非常快地耗尽电池!在这个Core Location教程中,您将学习如何使用框架中一些鲜为人知但功能非常强大的功能。您将学习如何创建一个应用程序,记录白天用户的移动,但也不会耗尽设备的大部分电池。
在本文中,您将制作一个旅行记录应用程序。想象一下,你正在前往一个新的城市。此应用程序不会保留日记,而是会自动跟踪您访问的位置,以便您以后记住它们并将其与您的朋友进行比较。
以下是此应用的功能:
- 跟踪用户的位置,即使应用程序未打开也是如此。
- 当应用程序记录新位置时,向用户发送本地通知。
- 将这些位置保存在文件中。
- 显示已记录位置的列表。
- 显示包含用户位置和记录位置的地图。
- 允许用户手动记录其当前位置。
首先,使用本教程的入门项目。 现在,该应用程序没有做太多。 在第一个选项卡上,您有一个包含位置的空列表。 在第二个选项卡上,您将看到一个空的地图视图。
下面我们就进入正题了。
1. AppDelegate.swift
您在文件顶部还有两个额外的导入:
import CoreLocation
import UserNotifications
CoreLocation
框架侦听用户位置更新。 当应用程序记录新位置时,您将使用UserNotifications
框架显示横幅通知。
您还可以在类声明中看到两个额外的属性:
let center = UNUserNotificationCenter.current()
let locationManager = CLLocationManager()
通过这两个属性,您将访问上述两个框架的API。
2. PlacesTableViewController.swift
这是应用程序的第一个tab -- UITableViewController
子类 - 具有空数据源实现。
3. MapViewController.swift
这是第二个选项卡的视图控制器。 你有从故事板上挂起的MKMapView
。 您还可以在导航栏中为加号按钮设置IBAction
。
4. Location.swift
这是模型类。 它有五个存储的属性:
let latitude: Double
let longitude: Double
let date: Date
let dateString: String
let description: String
- 纬度和经度是你所期望的,位置的坐标。
-
date
日期是记录此位置的确切日期。 -
dateString
是日期的人类可读版本。 -
description
是该位置的人类可读地址。
还有一个用于将Location
对象转换为CLLocationCoordinate2D
的计算属性,这在本教程的后面部分将非常有用。
这个类有两个初始化器;您将在本教程后面了解它们。
您需要在磁盘上保存此类的对象。 为了做到这一点,这个类遵循Codable
。 Codable
是一种Swift 4
语言功能,允许您轻松编码和解码对象。
5. LocationsStorage.swift
最后但并非最不重要的是,使用此单例,您可以将位置保存到应用程序的文档文件夹中。
这个类有几个属性可以从磁盘写入和读取:
private let fileManager: FileManager
private let documentsURL: URL
它还具有访问所有已记录位置的属性,目前,它们在初始化程序中设置为空数组:
private(set) var locations: [Location]
现在你已经开始使用初始代码了,现在是时候添加一些新代码了!
Core Location: Asking for User Locations - 请求用户位置
第一步是请求权限以跟踪用户的位置。 在隐私时代,Apple在保持用户掌控应用可以收集哪些数据方面表现得非常强大。 这就是为什么正确地要求用户允许应用程序访问以收集所需数据非常重要的原因。
1. Providing a Proper Description - 提供正确的描述
要收集位置更改数据,您需要在Info.plist
文件中设置两个特殊字符串:
当应用程序请求许可时,应用程序会显示这些字符串。 只要文本符合以下要求,您可以随意将提示更改为您喜欢的任何文本:
- 鼓励用户为您提供访问权限。
- 让用户确切知道收集数据的方式和原因。
- 声明100%正确。
2. Asking for Locations Permissions - 询问地点权限
打开AppDelegate.swift
并在application(_:didFinishLaunchingWithOptions:):
中的return
语句之前添加此行。
locationManager.requestAlwaysAuthorization()
使用此行,您要求用户允许该应用访问后台和前台的位置数据。
Build并运行项目。 您应该得到一个与此类似的对话框,但它将包含您在本教程前面的Info.plist
文件中设置的字符串:
点按Always Allow。
注意:用户可以限制对后台或后台与前台的位置数据的访问;在这种情况下,开发人员有责任正确地妥善处理这些情况。 为了简化本教程,您将假设用户选择Always Allow。
3. Asking for Notifications Permissions - 请求通知权限
位置权限不是您需要的唯一权限:要显示用户通知,您需要获得权限。
为此,您不必指定任何其他字符串。 只需在刚刚添加的行上方添加此代码:
center.requestAuthorization(options: [.alert, .sound]) { granted, error in
}
在这里,您传递options
以指定要发布的通知类型。 您还包含一个空闭包,因为在本教程中,您假设用户始终向您授予权限。 您可以在此闭包中处理拒绝。
Build并运行。 你应该看到这个对话框:
点击Allow
Choosing the Most Appropriate Locations Data - 选择最合适的位置数据
Core Location 框架有许多方法来跟踪用户的位置,每个方法都有不同的特征:
- Standard location services - 标准位置服务:高电池损耗,定位精度高。 非常适合导航或健身应用。
- Significant location changes - 重大位置变化:中等电池损耗,中等位置精度。 低停止精度。
- Regional monitoring - 区域监测:低电池电量损耗,很棒的位置精度。 需要特定区域才能进行监控。
这些都不适合您的应用。 低电池影响是必须的 - 否则用户不太可能使用该应用程序。 更重要的是,区域监控也是不受欢迎的,因为您限制用户移动到某些特定区域。
幸运的是,您可以使用另外一个API。
1. Visit Monitoring - 访问监控
访问监控允许您跟踪目的地 - 用户停留一段时间的地方。 每当检测到新的访问时它都会唤醒应用程序,并且非常节能并且不依赖于任何地标。
Subscribe to Location Changes - 订阅位置更改
现在您已经了解了用于获取用户位置的众多核心位置API中的哪一个,现在是时候开始实现它了!
1. CLLocationManager
在AppDelegate.swift
中,在此行下方:
locationManager.requestAlwaysAuthorization()
添加如下代码
locationManager.startMonitoringVisits()
locationManager.delegate = self
第一行启动监听功能。 Core Location
使用代理回调来通知您位置更改。
现在,在文件底部添加此扩展名:
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
// create CLLocation from the coordinates of CLVisit
let clLocation = CLLocation(latitude: visit.coordinate.latitude, longitude: visit.coordinate.longitude)
// Get location description
}
func newVisitReceived(_ visit: CLVisit, description: String) {
let location = Location(visit: visit, descriptionString: description)
// Save location to disk
}
}
第一种方法是在记录新访问时从CLLocationManager
回调并为您提供CLVisit
。
CLVisit
有四个属性:
- 1)
arrivalDate
:visit开始的日期。 - 2)
departureDate
:visit结束的日期。 - 3)
coordinate
:设备正在visit的区域的中心。 - 4)
horizontalAccuracy
:该区域的半径估计值(以米为单位)。
您需要从此数据创建一个Location
对象,如果您还记得,有一个初始化程序,它接受CLVisit
,日期和描述字符串:
init(_ location: CLLocationCoordinate2D, date: Date, descriptionString: String)
上面唯一缺少的是descriptionString
。
2. Location Description - 位置说明
要获得描述,您将使用CLGeocoder
。 地理编码是将坐标转换为现实世界中的地址或地名的过程。 如果要从一组坐标中获取地址,请使用反向地理编码。 值得庆幸的是,Core Location为我们提供了一个CLGeocoder
类,它可以为我们做到这一点!
仍然在AppDelegate.swift
中,在类的顶部添加此属性:
static let geoCoder = CLGeocoder()
现在,在locationManager(_:didVisit :)
的底部,添加以下代码:
AppDelegate.geoCoder.reverseGeocodeLocation(clLocation) { placemarks, _ in
if let place = placemarks?.first {
let description = "\(place)"
self.newVisitReceived(visit, description: description)
}
}
在这里,您要求geoCoder
从该位置获取地标(placemarks)
。 地标包含一系列有关坐标的有用信息,包括它们的地址。 然后,您可以从第一个地标创建描述字符串。 获得描述字符串后,可以调用newVisitReceived(_:description :)
。
3. Sending Local Notifications - 发送本地通知
现在,是时候在记录新的访问位置时通知用户了。 在newVisitReceived(_:description :)
的底部,添加以下内容:
// 1
let content = UNMutableNotificationContent()
content.title = "New Journal entry 📌"
content.body = location.description
content.sound = .default
// 2
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: location.dateString, content: content, trigger: trigger)
// 3
center.add(request, withCompletionHandler: nil)
下面详细分说:
- 1) 创建通知内容。
- 1) 使用该触发器创建一秒长触发和通知请求。
- 1) 通过将请求添加到通知中心来安排通知。
Build并运行应用程序。 此时,该应用程序可用,因为它记录访问并通知用户。
如果您使用真实设备并有时间散步,您可以立即测试您的工作。 去某个地方停下来喝杯咖啡。 访问要求您在某个地方停留一段时间。 您应该收到一些通知,如下所示:
正在记录访问,但访问尚未持续。
Faking Data (Optional) - 伪造数据(可选)
散步对你的身体有好处,但是现在在构建这个应用程序的过程中可能会有问题! 要在不实际行走的情况下测试应用程序,您可以使用Route.gpx文件。 这种文件允许您模拟设备或模拟器的GPS位置。 这个特殊的文件将模拟在库比蒂诺的Apple校园周围散步。
要使用它,请在Debug
区域中单击Simulate Location
图标,然后从列表中选择Route
:
您可以使用地图或地图应用打开标签,以查看步行路线。
1. Faking CLVisits - 伪造CLVisits
iOS在幕后记录CLVisits
,有时您可能需要等待30分钟才能获得回调! 为避免这种情况,您需要实现伪造CLVisit
记录的机制。 您将创建CLVisit
实例,并且由于CLVisit没有可访问的初始化程序,因此您需要创建一个子类。
将其添加到AppDelegate.swift
的末尾:
final class FakeVisit: CLVisit {
private let myCoordinates: CLLocationCoordinate2D
private let myArrivalDate: Date
private let myDepartureDate: Date
override var coordinate: CLLocationCoordinate2D {
return myCoordinates
}
override var arrivalDate: Date {
return myArrivalDate
}
override var departureDate: Date {
return myDepartureDate
}
init(coordinates: CLLocationCoordinate2D, arrivalDate: Date, departureDate: Date) {
myCoordinates = coordinates
myArrivalDate = arrivalDate
myDepartureDate = departureDate
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
使用此子类,您可以为CLVisit
的属性提供初始值。
2. Set Up locationManager - 设置locationManager
现在,您需要locationManager
在位置更改时通知您。 为此,在application(_:didFinishLaunchingWithOptions:)
末尾,在return
语句之前,添加以下内容:
// 1
locationManager.distanceFilter = 35
// 2
locationManager.allowsBackgroundLocationUpdates = true
// 3
locationManager.startUpdatingLocation()
以下是这些行的作用:
- 1) 当位置更改为n米或更多时,接收位置更新。
- 2) 允许在后台跟踪位置。
- 3) 开始监听。
您可以注释掉这3行以关闭访问伪造。
3. Handle Fake Visits - 处理伪造访问
是时候处理位置回调了。 为此,将以下代码添加到AppDelegate
的CLLocationManagerDelegate
扩展:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// 1
guard let location = locations.first else {
return
}
// 2
AppDelegate.geoCoder.reverseGeocodeLocation(location) { placemarks, _ in
if let place = placemarks?.first {
// 3
let description = "Fake visit: \(place)"
//4
let fakeVisit = FakeVisit(
coordinates: location.coordinate,
arrivalDate: Date(),
departureDate: Date())
self.newVisitReceived(fakeVisit, description: description)
}
}
}
- 1) 丢弃除第一个以外的所有位置。
- 2) 像往常一样抓住位置描述。
- 3) 将访问标记为伪造。
- 4) 创建一个
FakeVisit
实例并将其传递给newVisitReceived
函数。
Build并运行应用程序。 打开路线位置模拟。 关闭应用程序或锁定iPhone,您应该每分钟获得一次新通知。
后记
本篇主要讲述了跟踪访问位置,感兴趣的给个赞或者关注~~~