INTULocationManager 可以輕松獲取 iOS 設(shè)備上的位置信息和設(shè)備方向信息泣崩。它是一個 Objective-C 庫拼岳,并且也可以在 Swift 中使用抬闯。
INTULocationManager 提供基于 Block 塊的異步 API晾浴,一次性或連續(xù)請求獲取當(dāng)前位置信息涌献。它在內(nèi)部管理多個同時進行的位置和方向請求星岗,每個一次性的位置請求可以指定自己所需的精度等級和超時時間填大。INTULocationManager 會在第一個請求進來時自動啟動位置服務(wù),并在所有請求完成后停止位置服務(wù)俏橘,同時動態(tài)管理位置服務(wù)消耗的電量允华,以減少對電池壽命的影響。
CLLocationManager 有哪些問題?
CLLocationManager 需要你手動檢測和處理諸如權(quán)限寥掐、停滯/不準(zhǔn)確的位置靴寂、錯誤等問題。CLLocationManager 使用了更傳統(tǒng)的委托設(shè)計模式召耘,而不是更現(xiàn)代的基于 Block 塊的回調(diào)模式百炬。雖然它可以很好地跟蹤用戶位置隨時間的變化(例如,用于支持轉(zhuǎn)彎的導(dǎo)航系統(tǒng))污它,但要正確地請求一個一次性的位置信息(例如確定用戶當(dāng)前的城市以獲得天氣預(yù)報剖踊,或從當(dāng)前位置自動填寫地址)是非常麻煩的。
INTULocationManager 可以很容易地獲取設(shè)備的當(dāng)前位置信息轨蛤,無論是一次性位置信息還是連續(xù)變化的位置信息蜜宪,以及設(shè)備的連續(xù)方向。對于一次性的位置請求和重復(fù)性的位置更新訂閱祥山,API都是非常簡單的圃验。對于一次性的位置請求,你可以指定你所需要的位置有多精確缝呕,以及你愿意等待多長時間來獲得它澳窑。還支持重大的位置變化監(jiān)控。INTULocationManager 通過自動確定和使用最有效的核心位置精度設(shè)置供常,并在不再需要時自動關(guān)閉位置服務(wù)(如 GPS 或指南針)摊聋,從而節(jié)省設(shè)備的電量。
安裝
INTULocationManager 需要 iOS 9.0 或更高版本栈暇。
使用 CocoaPods
- Add the pod
INTULocationManager
to your Podfile.
pod 'INTULocationManager'
- Run
pod install
from Terminal, then open your app's.xcworkspace
file to launch Xcode. - Import the
INTULocationManager.h
header.
- With
use_frameworks!
in your Podfile- Swift:
import INTULocationManager
- Objective-C:
#import <INTULocationManager/INTULocationManager.h>
(or with Modules enabled:@import INTULocationManager;
)
- Swift:
- Without
use_frameworks!
in your Podfile- Swift: Add
#import "INTULocationManager.h"
to your bridging header. - Objective-C:
#import "INTULocationManager.h"
- Swift: Add
使用 Carthage
- Add the
intuit/LocationManager
project to your Cartfile.
github "intuit/LocationManager"
- Run
carthage update
, then follow the additional steps required to add the iOS and/or Mac frameworks into your project. - Import the INTULocationManager framework/module.
- Swift:
import INTULocationManager
- Objective-C:
#import <INTULocationManager/INTULocationManager.h>
(or with Modules enabled:@import INTULocationManager;
)
手動從 GitHub 導(dǎo)入
- Download all the files in INTULocationManager subdirectory.
- Add the source files to your Xcode project (drag and drop is easiest).
- Import the
INTULocationManager.h
header.
- Swift: Add
#import "INTULocationManager.h"
to your bridging header. - Objective-C:
#import "INTULocationManager.h"
使用
申請訪問位置服務(wù)的權(quán)限
當(dāng)您發(fā)出一個位置請求麻裁,而用戶還沒有授予您的應(yīng)用程序訪問該位置服務(wù)的權(quán)限時,INTULocationManager 會自動處理獲取訪問位置服務(wù)的權(quán)限。
iOS 9及以上
從 iOS 8.0 開始煎源,你必須通過在應(yīng)用程序的 Info.plist
文件中為 NSLocationWhenInUseUsageDescription
或 NSLocationAlwaysUsageDescription
的鍵中設(shè)置描述字符串色迂,為您的應(yīng)用程序如何使用位置服務(wù)提供描述信息。
INTULocationManager 會根據(jù)存在的描述鍵來決定請求哪個級別的權(quán)限手销。您應(yīng)該只請求您的應(yīng)用程序所需的最低權(quán)限級別歇僧,因此建議您使用 "僅在應(yīng)用使用期間允許(When In Use) "級別的權(quán)限,除非您需要更多的訪問權(quán)限锋拖。如果您為這兩個描述鍵都提供了值诈悍,則會請求權(quán)限更高的 "始終允許(always) "級別權(quán)限。
iOS 11
從 iOS 11 開始兽埃,你必須通過在應(yīng)用程序的 Info.plist
文件中為 NSLocationAlwaysAndWhenInUseUsageDescription
鍵設(shè)置一個字符串侥钳,為您的應(yīng)用程序如何使用位置服務(wù)提供描述。
iOS 12
從 iOS 12 開始柄错,開發(fā)者擁有了將 desiredActivityType
設(shè)置為 CLActivityTypeAirborne
的權(quán)限慕趴,用于指定定位活動的行為。
/*
指定定位活動的行為
CLActivityTypeAutomotiveNavigation 汽車導(dǎo)航
CLActivityTypeFitness 步行
CLActivityTypeOtherNavigation 其他導(dǎo)航 如火車 輪船
CLActivityTypeAirborne 飛機導(dǎo)航
CLActivityTypeOther 其他類型
*/
@property(assign, nonatomic) CLActivityType activityType;
獲取當(dāng)前位置 (一次性)
要獲取設(shè)備的當(dāng)前位置鄙陡,請使用方法 requestLocationWithDesiredAccuracy:timeout:block:
冕房。
desiredAccuracy
參數(shù)指定了你所需要的位置的準(zhǔn)確度和最近的位置〕梅可能的值是:
INTULocationAccuracyCity // 城市級精度耙册,5000 米或更高,在過去 10 分鐘內(nèi)收到--最低精度毫捣。
INTULocationAccuracyNeighborhood // 鄰近地區(qū)級精度详拙,1000 米或更遠,在過去5分鐘內(nèi)收到蔓同。
INTULocationAccuracyBlock // 街區(qū)級精度饶辙,100米或更高,在最后1分鐘內(nèi)收到斑粱。
INTULocationAccuracyHouse // 房屋級精度弃揽,15米或更高,在過去15秒內(nèi)收到则北。
INTULocationAccuracyRoom // 房間級精度矿微,5米或更高,在過去5秒內(nèi)收到 -- -- 最高精度尚揣。
desiredActivityType
參數(shù)表示被跟蹤的活動類型涌矢。可能的值是:
CLActivityTypeFitness // 追蹤健身活動快骗,如步行娜庇、跑步塔次、騎車等。
CLActivityTypeAutomotiveNavigation // 跟蹤汽車的位置更新
CLActivityTypeAirborne // 追蹤空中飛機的活動 - iOS 12及以上版本名秀。
CLActivityTypeOtherNavigation // 跟蹤與汽車無關(guān)的車輛導(dǎo)航
CLActivityTypeOther // 追蹤未知活動俺叭。這是默認(rèn)值
timeout
參數(shù)指定了你愿意等待多長時間,以獲得您所請求的精度的位置泰偿。超時參數(shù)保證您的Block 塊將在這段時間內(nèi)執(zhí)行,要么是您所請求的至少準(zhǔn)確度的位置(INTULocationStatusSuccess)蜈垮,要么是在超時間隔結(jié)束前可以確定的任何位置(INTULocationStatusTimedOut)耗跛。傳入 0.0
表示沒有超時(不推薦)。
默認(rèn)情況下攒发,一旦調(diào)用 requestLocationWithDesiredAccuracy:timeout:block:
方法调塌,超時倒計時就會開始。然而惠猿,該方法還有另一個變體羔砾,它包含一個delayUntilAuthorized:
參數(shù),允許你傳遞 YES
來延遲超時倒計時的開始偶妖,直到用戶對系統(tǒng)位置服務(wù)權(quán)限提示做出反應(yīng)(如果用戶還沒有允許或拒絕應(yīng)用訪問)姜凄。
這是一個實例:
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyCity
timeout:10.0
delayUntilAuthorized:YES // 這個參數(shù)是可選的,如果省略趾访,默認(rèn)為NO态秧。
block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// 請求成功,意味著 achievedAccuracy 至少是請求的精度扼鞋,
// currentLocation 包含設(shè)備的當(dāng)前位置申鱼。
}
else if (status == INTULocationStatusTimedOut) {
// 無法在超時時間內(nèi)以要求的精度定位用戶。
// 然而云头,currentLocation 包含了目前可用的最佳位置(如果有的話)捐友,
// 而academicAccuracy則包含了currentLocation中位置的準(zhǔn)確度/近似度信息。
}
else {
// 發(fā)生了錯誤溃槐,更多信息可以查看返回的具體狀態(tài)匣砖。
}
}];
let locationManager = INTULocationManager.sharedInstance()
locationManager.requestLocation(withDesiredAccuracy: .city,
timeout: 10.0,
delayUntilAuthorized: true) { (currentLocation, achievedAccuracy, status) in
if (status == INTULocationStatus.success) {
// 請求成功,意味著 achievedAccuracy 至少是請求的精度昏滴,
// currentLocation 包含設(shè)備的當(dāng)前位置脆粥。
}
else if (status == INTULocationStatus.timedOut) {
// 無法在超時時間內(nèi)以要求的精度定位用戶。
// 然而影涉,currentLocation 包含了目前可用的最佳位置(如果有的話)变隔,
// 而academicAccuracy則包含了currentLocation中位置的準(zhǔn)確度/近似度信息。
}
else {
// 發(fā)生了錯誤蟹倾,更多信息可以查看返回的具體狀態(tài)匣缘。
}
}
訂閱以獲取持續(xù)的位置更新信息
要訂閱以獲取持續(xù)的位置信息更新猖闪,請使用 subscribeToLocationUpdatesWithBlock:
方法。這個方法指示位置服務(wù)使用最高的精度(這也需要最大的功率)肌厨。該 Block 塊將無限執(zhí)行(甚至跨越錯誤培慌,直到取消),每更新一個新的位置就執(zhí)行一次柑爸,無論其準(zhǔn)確性如何吵护。
如果你不需要盡可能高的精度級別,你應(yīng)該使用subscribeToLocationUpdatesWithDesiredAccuracy:block:
方法表鳍。這個方法采用了期望的準(zhǔn)確度級別馅而,并使用它來控制位置服務(wù)所使用的功率,較低的準(zhǔn)確度級別如 Neighborhood和 City 則需要較少的功率譬圣。請注意瓮恭,INTULocationManager 會自動管理系統(tǒng)的位置服務(wù)精度等級,包括當(dāng)有多個活躍的位置請求/訂閱具有不同的期望精度時厘熟。
如果發(fā)生錯誤屯蹦,Block 塊將以 INTULocationStatusSuccess
以外的狀態(tài)執(zhí)行,并且訂閱將被保留绳姨。
這是一個實例:
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToLocationUpdatesWithDesiredAccuracy:INTULocationAccuracyHouse
block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// currentLocation 中有一個新的更新位置登澜,
// 而 achievedAccuracy 表示這個特定位置的準(zhǔn)確性。
} else {
// 發(fā)生了錯誤飘庄,更多信息可查看返回的具體狀態(tài)帖渠。訂閱一直保持有效。
}
}];
訂閱重大位置變更
要訂閱重大位置變化竭宰,請使用 subscribeToSignificantLocationChangesWithBlock:
方法空郊。這將指示位置服務(wù)開始監(jiān)控重大位置變化,這是非常省電的切揭。該 Block 塊將無限期執(zhí)行(直到取消)狞甚,每更新一個新的位置就執(zhí)行一次,無論其準(zhǔn)確性如何廓旬。請注意哼审,如果有其他同時活躍的位置請求或訂閱,則該 Block 塊將為每次位置更新執(zhí)行(而不僅僅是重大位置更改)孕豹。如果您打算只在位置發(fā)生重大變化時才采取行動涩盾,您應(yīng)該根據(jù)從最后一個位置接收到的距離和時間實施自定義過濾。
如果發(fā)生錯誤励背,該 Block 塊將以 INTULocationStatusSuccess
以外的狀態(tài)執(zhí)行春霍,并且該訂閱將被保留。
這是一個實例:
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
if (status == INTULocationStatusSuccess) {
// currentLocation 中有一個新的更新位置叶眉,
// achievedAccuracy 表示這個特定位置的準(zhǔn)確性址儒。
} else {
// 發(fā)生了錯誤芹枷,更多信息可查看返回的具體狀態(tài)。訂閱一直保持有效莲趣。
}
}];
如果你的應(yīng)用程序已獲得 "始終允許(always)"位置服務(wù)授權(quán)鸳慈,且應(yīng)用程序終止時至少有一個活躍的重大位置變更訂閱,則當(dāng)系統(tǒng)檢測到重大位置變更時喧伞,您的應(yīng)用程序可能會在后臺啟動走芋。請注意,當(dāng)應(yīng)用程序終止時潘鲫,您在 INTULocationManager 中的所有活動位置請求和訂閱將被取消翁逞。因此,當(dāng)應(yīng)用程序因重大位置變化而啟動時次舌,您應(yīng)立即使用 INTULocationManager 為重大位置變化設(shè)置新的訂閱,以便接收位置信息兽愤。
下面是一個如何處理因位置發(fā)生重大變化而在后臺啟動的實例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 如果你開始監(jiān)測重大位置變化彼念,隨后你的應(yīng)用被終止,如果有新的事件到來浅萧,系統(tǒng)會自動重新啟動應(yīng)用進入后臺逐沙。
// 重新啟動后,您仍然必須訂閱重要的位置變化以繼續(xù)接收位置事件洼畅。
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToSignificantLocationChangesWithBlock:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
// 這個區(qū)塊將被執(zhí)行吩案,其中包含觸發(fā)后臺應(yīng)用啟動的重大位置變化的詳細(xì)信息。
// 并將繼續(xù)執(zhí)行未來任何重大的地點變更事件(除非取消)帝簇。
}];
}
return YES;
}
管理活動請求或訂閱
在發(fā)出位置請求時徘郭,可以選擇存儲請求 ID,允許你在任何時候強制完成或取消請求丧肴。
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
INTULocationRequestID requestID = [locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyHouse
timeout:5.0
block:locationRequestBlock];
// 強制請求提前完成残揉,類似手動設(shè)置超時(將執(zhí)行該塊)
[[INTULocationManager sharedInstance] forceCompleteLocationRequest:requestID];
// 取消請求(不會執(zhí)行該塊)。
[[INTULocationManager sharedInstance] cancelLocationRequest:requestID];
請注意芋浮,訂閱永遠不會超時抱环;在訂閱上調(diào)用 forceCompleteLocationRequest:
會簡單地取消它。
訂閱連續(xù)的設(shè)備方向更新
要訂閱連續(xù)的標(biāo)題更新纸巷,請使用方法 subscribeToHeadingUpdatesWithBlock:镇草。該方法不設(shè)置任何默認(rèn)的標(biāo)題過濾值,但您可以使用管理器實例上的 headingFilter 屬性來設(shè)置瘤旨。它也不會根據(jù)結(jié)果的準(zhǔn)確性進行過濾梯啤,而是讓你檢查返回的CLHeading對象的 headingAccuracy屬性來決定是否可以接受。
該塊將無限期執(zhí)行(直到取消)存哲,每更新一個新的標(biāo)題就執(zhí)行一次条辟,無論其準(zhǔn)確性如何黔夭。請注意,如果刪除或取消了標(biāo)題請求羽嫡,管理器將自動停止更新設(shè)備標(biāo)題本姥,以保護電池壽命。
如果發(fā)生錯誤杭棵,該塊將以 INTUHeadingStatusSuccess
以外的狀態(tài)執(zhí)行婚惫,并且只有在設(shè)備不支持標(biāo)題時(即狀態(tài) INTUHeadingStatusUnavailable
)才會自動取消訂閱。
這是一個實例:
INTULocationManager *locMgr = [INTULocationManager sharedInstance];
[locMgr subscribeToHeadingUpdatesWithBlock:^(CLHeading *heading, INTUHeadingStatus status) {
if (status == INTUHeadingStatusSuccess) {
// 已有最新的方向信息
NSLog(@"'Heading updates' subscription block called with Current Heading:\n%@", heading);
} else {
// 發(fā)生錯誤魂爪,更多信息可查看返回的具體狀態(tài)先舷。只有當(dāng)設(shè)備不支持航向時,才會取消訂閱滓侍。
}
}];
Example Project
Open the project included in the repository (requires Xcode 6 and iOS 8.0 or later). It contains a LocationManagerExample
scheme that will run a simple demo app. Please note that it can run in the iOS Simulator, but you need to go to the iOS Simulator's Debug > Location menu once running the app to simulate a location (the default is None).
Issues & Contributions
Please open an issue here on GitHub if you have a problem, suggestion, or other comment.
Pull requests are welcome and encouraged! There are no official guidelines, but please try to be consistent with the existing code style.
License
INTULocationManager is provided under the MIT license.
INTU on GitHub
Check out more iOS and OS X open source projects from Intuit!