前言
在iOS APP开发中个人设置中一般会有替换用户头像的功能,那么就会需要通过iOS 媒体库(相机\相册)来选取图片。为了简化操作,和集成方便,一般都会选择用 UIImagePickerController 来做处理。
我们都知道,iOS系统在7.0以后对调用相册\相机设置很多权限,每种权限都有不同的效果,如何处理才能让用户体验更好,也是我们这次主要考虑的方法。
业务需求
如果系统自动弹出系统让用户授权的提示框,不再弹出自己业务代码里的提示框
如果系统自动弹出用户授权提示框,点击授权,继续执行吊起媒体库控制器的操作
如果用户未授权,访问时弹出业务提示框,跳转系统设置中对APP对应的设置
授权方法说明
相机
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatusVedio = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
AVAuthorizationStatus 相机授权说明
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系统以上均可以使用
- AVAuthorizationStatusNotDetermined 这个参数比较特殊,只有用户在第一次安装此APP才会返回这个参数,用户后期更新或者删除重装都不会返回这个值,除非设置中还原。
- AVAuthorizationStatusRestricted限制使用,可以当做不允许使用。
- AVAuthorizationStatusDenied 禁止使用,可以当做不允许使用。
- AVAuthorizationStatusAuthorized 用户授权,可以当做允许使用。
相册
PHAuthorizationStatus authStatusAlbm = [PHPhotoLibrary authorizationStatus];
PHAuthorizationStatus 相册授权说明
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系统以上均可以使用
- PHAuthorizationStatusNotDetermined 这个参数比较特殊,只有用户在第一次安装此APP才会返回这个参数,用户后期更新或者删除重装都不会返回这个值,除非设置中还原。
- PHAuthorizationStatusRestricted限制使用,可以当做不允许使用。
- PHAuthorizationStatusDenied 禁止使用,可以当做不允许使用。
- PHAuthorizationStatusAuthorized 用户授权,可以当做允许使用。
源码
.h文件
#import <Foundation/Foundation.h>
typedef void (^LeePhotoOrAlbumImagePickerBlock)(UIImage *image);
@interface LeePhotoOrAlbumImagePicker : NSObject
// 必须创建一个对象才行,才不会释放指针
// 必须先在使用该方法的控制器中初始化 创建这个属性,然后在对象调用如下方法
/**
公共方法 选择图片后的图片回掉
@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 避免循环引用
@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];
}
/**
点击事件出发的方法
@param type 媒体库来源 (相册/相机)
*/
- (void)creatUIImagePickerControllerWithAlertActionType:(NSInteger)type {
self.sourceType = type;
// 获取不同媒体类型下的授权类型
NSInteger cameragranted = [self AVAuthorizationStatusIsGranted];
// 如果确定未授权 cameragranted ==0 弹框提示;如果确定已经授权 cameragranted == 1;如果第一次触发授权 cameragranted == 2,这里不处理
if (cameragranted == 0) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置-隐私-相机/相册中打开授权设置" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *comfirmAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
// 无权限 引导去开启
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 - 照机/相册 授权判断
- (NSInteger)AVAuthorizationStatusIsGranted {
kDefineWeakSelf;
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatusVedio = [AVCaptureDevice authorizationStatusForMediaType:mediaType]; // 相机授权
PHAuthorizationStatus authStatusAlbm = [PHPhotoLibrary authorizationStatus]; // 相册授权
NSInteger authStatus = self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary ? authStatusAlbm:authStatusVedio;
switch (authStatus) {
case 0: { //第一次使用,则会弹出是否打开权限,如果用户第一次同意授权,直接执行再次调起
if (self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) { //授权成功
[weakSelf presentPickerViewController];
}
}];
}else{
[AVCaptureDevice requestAccessForMediaType : AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) { //授权成功
[weakSelf presentPickerViewController];
}
}];
}
}
return 2; //-> 不提示
case 1: return 0; //-> 还未授权
case 2: return 0; //-> 主动拒绝授权
case 3: return 1; //-> 已授权
default:return 0;
}
}
/**
如果第一次访问用户是否是授权,如果用户同意 直接再次执行
*/
-(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) {
//回掉图片
}];
}