INTULocationManager 可以轻松获取设备的当前位置,并在 iOS 上实时前进。它是一个 Objective-C 库,同时在 Swift 中也表现优异。
INTULocationManager 提供了一个基于块的异步 API 来请求当前位置,一次性或持续不断地。它内部管理多个同时进行的位置和航向请求,并且每个一次性位置请求都可以指定自己的所需精度水平和超时持续时间。INTULocationManager 在收到第一个请求时自动启动位置服务,并在所有请求完成时停止位置服务,同时动态管理位置服务的功耗,以减少对电池寿命的影响。
CLLocationManager 有什么问题?
CLLocationManager 需要手动检测和处理权限、无效/不准确的定位、错误等问题。CLLocationManager 使用更传统的代理模式,而不是现代的基于块的回调模式。虽然它能很好地跟踪用户位置随时间的变化(例如,用于实时导航),但正确请求单一位置更新(例如,以确定用户的当前城市以获取天气预报或自动填充当前地址)却非常繁琐。
INTULocationManager 可以轻松地请求设备的当前位置(一次性或持续),以及设备的持续航向。API 对于一次性位置请求和重复订阅位置更新都非常简单。对于一次性位置请求,您可以指定所需的精度以及等待获取位置的时间。它还支持显著位置变化监控系统。INTULocationManager 通过自动确定并使用最有效率的 Core Location 精度设置,以及当位置服务不再需要时自动关闭位置服务(例如 GPS 或罗盘)来节省电量。
安装
INTULocationManager 需要 iOS 9.0 或更高版本。
使用 CocoaPods
- 将 pod
INTULocationManager
添加到您的 Podfile。
pod 'INTULocationManager'
- 从终端运行
pod install
,然后打开您的应用的.xcworkspace
文件以启动 Xcode。 - 导入
INTULocationManager.h
头文件。
- 在您的 Podfile 中包含
use_frameworks!
- Swift:
import INTULocationManager
- Objective-C:
#import <INTULocationManager/INTULocationManager.h>
(或启用 Modules 功能:@import INTULocationManager;
)
- Swift:
- 在不包含
use_frameworks!
的 Podfile 中- Swift: 将
#import "INTULocationManager.h"
添加到您的头桥文件中。 - Objective-C:
#import "INTULocationManager.h"
- Swift: 将
Carthage
使用- 将
intuit/LocationManager
项目添加到您的 Cartfile。
github "intuit/LocationManager"
- 运行
carthage update
,然后遵循 添加 iOS 和/或 Mac 框架所需的额外步骤。 - 导入 INTULocationManager 框架/模块。
- Swift:
import INTULocationManager
- Objective-C:
#import <INTULocationManager/INTULocationManager.h>
(或启用 Modules 功能:@import INTULocationManager;
)
从 GitHub 手动
- 下载 INTULocationManager 子目录 中的所有文件。
- 将源文件添加到您的 Xcode 项目中(拖放是最简单的方法)。
- 导入
INTULocationManager.h
头文件。
- Swift: 将
#import "INTULocationManager.h"
添加到您的头桥文件中。 - Objective-C:
#import "INTULocationManager.h"
用法
请求访问位置服务权限
INTULocationManager会在发出位置请求且用户尚未授予应用程序访问该位置服务的权限时,自动处理获取访问位置服务的权限。
iOS 9及以上
从iOS 8开始,您必须在应用程序的Info.plist
文件中设置一个字符串为NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
键,为应用程序如何使用位置服务提供描述。INTULocationManager会根据哪个描述键存在来确定请求哪个权限级别。您应该只请求应用程序所需的最小权限级别,因此除非确实需要更多访问权限,否则建议使用"当在应用中使用"级别。如果您为这两个描述键都提供了值,则将请求更宽松的"始终"级别。
iOS 11
从iOS 11开始,您必须在应用程序的Info.plist
文件中设置一个字符串以为键NSLocationAlwaysAndWhenInUseUsageDescription
提供描述,说明应用程序如何使用位置服务。
iOS 12
从iOS 12开始,您将可以使用设置desiredActivityType
为CLActivityTypeAirborne
。
获取当前位置(一次性)
要获取设备的当前位置,请使用方法 requestLocationWithDesiredAccuracy:timeout:block:
。
desiredAccuracy
参数指定您需要的位置的精度和更新时间。可能的值有
INTULocationAccuracyCity // 5000 meters or better, received within the last 10 minutes -- lowest accuracy
INTULocationAccuracyNeighborhood // 1000 meters or better, received within the last 5 minutes
INTULocationAccuracyBlock // 100 meters or better, received within the last 1 minute
INTULocationAccuracyHouse // 15 meters or better, received within the last 15 seconds
INTULocationAccuracyRoom // 5 meters or better, received within the last 5 seconds -- highest accuracy
desiredActivityType
参数表示正被追踪的活动类型。可能的值有
CLActivityTypeFitness // Track fitness activities such as walking, running, cycling, and so on
CLActivityTypeAutomotiveNavigation // Track location changes to the automobile
CLActivityTypeAirborne // Track airborne activities - iOS 12 and above
CLActivityTypeOtherNavigation // Track vehicular navigation that are not automobile related
CLActivityTypeOther // Track unknown activities. This is the default value
timeout
参数指定您愿意等待多久才能获取您请求的精度位置。超时保证在指定时间内执行,要么是至少包含请求精度的位置(INTULocationStatusSuccess
),要么是在超时前可以确定的任何位置(INTULocationStatusTimedOut
)。传递 0.0
表示没有超时(不推荐)。
默认情况下,计时从调用 requestLocationWithDesiredAccuracy:timeout:block:
方法开始。但是,此方法还有另一种变体,包括 delayUntilAuthorized:
参数,允许将超时计时的开始延迟到用户对系统位置服务权限提示做出响应(如果用户尚未允许或拒绝应用程序访问)。
以下是一个示例
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyCity
timeout:10.0
delayUntilAuthorized:YES // This parameter is optional, defaults to NO if omitted
block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// Request succeeded, meaning achievedAccuracy is at least the requested accuracy, and
// currentLocation contains the device's current location.
}
else if (status == INTULocationStatusTimedOut) {
// Wasn't able to locate the user with the requested accuracy within the timeout interval.
// However, currentLocation contains the best location available (if any) as of right now,
// and achievedAccuracy has info on the accuracy/recency of the location in currentLocation.
}
else {
// An error occurred, more info is available by looking at the specific status returned.
}
}];
let locationManager = INTULocationManager.sharedInstance()
locationManager.requestLocation(withDesiredAccuracy: .city,
timeout: 10.0,
delayUntilAuthorized: true) { (currentLocation, achievedAccuracy, status) in
if (status == INTULocationStatus.success) {
// Request succeeded, meaning achievedAccuracy is at least the requested accuracy, and
// currentLocation contains the device's current location
}
else if (status == INTULocationStatus.timedOut) {
// Wasn't able to locate the user with the requested accuracy within the timeout interval.
// However, currentLocation contains the best location available (if any) as of right now,
// and achievedAccuracy has info on the accuracy/recency of the location in currentLocation.
}
else {
// An error occurred, more info is available by looking at the specific status returned.
}
}
订阅持续位置更新
要订阅持续的位置更新,请使用方法 subscribeToLocationUpdatesWithBlock:
。此方法指示位置服务使用最高可用精度(这也需要最大功率)。无论精度如何,都会无限期(即使在发生错误或取消之前)执行块,每次为新更新的位置执行一次。
如果您不需要最高的精度级别,请改用 subscribeToLocationUpdatesWithDesiredAccuracy:block:
。此方法获取期望的精度级别,并使用它来控制位置服务使用的功率,例如,Neighborhood 和 City 级别的精度需要较低的功率。请注意,INTULocationManager 将自动管理系统位置服务的精度级别,包括当有多个活动位置请求/订阅具有不同期望精度时。
如果发生错误,块将带有非 INTULocationStatusSuccess
的状态执行,并且订阅将保持活动状态。
以下是一个示例
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToLocationUpdatesWithDesiredAccuracy:INTULocationAccuracyHouse
block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// A new updated location is available in currentLocation, and achievedAccuracy indicates how accurate this particular location is.
}
else {
// An error occurred, more info is available by looking at the specific status returned. The subscription has been kept alive.
}
}];
订阅重大位置变更
要订阅重要的位置变化,请使用方法 subscribeToSignificantLocationChangesWithBlock:
。这将指示位置服务开始监控重要位置变化,这非常节能。该块将无限执行(直到取消),对于每个新的更新位置,无论其准确性如何。注意,如果存在其他同时活跃的位置请求或订阅,该块将在每次位置更新时执行(而不仅是重要位置变化)。如果您只想在位置发生重大变化时采取行动,您应根据接收到的最后位置的距离和时间实现自定义过滤。
如果发生错误,块将带有非 INTULocationStatusSuccess
的状态执行,并且订阅将保持活动状态。
以下是一个示例
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// A new updated location is available in currentLocation, and achievedAccuracy indicates how accurate this particular location is.
}
else {
// An error occurred, more info is available by looking at the specific status returned. The subscription has been kept alive.
}
}];
如果您的应用程序已获得“始终”位置服务授权,并且您的应用程序至少有一个活跃的重要位置变化订阅被终止,则当系统检测到重要位置变化时,您的应用程序可能会在后台运行。请注意,当应用程序终止时,使用INTULocationManager的所有活动位置请求和订阅都会被取消。因此,当应用程序由于重要位置变化而启动时,您应该立即使用INTULocationManager为新的重要位置变化设置新的订阅,以接收位置信息。
以下是从重要位置变化中启动后台的示例
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// If you start monitoring significant location changes and your app is subsequently terminated, the system automatically relaunches the app into the background if a new event arrives.
// Upon relaunch, you must still subscribe to significant location changes to continue receiving location events.
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
// This block will be executed with the details of the significant location change that triggered the background app launch,
// and will continue to execute for any future significant location change events as well (unless canceled).
}];
}
return YES;
}
管理活动请求或订阅
在发出位置请求时,您可以选择存储请求ID,这使得您可以在任何时间强制完成或取消请求
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
INTULocationRequestID requestID = [locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyHouse
timeout:5.0
block:locationRequestBlock];
// Force the request to complete early, like a manual timeout (will execute the block)
[[INTULocationManager sharedInstance] forceCompleteLocationRequest:requestID];
// Cancel the request (won't execute the block)
[[INTULocationManager sharedInstance] cancelLocationRequest:requestID];
请注意,订阅从不超时;对订阅调用 forceCompleteLocationRequest:
将仅取消它。
订阅连续航向更新
要订阅连续航向更新,请使用方法 subscribeToHeadingUpdatesWithBlock:
。该方法不设置任何默认航向过滤器值,但您可以使用管理实例上的 headingFilter
属性来设置。它也不基于结果的准确性进行过滤,而是将其留给您来检查返回的 CLHeading
对象的 headingAccuracy
属性以确定它是否可接受。
该块将无限执行(直到取消),在新的更新航向时执行一次,无论其准确性如何。注意,如果删除或取消航向请求,管理器将自动停止更新设备的航向,以节省电池寿命。
如果发生错误,块将以除 INTUHeadingStatusSuccess
之外的状态执行,并且只有当设备不支持航向时(即状态 INTUHeadingStatusUnavailable
)才会自动取消订阅。
以下是一个示例
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToHeadingUpdatesWithBlock:^(CLHeading *heading, INTUHeadingStatus status) {
if (status == INTUHeadingStatusSuccess) {
// An updated heading is available
NSLog(@"'Heading updates' subscription block called with Current Heading:\n%@", heading);
} else {
// An error occurred, more info is available by looking at the specific status returned. The subscription will be canceled only if the device doesn't have heading support.
}
}];
示例项目
打开存储库中包含的项目(需要 Xcode 6 和 iOS 8.0 或更高版本)。其中包含一个 LocationManagerExample
方案,该方案将运行一个简单的演示应用。请注意,它可以在 iOS 模拟器中运行,但您需要在运行应用程序后,转到 iOS 模拟器的 调试 > 位置 菜单来模拟位置(默认是 未指定)。
问题和贡献
如果有问题、建议或其他评论,请在 GitHub 上此处打开一个问题。
欢迎并鼓励 Pull requests!虽然没有官方指南,但请尽量与现有代码风格保持一致。
许可协议
INTULocationManager 规范遵循 MIT 许可协议。
INTU 在 GitHub 上
请查看 Intuit 的更多 iOS 和 OS X 开源项目!