ios访问系统相册的新框架Photo Kit在使用时候感觉还是蛮恶心的,所有总结了一下,整理下来,以备以后使用
请求相册授权
- 在info.plist文件中加入下面两个key,一个是访问相册所需,另一个是调用摄像头所需
NSPhotoLibraryUsageDescription
访问相册
NSCameraUsageDescription
使用相机
- 获取授权的状态
鉴于ios对于用户隐私的保护,使用相册时需要用户授权,用户么有授权的时候不能访问相册,
PHPhotoLibrary 代表整个照片应用,权限的四种状态如下,
只有PHAuthorizationStatusAuthorized,才能使用相册
/*
PHAuthorizationStatusNotDetermined 未决定
PHAuthorizationStatusRestricted 受限制
PHAuthorizationStatusDenied 拒绝
PHAuthorizationStatusAuthorized 允许
*/
[PHPhotoLibrary authorizationStatus];
- 如果用户没有开启授权,可以来个提醒,或者在合适的时机去跳转到授权界面
+(void)requestAuthorizationIfNotDetermined{
if (IOSVersion >= 8.0) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
} else {
NSURL *privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"];
if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) {
[[UIApplication sharedApplication] openURL:privacyUrl];
} else {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"相册未授权" message:@"请手动开启相册授权" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
[alert show];
}
}
}
创建app对应的相册
先来了解几个类
PHAssetCollection
这个类相当于一个照片组,Collection就是集合的意思
属性
//The type of the asset collection, such as an album or a moment.
//相册的类型
@property(nonatomic, assign, readonly) PHAssetCollectionType assetCollectionType;
//子类型
@property(nonatomic, assign, readonly) PHAssetCollectionSubtype assetCollectionSubtype;
//估算的相册中的资源(Asset)数量,没什么卵用
@property(nonatomic, assign, readonly) NSUInteger estimatedAssetCount;
//开始日期
@property(nonatomic, strong, readonly) NSDate *startDate;
//结束日期
@property(nonatomic, strong, readonly) NSDate *endDate;
//粗略估计存放的位置,没什么卵用
@property(nonatomic, strong, readonly) CLLocation *approximateLocation;
//这个才是最有用的,这个就是所有相册名称的数组,
@property(nonatomic, strong, readonly) NSArray *localizedLocationNames;
//单个相册名称
@property(nonatomic, strong, readonly) NSString *localizedTitle;
这个框架里要查找某个东西,都是用 fetch xxx,这个规律
明显
- 一些常用方法的解释
这个方法是我们传入一个相册名称的数组, PHFetchOptions,我们的一些描述信息
+ (PHFetchResult *)fetchAssetCollectionsWithLocalIdentifiers:(NSArray *)identifiers options:(PHFetchOptions *)options;
PHFetchOptions
这个类就是对要要获取(Fetch)的内容的一个描述,相当于选择的条件整合,这个类就那么几个属性,可以根据需求来定义
属性
//描述信息, NSPredicate这个类和SQL语句的用法类似,具体可参见
http://www.cocoachina.com/ios/20160111/14926.html
@property(nonatomic, strong) NSPredicate *predicate;
//排序类型
用法如下,按照你要求的排序类型来给出查询结果
/*
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES],
];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithOptions:fetchOptions];
return [fetchResult firstObject];
*/
@property(nonatomic, strong) NSArray *sortDescriptors;
//是否想要包含资源变化的详细信息
@property(nonatomic, assign) BOOL wantsIncrementalChangeDetails;
//每次的查询数量限制
@property(nonatomic, assign, readwrite) NSUInteger fetchLimit;
//这三个是要包含的资源类型
@property(nonatomic, assign) BOOL includeAllBurstAssets;
@property(nonatomic, assign) BOOL includeHiddenAssets;
@property(nonatomic, assign) PHAssetSourceType includeAssetSourceTypes;
下面开始创建对应app名称的一个相册
- (PHAssetCollection *)createdCollection
{
// 获得软件名字
NSString *title = [NSBundle mainBundle].infoDictionary[(__bridge NSString *)kCFBundleNameKey];
// 抓取所有的自定义相册
PHFetchResult *results= [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 查找当前App对应的自定义相册
for (PHAssetCollection *collection in results) {
if ([collection.localizedTitle isEqualToString:title]) {
return collection;//找到了就返回
}
}
/** 当前App对应的自定义相册没有被创建过 **/
// 创建一个【自定义相册】
NSError *error = nil;
__block NSString *createdCollectionID = nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
createdCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier;
} error:&error];
if (error) return nil;
// 根据唯一标识获得刚才创建的相册
return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionID] options:nil].firstObject;
}
系统相册的获取方法
自己封装了一个关于相册的类
#import
#import "YSPhotoKit.h"
@interface YSAssetAlbum : NSObject
@property (nonatomic, strong) NSString *name; ///< The album name
@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain
@property (nonatomic, strong) PHFetchResult *result; ///相当于存储asset的数组
@property (nonatomic, strong) NSArray *models;//所有照片模型
@property (nonatomic, strong) NSArray *selectedModels;//选中的照片
@property (nonatomic, assign) NSUInteger selectedCount;//选中的数量
+ (YSAssetAlbum *)albumWithResult:(PHFetchResult*)result name:(NSString *)name;
@end
//.m文件的实现
#import "YSAssetAlbum.h"
@implementation YSAssetAlbum
+ (YSAssetAlbum *)albumWithResult:(PHFetchResult*)result name:(NSString *)name{
YSAssetAlbum *album = [[YSAssetAlbum alloc]init];
album.result = result;
album.name = name;
if ([result isKindOfClass:[PHFetchResult class]]) {
album.count = result.count;
}
return album;
}
@end
//获得相机胶卷
-(void)getSmartAlbumAllowVideo:(BOOL)allowVideo AllowPhoto:(BOOL)allowPhoto completion:(void(^)(YSAssetAlbum *model))completion{
__block YSAssetAlbum *album ;
PHFetchOptions *option = [[PHFetchOptions alloc]init];
if (IOSVersion >= 8.0) {
if (!allowVideo) {
option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
}
if (!allowPhoto) {
option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
PHAssetMediaTypeVideo];
}
NSSortDescriptor *sortDescriptors = [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate];
option.sortDescriptors = @[sortDescriptors];
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (PHAssetCollection *assetCollection in fetchResult) {
//过滤掉不是相册的对象
if (![assetCollection isKindOfClass:[PHAssetCollection class]]) {
continue;
}
if ([self isCameraRollAlbum:assetCollection.localizedTitle]) {
PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:option];
album = [YSAssetAlbum albumWithResult:assetsFetchResult name:assetCollection.localizedTitle];
if (completion){
completion(album);
}
break;
}
}
}
}
总结
从上面的简单描述可见,查询一个相册内资源的方法是
1 首先要请求授权 PHPhotoLibrary
2 然后要创建描述信息 PHFetchOptions
3 然后用 PHAssetCollection 去fetch xxx ,得到PHFetchResult
4 接着遍历PHFetchResult,这个类里面存的又都是PHAssetCollection
5然后用 PHAsset 去fetch xxx ,获取资源得到的又是PHFetchResult *assetsFetchResult
这个PHFetchResult里面存的是PHAsset,其实PHFetchResult就是一个和数 组一样功能的类
- 如果我们想要取得某个PHAsset所对应的照片或者视频,又需要用到一个类
PHImageManager ,这个类是个单列,然后把我们的PHAsset当做参数传入这个类的 request xxxx ForAsset xxx方法中,类似的方法有好几个- requestImageForAsset
- requestImageDataForAsset
- requestLivePhotoForAsset
- requestPlayerItemForVideo
- requestAVAssetForVideo
等
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeDefault options:option resultHandler:
最后查询的结果在resultHandler中回调出来,整个思路就是这样,我自己封装了一些方法,使用方便点,需要的可以去下载
https://github.com/HongXiuTanXiang/YSphoto