前言
在iOS APP開發(fā)中個人設(shè)置中一般會有替換用戶頭像的功能,那么就會需要通過iOS 媒體庫(相機\相冊)來選取圖片。為了簡化操作,和集成方便,一般都會選擇用 UIImagePickerController 來做處理。
我們都知道,iOS系統(tǒng)在7.0以后對調(diào)用相冊\相機設(shè)置很多權(quán)限,每種權(quán)限都有不同的效果,如何處理才能讓用戶體驗更好,也是我們這次主要考慮的方法。
業(yè)務(wù)需求

未命名gif.gif
如果系統(tǒng)自動彈出系統(tǒng)讓用戶授權(quán)的提示框,不再彈出自己業(yè)務(wù)代碼里的提示框
如果系統(tǒng)自動彈出用戶授權(quán)提示框,點擊授權(quán),繼續(xù)執(zhí)行吊起媒體庫控制器的操作
如果用戶未授權(quán),訪問時彈出業(yè)務(wù)提示框,跳轉(zhuǎn)系統(tǒng)設(shè)置中對APP對應(yīng)的設(shè)置
授權(quán)方法說明
相機
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatusVedio = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
AVAuthorizationStatus 相機授權(quán)說明
typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {
AVAuthorizationStatusNotDetermined = 0,
AVAuthorizationStatusRestricted = 1,
AVAuthorizationStatusDenied = 2,
AVAuthorizationStatusAuthorized = 3,
} NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
- NS_AVAILABLE_IOS(7_0) 表示iOS7.0系統(tǒng)以上均可以使用
- AVAuthorizationStatusNotDetermined 這個參數(shù)比較特殊,只有用戶在第一次安裝此APP才會返回這個參數(shù),用戶后期更新或者刪除重裝都不會返回這個值,除非設(shè)置中還原。
- AVAuthorizationStatusRestricted限制使用,可以當(dāng)做不允許使用。
- AVAuthorizationStatusDenied 禁止使用,可以當(dāng)做不允許使用。
- AVAuthorizationStatusAuthorized 用戶授權(quán),可以當(dāng)做允許使用。
相冊
PHAuthorizationStatus authStatusAlbm = [PHPhotoLibrary authorizationStatus];
PHAuthorizationStatus 相冊授權(quán)說明
typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
PHAuthorizationStatusNotDetermined = 0, // User has not yet made a choice with regards to this application
PHAuthorizationStatusRestricted, // This application is not authorized to access photo data.
// The user cannot change this application’s status, possibly due to active restrictions
// such as parental controls being in place.
PHAuthorizationStatusDenied, // User has explicitly denied this application access to photos data.
PHAuthorizationStatusAuthorized // User has authorized this application to access photos data.
} PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);
- PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0) 表示iOS8.0系統(tǒng)以上均可以使用
- PHAuthorizationStatusNotDetermined 這個參數(shù)比較特殊,只有用戶在第一次安裝此APP才會返回這個參數(shù),用戶后期更新或者刪除重裝都不會返回這個值,除非設(shè)置中還原。
- PHAuthorizationStatusRestricted限制使用,可以當(dāng)做不允許使用。
- PHAuthorizationStatusDenied 禁止使用,可以當(dāng)做不允許使用。
- PHAuthorizationStatusAuthorized 用戶授權(quán),可以當(dāng)做允許使用。
源碼
.h文件
#import <Foundation/Foundation.h>
typedef void (^LeePhotoOrAlbumImagePickerBlock)(UIImage *image);
@interface LeePhotoOrAlbumImagePicker : NSObject
// 必須創(chuàng)建一個對象才行,才不會釋放指針
// 必須先在使用該方法的控制器中初始化 創(chuàng)建這個屬性,然后在對象調(diào)用如下方法
/**
公共方法 選擇圖片后的圖片回掉
@param controller 使用這個工具的控制器
@param photoBlock 選擇圖片后的回掉
*/
- (void)getPhotoAlbumOrTakeAPhotoWithController:(UIViewController *)controller photoBlock:(LeePhotoOrAlbumImagePickerBlock)photoBlock;
@end
.m文件
#import "LeePhotoOrAlbumImagePicker.h"
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/PhotosDefines.h>
#import <Photos/PHPhotoLibrary.h>
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface LeePhotoOrAlbumImagePicker ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@property (nonatomic,copy) LeePhotoOrAlbumImagePickerBlock photoBlock; //-> 回掉
@property (nonatomic,strong) UIImagePickerController *picker; //-> 多媒體選擇控制器
@property (nonatomic,weak) UIViewController *viewController; //-> 一定是weak 避免循環(huán)引用
@property (nonatomic,assign) NSInteger sourceType; //-> 媒體來源 (相冊/相機)
@end
@implementation LeePhotoOrAlbumImagePicker
#pragma mark - 初始化
- (instancetype)init{
if (self = [super init]) {
}
return self;
}
- (void)getPhotoAlbumOrTakeAPhotoWithController:(UIViewController *)controller photoBlock:(LeePhotoOrAlbumImagePickerBlock)photoBlock{
self.photoBlock = photoBlock;
self.viewController = controller;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *photoAlbumAction = [UIAlertAction actionWithTitle:@"從相冊選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self getAlertActionType:1];
}];
UIAlertAction *cemeraAction = [UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self getAlertActionType:2];
}];
UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[self getAlertActionType:0];
}];
[alertController addAction:photoAlbumAction];
[alertController addAction:cancleAction];
// 判斷是否支持拍照
[self imagePickerControlerIsAvailabelToCamera] ? [alertController addAction:cemeraAction]:nil;
[self.viewController presentViewController:alertController animated:YES completion:nil];
}
/**
UIAlertController 點擊事件 確定選擇的媒體來源(相冊/相機)
@param type 點擊的類型
*/
- (void)getAlertActionType:(NSInteger)type {
NSInteger sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if (type == 1) {
sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}else if (type ==2){
sourceType = UIImagePickerControllerSourceTypeCamera;
}
[self creatUIImagePickerControllerWithAlertActionType:sourceType];
}
/**
點擊事件出發(fā)的方法
@param type 媒體庫來源 (相冊/相機)
*/
- (void)creatUIImagePickerControllerWithAlertActionType:(NSInteger)type {
self.sourceType = type;
// 獲取不同媒體類型下的授權(quán)類型
NSInteger cameragranted = [self AVAuthorizationStatusIsGranted];
// 如果確定未授權(quán) cameragranted ==0 彈框提示;如果確定已經(jīng)授權(quán) cameragranted == 1;如果第一次觸發(fā)授權(quán) cameragranted == 2,這里不處理
if (cameragranted == 0) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"請到設(shè)置-隱私-相機/相冊中打開授權(quán)設(shè)置" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *comfirmAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 無權(quán)限 引導(dǎo)去開啟
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication]canOpenURL:url]) {
[[UIApplication sharedApplication]openURL:url];
}
}];
[alertController addAction:comfirmAction];
[self.viewController presentViewController:alertController animated:YES completion:nil];
}else if (cameragranted == 1) {
[self presentPickerViewController];
}
}
// 判斷硬件是否支持拍照
- (BOOL)imagePickerControlerIsAvailabelToCamera {
return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
}
#pragma mark - 照機/相冊 授權(quán)判斷
- (NSInteger)AVAuthorizationStatusIsGranted {
kDefineWeakSelf;
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatusVedio = [AVCaptureDevice authorizationStatusForMediaType:mediaType]; // 相機授權(quán)
PHAuthorizationStatus authStatusAlbm = [PHPhotoLibrary authorizationStatus]; // 相冊授權(quán)
NSInteger authStatus = self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary ? authStatusAlbm:authStatusVedio;
switch (authStatus) {
case 0: { //第一次使用,則會彈出是否打開權(quán)限,如果用戶第一次同意授權(quán),直接執(zhí)行再次調(diào)起
if (self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) { //授權(quán)成功
[weakSelf presentPickerViewController];
}
}];
}else{
[AVCaptureDevice requestAccessForMediaType : AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) { //授權(quán)成功
[weakSelf presentPickerViewController];
}
}];
}
}
return 2; //-> 不提示
case 1: return 0; //-> 還未授權(quán)
case 2: return 0; //-> 主動拒絕授權(quán)
case 3: return 1; //-> 已授權(quán)
default:return 0;
}
}
/**
如果第一次訪問用戶是否是授權(quán),如果用戶同意 直接再次執(zhí)行
*/
-(void)presentPickerViewController{
self.picker = [[UIImagePickerController alloc] init];
if (@available(iOS 11.0, *)){
[[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentAlways];
}
self.picker.delegate = self;
self.picker.allowsEditing = YES; //-> 是否允許選取的圖片可以裁剪編輯
self.picker.sourceType = self.sourceType; //-> 媒體來源(相冊/相機)
[self.viewController presentViewController:self.picker animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate
// 點擊完成按鈕的選取圖片的回掉
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
// 獲取編輯后的圖片
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
// 如果裁剪的圖片不符合標準 就會為空,直接使用原圖
image == nil ? image = [info objectForKey:UIImagePickerControllerOriginalImage] : nil;
self.photoBlock ? self.photoBlock(image): nil;
[picker dismissViewControllerAnimated:YES completion:^{
// 這個部分代碼 視情況而定
if (@available(iOS 11.0, *)){
[[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
}
}];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissViewControllerAnimated:YES completion:^{
// 這個部分代碼 視情況而定
if (@available(iOS 11.0, *)){
[[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
}
}];
}
@end
如何使用
@interface PDMinePostCommentViewController ()
@property (nonatomic,strong) LeePhotoOrAlbumImagePicker *myPicker;
@end
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"意見反饋";
self.myPicker = [[LeePhotoOrAlbumImagePicker alloc]init];
[self.myPicker getPhotoAlbumOrTakeAPhotoWithController:self photoBlock:^(UIImage *image) {
//回掉圖片
}];
}