瘋狂
前言
上篇文章iOS開發(fā)中的這些權(quán)限,你搞懂了嗎?介紹了一些常用權(quán)限的獲取和請求方法,知道這些方法的使用基本上可以搞定大部分應(yīng)用的權(quán)限訪問的需求。但是,這些方法并不全面,不能涵蓋住所有權(quán)限訪問的方法。
So,筆者在介紹一下剩下的幾種權(quán)限的訪問方法和一些使用上的注意事項,希望能給大家的開發(fā)過程帶來一絲便利。
最后,筆者將經(jīng)常使用的權(quán)限請求方法封裝開源庫JLAuthorizationManager送給大家,歡迎大家pull request 和 star~~
Objective-C版本
Swift版本
權(quán)限
- 語音識別;
- 媒體資料庫/Apple Music;
- Siri;
- 健康數(shù)據(jù)共享;
- 藍牙;
- 住宅權(quán)限(HomeKit);
- 社交賬號體系權(quán)限;
- 活動與體能訓(xùn)練記錄;
- 廣告標(biāo)識;
語音識別
- 引入頭文件: @import Speech;
- 首先判斷當(dāng)前應(yīng)用所處的權(quán)限狀態(tài),若當(dāng)前狀態(tài)為NotDetermined(未確定),此時,需要調(diào)用系統(tǒng)提供的請求權(quán)限方法,同時也是觸發(fā)系統(tǒng)彈窗的所在點;
- 該權(quán)限涉及到的類為** SFSpeechRecognizer**,具體代碼如下:
- (void)p_requestSpeechRecognizerAccessWithAuthorizedHandler:(void(^)())authorizedHandler
unAuthorizedHandler:(void(^)())unAuthorizedHandler{
SFSpeechRecognizerAuthorizationStatus authStatus = [SFSpeechRecognizer authorizationStatus];
if (authStatus == SFSpeechRecognizerAuthorizationStatusNotDetermined) {
//調(diào)用系統(tǒng)提供的權(quán)限訪問的方法
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
if (status == SFSpeechRecognizerAuthorizationStatusAuthorized) {
dispatch_async(dispatch_get_main_queue(), ^{
//授權(quán)成功后
authorizedHandler ? authorizedHandler() : nil;
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
//授權(quán)失敗后
unAuthorizedHandler ? unAuthorizedHandler() : nil;
});
}
}];
}else if (authStatus == SFSpeechRecognizerAuthorizationStatusAuthorized){
authorizedHandler ? authorizedHandler() : nil;
}else{
unAuthorizedHandler ? unAuthorizedHandler() : nil;
}
}
需要注意的是,調(diào)用
requestAuthorization
方法的block回調(diào)是在任意的子線程中進行的,如果你需要在授權(quán)成功后刷新UI的話,需要將對應(yīng)的方法置于主線程中進行,筆者將上述方法默認(rèn)在主線程中進行。后續(xù)權(quán)限請求方法與此類似,不再贅述。-
在info.plist添加指定的配置信息,如下所示:
Speech Recognizer
媒體資料庫/Apple Music
- 導(dǎo)入頭文件@import MediaPlayer;
- 使用類MPMediaLibrary進行權(quán)限訪問,代碼如下;
- (void)p_requestAppleMusicAccessWithAuthorizedHandler:(void(^)())authorizedHandler
unAuthorizedHandler:(void(^)())unAuthorizedHandler{
MPMediaLibraryAuthorizationStatus authStatus = [MPMediaLibrary authorizationStatus];
if (authStatus == MPMediaLibraryAuthorizationStatusNotDetermined) {
[MPMediaLibrary requestAuthorization:^(MPMediaLibraryAuthorizationStatus status) {
if (status == MPMediaLibraryAuthorizationStatusAuthorized) {
dispatch_async(dispatch_get_main_queue(), ^{
authorizedHandler ? authorizedHandler() : nil;
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
unAuthorizedHandler ? unAuthorizedHandler() : nil;
});
}
}];
}else if (authStatus == MPMediaLibraryAuthorizationStatusAuthorized){
authorizedHandler ? authorizedHandler() : nil;
}else{
unAuthorizedHandler ? unAuthorizedHandler() : nil;
}
}
- 在info.plist添加指定的配置信息,如下所示:
Media
Siri
- 導(dǎo)入頭文件@import Intents;;
- 與其他權(quán)限不同的時,使用Siri需要在Xcode中Capabilities打開Siri開關(guān),Xcode會自動生成一個xx.entitlements文件,若沒有打開該開關(guān),項目運行時會報錯。
- 實現(xiàn)代碼如下:
- (void)p_requestSiriAccessWithAuthorizedHandler:(void(^)())authorizedHandler
unAuthorizedHandler:(void(^)())unAuthorizedHandler{
INSiriAuthorizationStatus authStatus = [INPreferences siriAuthorizationStatus];
if (authStatus == INSiriAuthorizationStatusNotDetermined) {
[INPreferences requestSiriAuthorization:^(INSiriAuthorizationStatus status) {
if (status == INSiriAuthorizationStatusAuthorized) {
dispatch_async(dispatch_get_main_queue(), ^{
authorizedHandler ? authorizedHandler() : nil;
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
unAuthorizedHandler ? unAuthorizedHandler() : nil;
});
}
}];
}else if (authStatus == INSiriAuthorizationStatusAuthorized){
authorizedHandler ? authorizedHandler() : nil;
}else{
unAuthorizedHandler ? unAuthorizedHandler() : nil;
}
}
健康數(shù)據(jù)共享
- 導(dǎo)入頭文件@import HealthKit;
- 健康數(shù)據(jù)共享權(quán)限相對其他權(quán)限相對復(fù)雜一些,分為寫入和讀出權(quán)限.
- 在Xcode 8中的
info.plist
需要設(shè)置以下兩種權(quán)限:
1、Privacy - Health Update Usage Description
2、Privacy - Health Share Usage Description
- 具體實現(xiàn)代碼:
//設(shè)置寫入/共享的健康數(shù)據(jù)類型
- (NSSet *)typesToWrite {
HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
return [NSSet setWithObjects:stepType,distanceType, nil];
}
//設(shè)置讀寫以下為設(shè)置的權(quán)限類型:
- (NSSet *)typesToRead {
HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKQuantityType *distanceType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
return [NSSet setWithObjects:stepType,distanceType, nil];
}
//需要確定設(shè)備支持HealthKit
if ([HKHealthStore isHealthDataAvailable]) {
return;
}
HKHealthStore *healthStore = [[HKHealthStore alloc] init];
NSSet * typesToShare = [self typesToWrite];
NSSet * typesToRead = [self typesToRead];
[healthStore requestAuthorizationToShareTypes:typesToShare readTypes:typesToRead completion:^(BOOL success, NSError * _Nullable error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Health has authorized!");
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Health has not authorized!");
});
}
}];
藍牙
- 需要導(dǎo)入頭文件@import CoreBluetooth;
- 藍牙的權(quán)限檢測相對其他會復(fù)雜一些,需要在代理中檢測藍牙狀態(tài);
- 獲取藍牙權(quán)限:
- (void)checkBluetoothAccess {
CBCentralManager *cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
CBManagerState state = [cbManager state];
if(state == CBManagerStateUnknown) {
NSLog(@"Unknown!");
}
else if(state == CBManagerStateUnauthorized) {
NSLog(@"Unauthorized!");
}
else {
NSLog(@"Granted!");
}
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
//這個代理方法會在藍牙權(quán)限狀態(tài)發(fā)生變化時被調(diào)用,并且可以根據(jù)不同的狀態(tài)進行相應(yīng)的修改UI或者數(shù)據(jù)訪問的操作。
}
- 請求藍牙權(quán)限
- (void)requestBluetoothAccess {
CBCentralManager *cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
//該方法會顯示用戶同意的彈窗
[cbManager scanForPeripheralsWithServices:nil options:nil];
}
住宅權(quán)限(HomeKit)
- 需導(dǎo)入頭文件@import HomeKit;
-
HomeKit
請求權(quán)限的方法如下:
- (void)requestHomeAccess {
self.homeManager = [[HMHomeManager alloc] init];
//當(dāng)設(shè)置該代理方法后,會請求用戶權(quán)限
self.homeManager.delegate = self;
}
- (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager {
if (manager.homes.count > 0) {
// home的數(shù)量不為空,即表示用戶權(quán)限已通過
}
else {
__weak HMHomeManager *weakHomeManager = manager; // Prevent memory leak
[manager addHomeWithName:@"Test Home" completionHandler:^(HMHome *home, NSError *error) {
if (!error) {
//權(quán)限允許
}
else {
if (error.code == HMErrorCodeHomeAccessNotAuthorized) {
//權(quán)限不允許
}
else {
//處理請求產(chǎn)生的錯誤
}
}
if (home) {
[weakHomeManager removeHome:home completionHandler:^(NSError * _Nullable error) {
//移除Home
}];
}
}];
}
}
社交賬號體系權(quán)限
- 導(dǎo)入頭文件@import Accounts;
- 獲取對應(yīng)的權(quán)限:
- (void)checkSocialAccountAuthorizationStatus:(NSString *)accountTypeIndentifier {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *socialAccount = [accountStore accountTypeWithAccountTypeIdentifier:accountTypeIndentifier];
if ([socialAccount accessGranted]) {
NSLog(@"權(quán)限通過了");
}else{
NSLog(@"權(quán)限未通過!");
}
}
-
accountTypeIndentifier
可以是以下類型:
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierTwitter NS_AVAILABLE(NA, 5_0);
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierFacebook NS_AVAILABLE(NA, 6_0);
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierSinaWeibo NS_AVAILABLE(NA, 6_0);
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierTencentWeibo NS_AVAILABLE(NA, 7_0);
ACCOUNTS_EXTERN NSString * const ACAccountTypeIdentifierLinkedIn NS_AVAILABLE(NA, NA);
- 請求對應(yīng)的權(quán)限:
- (void)requestTwitterAccess {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:accountTypeIdentifier];
[accountStore requestAccessToAccountsWithType: accountType options:nil completion:^(BOOL granted, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if(granted){
NSLog(@"授權(quán)通過了");
}else{
NSLog(@"授權(quán)未通過");
}
});
}];
}
活動與體能訓(xùn)練記錄
- 導(dǎo)入頭文件@import CoreMotion;
- 具體實現(xiàn)代碼:
//訪問活動與體能訓(xùn)練記錄
CMMotionActivityManager *cmManager = [[CMMotionActivityManager alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[cmManager startActivityUpdatesToQueue:queue withHandler:^(CMMotionActivity *activity) {
//授權(quán)成功后,會進入Block方法內(nèi),授權(quán)失敗不會進入Block方法內(nèi)
}];
廣告標(biāo)識
- 導(dǎo)入頭文件@import AdSupport;
- 獲取廣告標(biāo)識的權(quán)限狀態(tài):
BOOL isAuthorizedForAd = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled];
- 在使用
advertisingIdentifier
屬性前,必須調(diào)用上述方法判斷是否支持,如果上述方法返回值為NO
,則advertising ID
訪問將會受限。
小結(jié)一下
- 通過以上兩篇文章的整理,有關(guān)iOS系統(tǒng)權(quán)限問題的處理基本上涵蓋完全了;
- 并不是所有的權(quán)限訪問都有顯式的調(diào)用方法,有些是在使用過程中進行訪問的,比如
定位權(quán)限
、藍牙共享權(quán)限
、Homekit權(quán)限
、活動與體能訓(xùn)練權(quán)限
,這些權(quán)限在使用時注意回調(diào)方法中的權(quán)限處理; -
HomeKit
、HealthKit
、Siri
需要開啟Capabilities
中的開關(guān),即生成projectName.entitlements
文件; - 開源庫JLAuthorizationManager支持集成大部分常用的權(quán)限訪問,便捷使用 welcome to pull request or star;