? ? ?最近需要適配iOS 14的相冊權限,在網上查了很多資料,大部分資料都只講一部分缺另一部分,想把整個相冊權限適配好還是有點麻煩,現在辦把我整個適配過程記錄下來,需要適配的兄弟可以參考一下
? ? ?在 iOS13 及以前,當用戶首次訪問應用程序時,會被要求開放大量權限,比如相冊、定位、聯系人,實際上該應用可能僅僅需要一個選擇圖片功能,卻被要求開放整個照片庫的權限,這確實是不合理的。對于相冊,在 iOS14 中引入了 “LimitedPhotos Library” 的概念,用戶可以授予應用訪問其一部分的照片,對于應用來說,僅能讀取到用戶選擇讓應用來讀取的照片,讓我們看到了 Apple 對于用戶隱私的尊重。這僅僅是一部分,在iOS14 中,可以看到諸多類似的保護用戶隱私的措施,也需要我們升級適配。?
? ? ? iOS14 新增了“Limited Photo Library Access” 模式,在授權彈窗中增加了 Select Photo 選項。用戶可以在 App 請求調用相冊時選擇部分照片讓 App 讀取。從 App 的視?來看,你的相冊里就只有這幾張照片,App 無法得知其它照片的存在。
? ?當一下次在進入時有會彈提示框,讓你選擇更多圖片或者保留當前選擇,這個提示框不太友好,可以在plist文件里面通過設置?Prevent limited photos access alert = YES隱藏提示
當選擇添加更多圖片是,可以通過? ? [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];到相冊添加刪除圖片,然后監聽圖片變化做相應處理。
對于PHAuthorizationStatusLimited權限的適配,我采用的方案是,先繪制一個列表用于顯示授權的圖片,圖片的資源也就是授權訪問的,當要添加更多圖片是通過?[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];跳轉到相冊,添加圖片,添加完成后監聽圖片變化,更新列表,下面是我的代碼:
?if (@available(iOS 14.0, *)) {
? ? ? ? ? ? PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite];
? ? ? ? ? ? ? switch(status) {
? ? ? ? ? ? ? ? ? case PHAuthorizationStatusNotDetermined:
? ? ? ? ? ? ? ? ? ? ? [self dispatchAuthorizationForAccessLevel];
? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? case PHAuthorizationStatusLimited:
? ? ? ? ? ? ? ? ? ? ? NSLog(@"limited");
? ? ? ? ? ? ? ? ? ? ? [selfe_enterGDPickerVC];
? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? // 用戶拒絕當前應用訪問相冊
? ? ? ? ? ? ? ? ? case PHAuthorizationStatusDenied:
? ? ? ? ? ? ? ? ? ? ? NSLog(@"denied");
? ? ? ? ? ? ? ? ? ? ? [self disptachPHAuthorizationStatusDenied];
? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? // 用戶允許當前應用訪問相冊
? ? ? ? ? ? ? ? ? case PHAuthorizationStatusAuthorized:
? ? ? ? ? ? ? ? ? ? ? NSLog(@"authorized");
? ? ? ? ? ? ? ? ? ? ? [self P_enterPHPickerViewController];
? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
/用戶第一次訪問
-(void)dispatchAuthorizationForAccessLevel{
? ? [PHPhotoLibrary requestAuthorizationForAccessLevel:PHAccessLevelReadWrite handler:^(PHAuthorizationStatus status) {
? ? ? ? ? ? ? ? switch(status) {
? ? ? ? ? ? ? ? ? ? case PHAuthorizationStatusLimited:
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? ? ? ? ? ? ? ? ? ? ? [selfe_enterGDPickerVC];
? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? case PHAuthorizationStatusDenied:
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"denied");
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case PHAuthorizationStatusAuthorized:
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }];
}
//進入授權訪問的圖片控制器
-(void)e_enterGDPickerVC{
? ? MJWeakSelf;
? ? GDPickerVC *picker = [GDPickerVC new];
? ? picker.currentImageContent= ^(UIImage*_NonnullimageContent) {
? ? ? ? NSLog(@"--選擇圖片--");
? ? ? ? if(!imageContent) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? [weakSelfanalysisImageWithContent:imageContent];
? ? };
? ? UINavigationController *nv = [[UINavigationController alloc] initWithRootViewController:picker];
? ? nv.modalPresentationStyle? =0;
? ? [_controller presentViewController:nv animated:YES completion:nil];
}
----------授權圖片列表--------------
//
//
#import "GDPickerVC.h"
#import
#import "GDPickerCollectionViewCell.h"
#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
// 屏幕高度,會根據橫豎屏的變化而變化
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
@interface GDPickerVC ()<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSMutableArray *photoArray;
@end
@implementation GDPickerVC
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? self.view.backgroundColor = [UIColor whiteColor];
? ? self.title = @"顯示允許訪問的圖片";
? ? //左邊返回按鈕
? ? UIButton *fanHuiButton = [UIButton buttonWithType:UIButtonTypeCustom];
? ? fanHuiButton.frame=CGRectMake(0,0,30,40);
? ? [fanHuiButtonsetTitle:@"取消"forState:0];
? ? [fanHuiButtonsetTitleColor:[UIColor systemBlueColor] forState:0];
? ? [fanHuiButtonaddTarget:self action:@selector(comebackFuncation) forControlEvents:UIControlEventTouchUpInside];
? ? UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithCustomView:fanHuiButton];
? ? self.navigationItem.leftBarButtonItem = leftItem;
? ? UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeCustom];
? ? rightButton.frame=CGRectMake(0,0,30,40);
? ? [rightButtonsetTitle:@"添加"forState:0];
? ? [rightButtonsetTitleColor:[UIColor systemBlueColor] forState:0];
? ? [rightButtonaddTarget:self action:@selector(confirmButton:) forControlEvents:UIControlEventTouchUpInside];
? ? UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView:rightButton];
? ? self.navigationItem.rightBarButtonItem = rightItem;
? ? //獲取圖片
? ? [self getLibarayPhotoImage];
? ? self.photoArray = [NSMutableArray array];
? ? [self.view addSubview:self.collectionView];
}
#pragma mark - UICollectionViewDataSource
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
? ? return CGSizeMake(SCREEN_WIDTH/3-2,SCREEN_WIDTH/3);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
? ? return self.photoArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
? ? UIImage*image =self.photoArray[indexPath.row];
? ? GDPickerCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass(GDPickerCollectionViewCell.class) forIndexPath:indexPath];
? ? cell.imgView.image= image;
? ? returncell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
? ? UIImage*image =self.photoArray[indexPath.row];
? ? if (_currentImageContent&&image) {
? ? ? ? _currentImageContent(image);
? ? ? ? [self comebackFuncation];
? ? }
}
#pragma response
//返回
-(void)comebackFuncation{
? ? [self dismissViewControllerAnimated:YES completion:nil];
}
//點擊確認回調數據
-(void)confirmButton:(UIButton *)btn{
? ? [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];
? ? [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
}
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
? ? [self.photoArray removeAllObjects];
? ? [self getLibarayPhotoImage];
}
/*? 遍歷相簿中的全部圖片
*? @param assetCollection 相簿
*? @param original? ? ? ? 是否要原圖
*/
-(void)getLibarayPhotoImage01{
? ? __weaktypeof(self) weakSelf =self;
? ? NSMutableArray<UIImage *> *images = [NSMutableArray array];
? ? //獲取可訪問的圖片配置選項
? ? PHFetchOptions *option = [[PHFetchOptions alloc] init];
? ? //根據圖片的創建時間升序排序返回
? ? option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
? ? //獲取類型為image的資源
? ? PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:option];
?? ? //遍歷出每個PHAsset資源對象
? ? [resultenumerateObjectsUsingBlock:^(id? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
? ? ? ? PHAsset*asset = (PHAsset*)obj;
? ? ? ? //將PHAsset解析為image的配置選項
? ? ? ? PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init];
? ? ? ? //圖像縮放模式
? ? ? ? requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
? ? ? ? //圖片質量
? ? ? ? requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
? ? ? ? //PHImageManager解析圖片
? ? ? ? [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:requestOptions resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
? ? ? ? ? ? NSLog(@"圖片 %@",result);
? ? ? ? ? ? //在這里可以自定義一個顯示可訪問相冊資源的viewController.
? ? ? ? ? ? if(result) {
? ? ? ? ? ? ? ? [weakSelf.photoArrayaddObject:result];
? ? ? ? ? ? }
? ? ? ? }];
? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? ? ? [self.collectionView reloadData];
? ? ? ? });
? ? }];
}
-(void)getLibarayPhotoImage{
? ? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
? ? ? ? PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
? ? ? ? for(PHAssetCollection*assetCollectioninassetCollections) {
? ? ? ? ? ? [self enumerateAssetsInAssetCollection:assetCollection original:YES];
? ? ? ? }
? ? ? ? PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject;
? ? ? ? [self enumerateAssetsInAssetCollection:cameraRoll original:YES];
? ? });
}
- (void)enumerateAssetsInAssetCollection:(PHAssetCollection *)assetCollectionoriginal:(BOOL)original
{
?? PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
?? options.resizeMode = PHImageRequestOptionsResizeModeFast;
?? options.synchronous=YES;
?? PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
?? for(PHAsset*assetinassets) {
?? ? ? CGSize size = original ? CGSizeMake(asset.pixelWidth, asset.pixelHeight) : CGSizeZero;
?? ? ? __weaktypeof(self) weakSelf =self;
?? ? ? [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
?? ? ? ? ? NSLog(@"%@", result);
?? ? ? ? ? if(result) {
?? ? ? ? ? ? ? original ? [weakSelf.photoArrayaddObject:result] : [weakSelf.photoArrayaddObject:result];
?? ? ? ? ? }
?? ? ? }];
?? ? ? dispatch_async(dispatch_get_main_queue(), ^{
?? ? ? ? ? [weakSelf.collectionViewreloadData];
?? ? ? });
?? }
}
#pragma mark--懶加載
- (UICollectionView *)collectionView{
? ? if (!_collectionView) {
? ? ? ? UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
? ? ? ? flowLayout.minimumLineSpacing=2;
? ? ? ? flowLayout.minimumInteritemSpacing = 1;
? ? ? ? UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
? ? ? ? collectionView.backgroundColor = self.view.backgroundColor;
? ? ? ? collectionView.delegate=self;
? ? ? ? collectionView.dataSource=self;
? ? ? ? [collectionViewregisterClass:GDPickerCollectionViewCell.class forCellWithReuseIdentifier:NSStringFromClass(GDPickerCollectionViewCell.class)];
? ? ? ? _collectionView= collectionView;
? ? }
? ? return _collectionView;
}
@end
上面是PHAuthorizationStatusLimited 用戶已授權此應用程序進行有限照片庫訪問(iOS14新增)的適配,下面在來說一下適配允許訪問所有圖片,下面是適配代碼
//ios14后使用
-(void)P_enterPHPickerViewController{
? ? MJWeakSelf;
? ? //用戶選擇"允許訪問所有照片",調用PHPickerViewController顯示圖片選擇器
? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? PHPickerConfiguration *configuration = [[PHPickerConfiguration alloc] init];
? ? ? ? //只獲取image類型資源
? ? ? ? configuration.filter = [PHPickerFilter imagesFilter];
?? ? ? ? //可以多選
//? ? ? ? configuration.selectionLimit = 1;
? ? ? ? PHPickerViewController *pickerVC = [[PHPickerViewController alloc] initWithConfiguration:configuration];
? ? ? ? pickerVC.delegate=self;
? ? ? ? pickerVC.modalPresentationStyle = UIModalPresentationFullScreen;
? ? ? ? [weakSelf.controller presentViewController:pickerVC animated:YES completion:^{
? ? ? ? }];
? ? });
}
- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results
{
? ? MJWeakSelf;
? ? [pickerdismissViewControllerAnimated:YES completion:nil];
? ? if(!results || !results.count) {
? ? ? ? return;
? ? }
? ? NSLog(@"didFinishPicking");
? ? NSItemProvider *itemProvider = results.firstObject.itemProvider;
?? ? ? ? if ([itemProvider canLoadObjectOfClass:UIImage.class]) {
?? ? ? ? ? ? __weaktypeof(self) weakSelf =self;
?? ? ? ? ? ? [itemProviderloadObjectOfClass:UIImage.class completionHandler:^(__kindof id<NSItemProviderReading>? _Nullable object, NSError * _Nullable error) {
?? ? ? ? ? ? ? ? if([objectisKindOfClass:UIImage.class]) {
?? ? ? ? ? ? ? ? ? ? UIImage*image = (UIImage*)object;
?? ? ? ? ? ? ? ? ? ? [weakSelfanalysisImageWithContent:image];
?? ? ? ? ? ? ? ? }
?? ? ? ? ? ? }];
?? ? ? ? }
}