標籤:
在實際項目中,我們經常需要訪問裝置的網路攝影機或者相簿,當第一次安裝某個App的時候,系統便會彈出授權對話方塊,要求使用者做出是否授權的判斷。整體邏輯比較簡單,但是在使用過程中需要對使用者體驗進行最佳化,否則會出現bug。該部落格的範例程式碼已經上傳至 https://github.com/chenyufeng1991/AuthorityOfCameraAndPhoto 。
首先我先描述一下出現的問題。我以訪問相簿為例,實現代碼如下:
- (void)photoBtnPressed:(id)sender{ // 首先查看當前裝置是否支援相簿 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { [self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary]; } else { [self showAlertController:@"提示" message:@"當前裝置不支援相簿"]; }}
- (void)presentToImagePickerController:(UIImagePickerControllerSourceType)type{ UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = type; [self presentViewController:picker animated:YES completion:nil];}- (void)showAlertController:(NSString *)title message:(NSString *)message{ UIAlertController *ac = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; [ac addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { }]]; [self presentViewController:ac animated:YES completion:nil];}
解釋一下,首先需要判斷當前裝置是否支援相簿,進行這樣判斷操作會比較安全。如果可以的話直接使用UIImagePickerController訪問,否則彈出alert提示框。第一次運行效果如下:
。
該對話方塊就是系統請求使用者獲得訪問相簿許可權的對話方塊,如果點擊“OK”,那麼就能彈出相簿介面。如果點擊"Don‘t Allow",使用者就無法訪問相簿,因為我這裡要示範互動問題,所以我點擊"Don‘t Allow".此時出現如下的空白介面:
。
這樣就會出現互動問題,跳到了一個完全空白的頁面,並且沒有任何的提示,準確來說,這就是一個bug。而且我們無法對這個空白頁面進行自訂。如果大家仔細觀察這個許可權獲得的過程,發現介面是首先彈出這個空白頁面,然後才是彈出選擇對話方塊。這就是問題所在,擷取網路攝影機許可權也是一樣的,下面我們就來解決這類問題。
我的目標是首先彈出授權對話方塊,如果我允許授權,那麼就跳到網路攝影機介面或者相簿介面;如果我拒絕授權,那麼就跳到一個帶有提示的自訂頁面。首先以相簿為例來實現:
(1)首先說明下授權狀態,共有三種:
已授權:***Authorized;
未確定:***NotDetrmined;
已拒絕:***Denied,***Restricted;
對於當前裝置的這些許可權狀態,我們可以直接讀取,我實現了以下方法:
+ (BOOL)isPhotoAlbumDenied{ ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus]; if (author == ALAuthorizationStatusRestricted || author == ALAuthorizationStatusDenied) { return YES; } return NO;}+ (BOOL)isPhotoAlbumNotDetermined{ ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus]; if (author == ALAuthorizationStatusNotDetermined) { return YES; } return NO;}
isPhotoAlbumDenied方法判斷相簿許可權是否已經被拒絕;isPhotoAlbumNotDetermined方法判斷是否還沒確定。方法介面寫在YFKit類中。
(2)授權方法實現如下:
- (void)optimalPhotoBtnPressed:(id)sender{ if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { // 第一次安裝App,還未確定許可權,調用這裡 if ([YFKit isPhotoAlbumNotDetermined]) { if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { // 該API從iOS8.0開始支援 // 系統彈出授權對話方塊 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusRestricted || status == PHAuthorizationStatusDenied) { // 使用者拒絕,跳轉到自訂提示頁面 DeniedAuthViewController *vc = [[DeniedAuthViewController alloc] init]; [self presentViewController:vc animated:YES completion:nil]; } else if (status == PHAuthorizationStatusAuthorized) { // 使用者授權,彈出相簿對話方塊 [self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary]; } }); }]; } else { // 以上requestAuthorization介面只支援8.0以上,如果App支援7.0及以下,就只能調用這裡。 [self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary]; } } else if ([YFKit isPhotoAlbumDenied]) { // 如果已經拒絕,則彈出對話方塊 [self showAlertController:@"提示" message:@"拒絕訪問相簿,可去設定隱私裡開啟"]; } else { // 已經授權,跳轉到相簿頁面 [self presentToImagePickerController:UIImagePickerControllerSourceTypePhotoLibrary]; } } else { // 當前裝置不支援開啟相簿 [self showAlertController:@"提示" message:@"當前裝置不支援相簿"]; }}
(3)運行效果如下:
申請授權:
。
可以看到此時是先彈出對話方塊進行確認的,而不是跳到相簿空白頁面才進行彈出確認的。
拒絕授權:
。
該空態介面可以自訂。
允許授權:
。
直接跳到相簿頁面了。
(3)網路攝影機申請授權邏輯與相簿類似,只是使用的API不同,但是更為簡單,因為該API可以支援7.0及以上,而目前的App都基本支援7.0及以上。使用的介面是AVCaptureDevice。實現方法如下:
- (void)optimalCameraBtnPressed:(id)sender{ if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { // 應用第一次申請許可權調用這裡 if ([YFKit isCameraNotDetermined]) { [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { // 使用者授權 [self presentToImagePickerController:UIImagePickerControllerSourceTypeCamera]; } else { // 使用者拒絕授權 DeniedAuthViewController *vc = [[DeniedAuthViewController alloc] init]; [self presentViewController:vc animated:YES completion:nil]; } }); }]; } // 使用者已經拒絕訪問網路攝影機 else if ([YFKit isCameraDenied]) { [self showAlertController:@"提示" message:@"拒絕訪問網路攝影機,可去設定隱私裡開啟"]; } // 使用者允許訪問網路攝影機 else { [self presentToImagePickerController:UIImagePickerControllerSourceTypeCamera]; } } else { // 當前裝置不支援網路攝影機,比如模擬器 [self showAlertController:@"提示" message:@"當前裝置不支援拍照"]; }}測試網路攝影機需要在真機下進行測試,因為模擬器不支援網路攝影機。
通過以上代碼,可以有效並且可控的進行網路攝影機和相簿許可權申請的流程式控制制,最佳化使用者體驗。下面給出一些開發tips:
(1)對於模擬器,如果想要重設應用的許可權與隱私權設定,可以直接重設模擬器,選擇Simulator-->Reset Content and Setting即可。下次重新安裝App時,所有的許可權都要重新申請了。
(2)在真機上重設許可權可以進入:設定-->通用-->重設-->重設位置與隱私即可。這種重設方式是安全的,不會導致手機上的其他資料的丟失,僅僅只是把某些許可權記錄給刪除了。當需要使用許可權的時候,系統會重新申請。
(3)當只是要開關某個許可權的時候,進入設定-->隱私 裡面開關即可。
iOS開發實戰——網路攝影機與相簿許可權擷取邏輯最佳化