演示代码
ARKit和CoreLocation:第一部分
ARKit和CoreLocation:第二部分
ARKit和CoreLocation:第三部分
欢迎回来!
这篇文章是ARKit和Core Location系列的第三部分。在第一部分中,我们介绍了ARKit的基础知识并放置了对象,在第二部分中,我们想出了如何计算我们需要进行旅行的坐标以及如何将这些位置从二维图转换为三维图真实世界。
现在是时候应用我们学到的东西了。我已经创建了一个演示项目,其中包含了我们之前已经进入实际应用的所有内容。如果您尝试运行它,请务必更改目标位置。否则,如果你太遥远,它可能会崩溃(我们稍后会修复它。)这只是粗略的功能。
你可以在这里查看完成的代码:https://github.com/chriswebb09/ARKitNavigationDemo
优化
我提出的演示项目旨在演示概念,而不是提供出色的用户体验。但是我们可以采取哪些措施来改善它?
挑战
在使用ARKit和Core Location时遇到了很多挑战。其中一些问题是可以解决的,其他问题则更为根本,而且目前的硬件无法解决。即使它们不可解决,您也可以通过一些快速更改来减轻它们的最坏后果。
混凝土峡谷
首先,使用ARKit和Core Location时遇到的最大挑战是位置准确性问题。如果你去过纽约市,你会发现网格系统会产生这些混凝土,钢铁和玻璃的峡谷。虽然看起来非常棒,但如果你试图找到某人,这个地形可能会造成问题。GPS信号是从卫星发出的微波,这意味着信号可以被表面吸收或反射。这种干扰在纽约市特别明显。效果可能是您的位置(当您的手机感知它)不规律地跳跃。
在PokemonGO中,其中一个主要功能是Pokemon在地图上进行地理定位。你必须在Pokemon的某个半径范围内才能搞定它。这导致了一个有趣的效果。你可以坐在某个地方玩耍,然后翘曲到几个街区外的地方,并且能够在新的位置与口袋妖怪交战,然后再扭曲到原来的位置。
有了像PokemonGO这样的游戏,这不是什么大不了的事,它甚至可能是一个奖励。通过导航,这是另一个故事。一种解决方案是在设置标记后停止更新位置或仅以特定间隔使用它。虽然这不是最好的结果,但它是最容易实现的。这种不稳定的功能除了耗尽电池外,AR / SceneKits坐标系还提供了充分的理由来探索不同的工具集,以保持对您所在位置的了解。
位置意识
鉴于位置监控和意识是我们项目的基础,在我们进一步研究之前,我们需要了解如何在用户使用应用程序时监控用户位置。
定义
CLLocationManager: CLLocationManager是管理应用程序的位置相关事件的对象。
我们还需要涵盖Apple隐私权。Apple要求您的应用程序询问用户权限并让他们同意,然后才能监控他们的位置。在监控用户位置方面有多个隐私级别。您应该在info.plist中添加适当的一个。
隐私选项
使用中授权:您的应用可以使用大多数服务,但无法使用自动重新启动应用的服务。您的应用必须始终在前台运行时启动服务。如果您为应用启用了后台位置功能,则会在后台唤醒已暂停的应用以处理位置事件。但是,如果您的应用未运行,则无法启动。
始终授权: 您的应用可以使用所有位置服务,并且可以从前台或后台启动这些服务。如果您的应用未运行时发生与位置相关的事件,系统会启动您的应用并发送活动。
代理
我们的LocationService应该符合CLLocationManagerDelegate协议。我们不希望将LocationService直接绑定到控制器,因此我们将委托将位置更新松散地耦合到UI。
import Foundation
import CoreLocation
protocol LocationServiceDelegate: class {
func trackingLocation(for currentLocation: CLLocation)
func trackingLocationDidFail(with error: Error)
}
现在,当我们的LocationService中发生位置更新时,我们可以将新信息推送到我们的控制器中进行操作。
定位服务
现在我们已经让我们的代理平手了,让我们转移到LocationService!因为CLLocationManagerDelegate继承自NSObjectProtocol,所以此类应该是NSObject的子类,并且符合CLLocationMangerProtocol协议。回归到NS类可能听起来很奇怪,但由于Objective-C中的所有内容都继承自NSObject,而Apple的使命是使Swift和Objective-C尽可能兼容,你会看到NSObject不时弹出。
定义
NSObjectProtocol:所有Objective-C对象符合的基本协议。
NSObject:大多数Objective-C类的基类。继承自NSObject为子类提供了系统运行时的接口和Objective-C对象的基本行为。
Cocoa根类NSObject采用此协议,因此从中继承的所有对象NSObject 都具有此协议描述的功能。
import Foundation
import CoreLocation
class LocationService: NSObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
var delegate: LocationServiceDelegate?
var currentLocation: CLLocation?
override init() {
super.init()
locationManager = CLLocationManager()
guard let locationManager = locationManager else { return }
switch(CLLocationManager.authorizationStatus()) {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
lastLocation = locationManager.location
case .notDetermined, .restricted, .denied:
startUpdatingLocation()
}
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.headingFilter = kCLHeadingFilterNone
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.delegate = self
}
func startUpdatingLocation() {
locationManager?.startUpdatingLocation()
}
func stopUpdatingLocation() {
locationManager?.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
self.delegate?.locationManagerDidUpdateLocation(self, location: location)
}
currentLocation = manager.location
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
updateLocationDidFailWithError(error: error as NSError)
}
func updateLocation(currentLocation: CLLocation) {
guard let delegate = delegate else { return }
delegate.trackingLocation(for: currentLocation)
}
func updateLocationDidFailWithError(error: Error) {
guard let delegate = delegate else { return }
delegate.trackingLocationDidFail(with: error)
}
}
无论我们在哪个类中实例化LocationService,我们现在都可以使用我们的协议一致性来传递该类和服务之间的位置更新。
包起来
这应该包括现在的位置监控。在下一篇文章中,我们将设置MapKit来帮助我们进行导航。
原文:https://medium.com/journey-of-one-thousand-apps/arkit-and-corelocation-part-three-98b1d51e2eac
Christopher Webb-Orenstein