携手创造,共同成长!这是我参加「日新计划 8 月更文应战」的第35天,点击查看活动概况
前言
维护用户的隐私不被侵害是每个开发者应该承当的职责
用户隐私现已不断被资产化,经过商业运作成为了一种牟利的手段。apple在用户隐私维护方面一直走在前列.
遵循运用最少的权限来实现功能
例如给全部权限的话,有些app就偷偷读相册,根据相册给推产品
在iOS14相册 iOS 14 相册权限增加了 Limited Photo 形式 ,新增挑选权限类型 PHAuthorizationStatusLimited
PHAuthorizationStatusLimited API_AVAILABLE(ios(14)), // User has authorized this application for limited photo library access. Add PHPhotoLibraryPreventAutomaticLimitedAccessAlert = YES to the application's Info.plist to prevent the automatic alert to update the users limited library selection. Use -[PHPhotoLibrary(PhotosUISupport) presentLimitedLibraryPickerFromViewController:] from PhotosUI/PHPhotoLibrary+PhotosUISupport.h to manually present the limited library picker.
I iOS14相册权限适配
预备常识: 冷启动: App 不在内存中/没有相关的进程存在 热启动:(从后台康复)内存有部分,无相关的进程存在 暂停:存在内存中,存在相关进程
1.1 挑选答应被拜访的图片资源
用户在冷启 APP 运用 PhotoKit 拜访资源的时分会默许弹出体系图片挑选界面,让用户挑选答应被拜访的资源:
当页面弹出恳求权限 Alert 时,会有挑选相片...
选项,用户挑选该选项时,会弹出页面供用户挑选答应App拜访的相片。
后续有两种方式来修正用户挑选的资源:
- 手动触发挑选/撤销挑选图片以移除拜访权限的界面 :
[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];
- 在运用设置->Photos->Edit Selected Photos中修正
部分相册权限时,界面供给直接跳设置的进口
1.2 相册权限API的相关改动
- 新增了资源恳求和获取的 API,并且将老的资源恳求 API 标为抛弃
/// Replaces \c +authorizationStatus to support add-only/read-write access level status
+ (PHAuthorizationStatus)authorizationStatusForAccessLevel:(PHAccessLevel)accessLevel API_AVAILABLE(macosx(11.0), ios(14), tvos(14));
+ (void)requestAuthorizationForAccessLevel:(PHAccessLevel)accessLevel handler:(void(^)(PHAuthorizationStatus status))handler API_AVAILABLE(macosx(11.0), ios(14), tvos(14)) NS_SWIFT_ASYNC(2);
- Limited Photo 形式:PHAuthorizationStatus 增加新的枚举 PHAuthorizationStatusLimited
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.
PHAuthorizationStatusLimited API_AVAILABLE(ios(14)), // User has authorized this application for limited photo library access. Add PHPhotoLibraryPreventAutomaticLimitedAccessAlert = YES to the application's Info.plist to prevent the automatic alert to update the users limited library selection. Use -[PHPhotoLibrary(PhotosUISupport) presentLimitedLibraryPickerFromViewController:] from PhotosUI/PHPhotoLibrary+PhotosUISupport.h to manually present the limited library picker.
};
- 相册拜访方式: PHAccessLevel (恳求查询limited权限在 accessLevel 为 readAndWrite 时收效)
typedef NS_ENUM(NSInteger, PHAccessLevel) {
PHAccessLevelAddOnly = 1,
PHAccessLevelReadWrite = 2,
} API_AVAILABLE(macos(11.0), ios(14), tvos(14));
1.3 适配demo
从CSDN下载Demo源码:https://download.csdn.net/download/u011018979/18543032
关键:APP 需要监听用户修正了答应拜访的资源并且更新资源列表
private
- 手动触发挑选更多相片或撤销挑选以移除拜访权限的界面:
[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];
- 显现答应拜访的相册:
+ (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithType:(PHAssetCollectionType)type subtype:(PHAssetCollectionSubtype)subtype options:(PHFetchOptions *)options;
- 恳求limited 权限:
requestAuthorizationForAccessLevel:handler:
- 查询权限相册授权状况:
+ (PHAuthorizationStatus)authorizationStatusForAccessLevel:(PHAccessLevel)accessLevel API_AVAILABLE(macosx(11.0), ios(14), tvos(14));
- 图片挑选器:单选
UIImagePickerController
- 图片挑选器: 多选
PHPickerViewController
II 具体适配方案
2.1 手动触发挑选/撤销挑选图片以移除拜访权限的界面
优化挑选图片弹窗提示的交互方式:官方主张关闭自动弹窗,推荐在用户挑选了 Limited Photo 形式时,在特定界面(例如设置页)显现修正资源的进口,当用户自动点击该进口时弹出体系弹窗。
- 关闭体系自动的挑选弹窗提示:能够在 info.plist 中设置 PHPhotoLibraryPreventAutomaticLimitedAccessAlert 选项为 YES ,
<key>NSPhotoLibraryUsageDescription</key>
<string>你能够共享相机胶卷中的相片、将相片保存</string>
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<false/>
- 手动触发挑选更多相片或撤销挑选以移除拜访权限的界面:
[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];
2.2 相册拜访方式
还在运用 AssetsLibrary 管理资源读写的赶快迁移到 PhotoKit,关于只读,主张运用PHPicker。
3.2.1 只读权限
只读: 主张运用 iOS 14 供给的图片挑选器 PHPicker 来挑选图片资源(iOS 14 以下对应 UIImagePickerController)
PHPicker 长处:独立进程,不影响 APP 功能。不需要用户颁发权限就能够挑选用户所有的资源, 支撑多选。
对应的署理协议如下
@interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate, PHPickerViewControllerDelegate>
具体的实现代码请看第三章节。
3.2.2 只写权限
需要在 Info.plist 下配置权限信息
<key>NSPhotoLibraryAddUsageDescription</key>
<string>你能够共享相机胶卷中的相片、将相片保存</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>你能够共享相机胶卷中的相片</string>
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<false/>
别离运用 AssetsLibrary
、PhotoKit
以及 UIKit 层 UIImageWriteToSavedPhotosAlbum
写入相册
- (IBAction)saveClick:(UIButton *)sender {
//参数1:图片对象
//参数2:成功办法绑定的target
//参数3:成功后调用办法
//参数4:需要传递信息(成功后调用办法的参数) 一般写nil
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
/* 1.先保存图片到【相机胶卷】(不能直接保存到自定义相册中)
1> C言语函数
2> AssetsLibrary框架 (iOS4支撑,iOS9.0被抛弃)
3> Photos框架 (iOS 8.0支撑 推荐运用)
2.具有一个【自定义相册】
1> AssetsLibrary框架
2> Photos框架
3.将方才保存到【相机胶卷】里面的图片引用到【自定义相册】
1> AssetsLibrary框架
2> Photos框架
*/
}
#pragma mark -- <保存到相册>
-(void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
NSString *msg = nil ;
if(error){
msg = @"保存图片失败" ;
}else{
msg = @"保存图片成功" ;
}
}
3.2.3 读写权限
别离运用 AssetsLibrary 和 PhotoKit 来读取相册资源
2.3 其他需要注意的API
运用 PHAssetCreationRequests 来创建的资源默许是会增加在用户答应的集合傍边
2.4 监听第一次相册授权时
- 监听到用户点击不答应,不答应时显现引导。
- 用户未作出清晰挑选的状况下自己自动恳求了一次权限设置(改写UI的代码放到主线程履行)
更多内容请看此篇文章:blog.csdn.net/z929118967/…
/**
1. 监听到用户点击不答应,不答应时显现引导
2. 用户未作出清晰挑选的状况下自己自动恳求了一次权限设置
showAlert:不答应时显现引导
block: 答应之后的动作,比如保存图片
*/
+(BOOL)isHasPhotoLibraryAuthorityWithisShowAlert:(BOOL)showAlert block:(void (^)(id sender))block
{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus] ;
//1. 定义部分block: 处理没有权限的状况,显现引导
BOOL (^block4none)(PHAuthorizationStatus ) = ^ BOOL (PHAuthorizationStatus status ){
NSLog(@" 没有拜访图库的权限==============");
if (showAlert) {
[LBAlertController showAlertTitle:@"无法运用相册" content:@"请在iPhone的\"设置-隐私-相片\"中答应拜访相片。" cancelString:@"撤销" cancleBlock:nil sureString:@"去设置" sureBlock:^{
// 需要在info.plist中增加 URL types 并设置一项URL Schemes为prefs IOS10 以后不起作用
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]){
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
} currentController:[QCT_Common getCurrentVC]];
}
return NO;
};
switch (status) {
case PHAuthorizationStatusRestricted:
case PHAuthorizationStatusDenied : {
//没有拜访图库的权限
return block4none(status);
}
break;
case PHAuthorizationStatusNotDetermined:{//2. 用户未作出清晰挑选的状况下自己自动恳求了一次权限设置
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus phStatus) {
//监听到用户点击不答应,不答应时显现引导
if (phStatus == PHAuthorizationStatusRestricted || phStatus == PHAuthorizationStatusDenied) {
dispatch_sync(dispatch_get_main_queue(), ^{
//改写UI的代码放到主线程履行
block4none(status);
});
} else if (phStatus == PHAuthorizationStatusNotDetermined) {
// 不处理
} else {
// 履行外围的block
// status = QMUIAssetAuthorizationStatusAuthorized;
if(block){//履行答应之后的保存图片操作
block(nil);
}
}
}];
return NO;
}
default:
break;
}
if(block){// 3. 履行答应之后的保存图片操作
block(nil);
}
return YES;
}
III 挑选图片资源视图
运用PHPicker和UIImagePickerController挑选图片资源
3.1 恳求查询权限
/**
恳求查询权限
*/
- (IBAction)requestAuth:(id)sender
{
// 恳求权限,需注意 limited 权限尽在 accessLevel 为 readAndWrite 时收效
PHAccessLevel level1 = PHAccessLevelAddOnly;// 仅答应增加相片
PHAccessLevel level2 = PHAccessLevelReadWrite;// 答应拜访相片,limitedLevel 必须为 readWrite
[PHPhotoLibrary requestAuthorizationForAccessLevel:level2 handler:^(PHAuthorizationStatus status) {
switch (status) {
/**
恳求查询限制权限:需注意 `PHAuthorizationStatusLimited` 权限在 accessLevel 为 `PHAccessLevelReadWrite` 时收效
*/
case PHAuthorizationStatusLimited:
NSLog(@"limited");
break;
case PHAuthorizationStatusDenied:
NSLog(@"denied");
break;
case PHAuthorizationStatusAuthorized:
NSLog(@"authorized");
break;
default:
break;
}
}];
}
3.2 运用UIImagePickerController挑选图片资源(单选)
- 初始化
#pragma mark - 单选
/**
UIImagePickerController
*/
- (UIImagePickerController *)picker
{
if (!_picker) {
_picker = [[UIImagePickerController alloc]init];
}
return _picker;
}
- (IBAction)openPickerAciton:(id)sender
{
self.isDoing = NO;
if (self.isDoing) {
return;
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == NO) {
return;
}
self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
self.isDoing = YES;
[self presentViewController:self.picker animated:YES completion:nil];
}
- 处理署理
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
UIImage *image = info[UIImagePickerControllerOriginalImage];
self.imageView.image = image;
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
3.3 运用PHPicker挑选图片资源(多选)
- 初始化
#pragma mark - ******** 多选
- (IBAction)openNewPicker:(id)sender
{
//三种过滤类型
PHPickerFilter *imagesFilter = PHPickerFilter.imagesFilter;
PHPickerFilter *videosFilter = PHPickerFilter.videosFilter;
PHPickerFilter *livePhotosFilter = PHPickerFilter.livePhotosFilter;
PHPickerConfiguration *configuration = [[PHPickerConfiguration alloc] init];
configuration.filter = [PHPickerFilter anyFilterMatchingSubfilters:@[imagesFilter]]; // 可配置查询用户相册中文件的类型,支撑三种
configuration.selectionLimit = 0; // 默许为1,为0为跟从体系上限
PHPickerViewController *picker = [[PHPickerViewController alloc] initWithConfiguration:configuration];
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
- 处理署理
- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results API_AVAILABLE(ios(14)) {
[picker dismissViewControllerAnimated:YES completion:nil];
if (!results || !results.count) {
return;
}
NSItemProvider *itemProvider = results.firstObject.itemProvider;
if ([itemProvider canLoadObjectOfClass:UIImage.class]) {
__weak typeof(self) weakSelf = self;
//异步获取
[itemProvider loadObjectOfClass:UIImage.class completionHandler:^(__kindof id<NSItemProviderReading> _Nullable object, NSError * _Nullable error) {
if ([object isKindOfClass:UIImage.class]) {
__strong typeof(self) strongSelf = weakSelf;
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf.imageView.image = (UIImage *)object;
});
}
}];
}
}
see also
公号:iOS逆向