PhotoKit初用

简介: 我们公司做了一个DLNA的投屏软件,但是iOS是不能跨应用访问数据的,所以对于局域网投屏视频和图片需要把图片或者视频写入到应用的沙盒路径下。在我之前的前辈用的是AssetsLibrary,他是在进入界面之前写入,等到完全都写完了才会去显示。之前拍照的照片大小不是很大,而且手机的存储空间也不大,对于用户来说这么处理完全是没有问题的。但是,后来有用户反馈说在本地媒体界面一直都有那个“菊花转”。后来我们发现可能是用户的本地媒体数据过于大,倒是程序假死。我们老大说,你把这个功能优化一下,目标就是像微信那样是最好的。后来我们就选用的PhotoKit这个框架。

前言


我们公司做了一个DLNA的投屏软件,但是iOS是不能跨应用访问数据的,所以对于局域网投屏视频和图片需要把图片或者视频写入到应用的沙盒路径下。
在我之前的前辈用的是AssetsLibrary,他是在进入界面之前写入,等到完全都写完了才会去显示。之前拍照的照片大小不是很大,而且手机的存储空间也不大,对于用户来说这么处理完全是没有问题的。但是,后来有用户反馈说在本地媒体界面一直都有那个“菊花转”。后来我们发现可能是用户的本地媒体数据过于大,倒是程序假死。
我们老大说,你把这个功能优化一下,目标就是像微信那样是最好的。后来我们就选用的PhotoKit这个框架。


研究


之前并没有具体用过这个框架,所以就现在网上研究了一下。很幸运,我找到了一个很类似的DEMO。
我们只要在相应的控制器界面导入#import <Photos/Photos.h>就行。我们还需要在info.plist中添加相册的访问权限。
之后,我们建立一个二级控制器就可以了。


初用


弯路1:

当我们添加授权之后再相应的界面就会出现这么一个弹框
当我点击好的时候 界面并没有数据,但是当我第二期进入界面的时候数据就显示出来了。

解决1:

我们需要对这个弹框的点击事件进行处理,这里我们直接上代码:

- (void)getAuthorized{
    //判断是否有访问权限
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    //还没有去做选择
    if (status == PHAuthorizationStatusNotDetermined) {
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            //已经授权
            if (status == PHAuthorizationStatusAuthorized) {
                dispatch_async(dispatch_get_main_queue(), ^{
              //已经授权,显示相册 或者图片
                });
            }else{
                //做一个没有授权的提示
            }
        }];
    }
    //已经授权
    else if (status == PHAuthorizationStatusAuthorized){
        dispatch_async(dispatch_get_main_queue(), ^{
          //已经授权,显示相册 或者图片
        });
    }
    //拒绝访问
    else if (status == PHAuthorizationStatusRestricted){
        dispatch_async(dispatch_get_main_queue(), ^{
        //做一个没有授权的提示
        });
    }
}

那么接了下来我们继续。
这里我们先去做了获取相册的功能:

- (void)getAllAlbums{
    PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHCollection *collection in smartAlbums) {
        if ([collection isKindOfClass:[PHCollection class]]) {
            PHAssetCollection *assetCollection = (PHAssetCollection *)collection;

            switch (assetCollection.assetCollectionSubtype) {
                case PHAssetCollectionSubtypeSmartAlbumAllHidden:
                    break;
                case PHAssetCollectionSubtypeSmartAlbumUserLibrary:{
                    PHFetchResult *assetFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:self.options];
                    [self.smartFetchResultArray insertObject:assetFetchResult atIndex:0];
                    [self.smartFetchResultTitlt insertObject:collection.localizedTitle atIndex:0];
                }
                    break;
                default:{
                    PHFetchResult *assetFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:self.options];
                    [self.smartFetchResultTitlt addObject:collection.localizedTitle];
                    [self.smartFetchResultArray addObject:assetFetchResult];
                }
                    break;
            }
        }
    }
}

这里的self.smartFetchResultTitlt是用来存储相册标题的数组;self.smartFetchResultArray是用来存储相册内容的;self.options需要设置一下,代码如下:

- (PHFetchOptions *)options {
    if (!_options) {
        _options = [[PHFetchOptions alloc] init];
        _options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    }
    return _options;
}
弯路2:

在上面获取到的相册的名称,我在控制台打出来的都是英文的

但是我们想要的并不是英文的。

解决2:

依旧是在info.plist中:

显示图片,这里用PhototKit自身的PHCachingImageManager做显示就可以了。
我是用了一个collectionView做显示。方法如下:

    [self.imageManager requestImageForAsset:asset targetSize:CGSizeMake(self.bounds.size.width, self.bounds.size.width) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        weakSelf.imageView.image = result;
    }];

这里显示的只是一个缩略图,并不是很清晰,如果放到满屏看就会很模糊,那么还有另一种方式去获得清晰的图片:

WeakSelf(weakSelf);
    [[PHImageManager defaultManager]requestImageDataForAsset:self.asset                                                             options:nil
                                               resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {

                                                   UIImage *selectedImage = [UIImage imageWithData:imageData];
                                                   weakSelf.imageView.image = selectedImage;
                                                   weakSelf.title = [[info objectForKey:@"PHImageFileURLKey"] lastPathComponent];
                                               }];

这样不仅获得了图片,还可以获得这个照片的名字。


上面说的都是图片,接下来说说视频。

我么可以用下面这个方法去获取视频:

PHVideoRequestOptions *phVideoRequestOptions = [[PHVideoRequestOptions alloc]init];
        phVideoRequestOptions.version = PHImageRequestOptionsVersionCurrent;
        phVideoRequestOptions.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
        PHImageManager *manager = [PHImageManager defaultManager];
        [manager requestAVAssetForVideo:asset options:phVideoRequestOptions resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
            ShowVIdeoViewController *shouwVideoVC = [[ShowVIdeoViewController alloc]init];
            shouwVideoVC.asset = asset;
            shouwVideoVC.fileName =[[info objectForKey:@"PHImageFileSandboxExtensionTokenKey"] lastPathComponent];
            [weakSelf.navigationController pushViewController:shouwVideoVC animated:YES];
        }];
弯路3:

就是这个方法的等待时间比较长,用户体验不太好。


Live Photo

这个功能出现了有一段时间,我知道的软件只有微博支持了Live Photo的功能(小人可能见识短浅,有盆友知到别的软件也支持的话可以 私聊告诉我),我看PhotoKit支持Live Photo,那么我就小小的研究了一下。
但是在这个过程中我也是遇到了一些问题的,
我们看源码中给本地媒体分了很多种类型:

typedef NS_ENUM(NSInteger, PHAssetMediaType) {
    PHAssetMediaTypeUnknown = 0,
    PHAssetMediaTypeImage   = 1,
    PHAssetMediaTypeVideo   = 2,
    PHAssetMediaTypeAudio   = 3,
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);

typedef NS_OPTIONS(NSUInteger, PHAssetMediaSubtype) {
    PHAssetMediaSubtypeNone               = 0,

    // Photo subtypes
    PHAssetMediaSubtypePhotoPanorama      = (1UL << 0),
    PHAssetMediaSubtypePhotoHDR           = (1UL << 1),
    PHAssetMediaSubtypePhotoScreenshot PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = (1UL << 2),
    PHAssetMediaSubtypePhotoLive PHOTOS_AVAILABLE_IOS_TVOS(9_1, 10_0) = (1UL << 3),
    PHAssetMediaSubtypePhotoDepthEffect PHOTOS_AVAILABLE_IOS_TVOS(10_2, 10_1) = (1UL << 4),

    // Video subtypes
    PHAssetMediaSubtypeVideoStreamed      = (1UL << 16),
    PHAssetMediaSubtypeVideoHighFrameRate = (1UL << 17),
    PHAssetMediaSubtypeVideoTimelapse     = (1UL << 18),
} PHOTOS_AVAILABLE_IOS_TVOS(8_0, 10_0);
弯路4:

首先LivePhoto应该是属于PHAssetMediaTypeImage的,然后是属于PHAssetMediaSubtypePhotoLive的。
正常的理解就是这样对不对,但是在我的LivePhoto的相册中有的竟然会识别不出来。我去了本地媒体相册看了一下识别不出来的那些照片的类型,左上角竟然有两个标识,一个是Live,另一个是HDR
后来我就是把所有的类型都打印了一下,我发现这样的相片不属于任何一个类型。

解决4:

我在控制器打了一下看了一下子媒体类型的值,LivePhoto的类型值是8,既是LivePhoto又是HDR的类型值是10。我之前的媒体类型判断是:

asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive

而改成:

asset.mediaSubtypes >= PHAssetMediaSubtypePhotoLive

就可以了


下面来说我们怎么显示Live Photo:

PHLivePhotoRequestOptions *options = [[PHLivePhotoRequestOptions alloc]init];
    options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
    options.networkAccessAllowed = YES;
    options.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) {
        NSLog(@"progress = %f",progress);
    };
    [[PHImageManager defaultManager]requestLivePhotoForAsset:self.asset targetSize:self.livePhotoView.bounds.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
        self.livePhotoView.livePhoto = livePhoto;
        NSLog(@"info = %@",info);
    }];

这里的self.livephotoview 是PHLivePhotoView这个类 ,就和普通的View初始化一样。
这样你现实出来的LivePhoto就可以了,这时你只要按住照片,照片就会动起来,这里你也可以设置你的播放设置,我是这样设置的:

 [self.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleHint];

这样设置的效果就是进来界面,livePhoto就会自动播放一次。

弯路5:

我先通过上面的方法打印info里面的信息,但是控制台给我这样的信息:

error reading settings archive file: <ISRootSettings: /var/mobile/Containers/Data/Application/BCAA7EBA-543E-4B9E-B945-D8C4C509C491/Documents/com.C4ibD3.PhotoKitDemo.settings/ISRootSettings_10.plist>
2017-06-16 09:00:16.433082+0800 PhotoKitDemo[1444:307243] info = {
}

不知道是为什么?


传送门

github:PhotoKitDemo

相关文章
|
6月前
|
前端开发 测试技术 API
干掉丑陋的 Swagger,堪称开发者的瑞士军刀
“为什么改了这个没告诉我”,“实际功能和文档上说的不一样啊”。这些话大家做开发的想必耳朵都听出老茧了。真不是故意的,有时候任务比较急,就先改了代码,想着以后再同步文档,然后就给忘了。项目更新又全靠社交软件通知,人一多难免有一两个没及时沟通到的。确实给合作的小伙伴带来麻烦,但说实话开发商也挺委屈的。
|
10月前
|
存储 算法 iOS开发
ZPhotoBrowser (基于之前的那篇文章PhotoKit初用)
作为一个iOS开发人员,我已经不知不觉的在帝都这个地方上干了块两年了。前一阵,由于公司的发展方向的问题,我被迫加入了找工作的大军之中。这可把我担心坏了,因为我之前的一个同事找了好久都没有找到工作,之后他就选择回老家发展了。做过iOS这行的都知道现在是什么行情了,我就不多说了。不过还好我找了一周左右吧,面试不少。但是现在招人的公司,真的不知道要招什么样的开发人员,面试草草了事的偏多。还有就是自认为大牛的比较多,我记得我面了一家智能家居的科技公司。那个面试我的面试官,看了我做过的产品。就给我说了一句:“你就是个调接口和写TableView的啊。”这话听起来真的让人难受,用一句很流行的话说,那就是“
|
12月前
|
SQL XML 存储
MyBatis这样用,同事直呼哇塞,堪称最佳实践
MyBatis是一款非常流行的ORM框架,相信很多小伙伴都在使用。我们经常会把它和MyBatis-Plus或者MBG一起使用,用多了之后对于其一些常规操作就不太熟悉了。最近总结了下MyBatis的实用用法和技巧,希望对大家有所帮助!
|
前端开发 Oracle 算法
卷王必备学习的MyBatis-Plus用法,不来瞧瞧吗~~
卷王必备学习的MyBatis-Plus用法,不来瞧瞧吗~~
115095 1
卷王必备学习的MyBatis-Plus用法,不来瞧瞧吗~~
|
存储 开发工具 git
没用过.gitignore还敢自称高级开发?
Git是跟踪项目中所有文件的好工具, 但是,您会希望在项目的整个生命周期中不要跟踪某些文件及其变更。
没用过.gitignore还敢自称高级开发?
初用体验
飞天加速计划感想
|
C# 数据库 Windows
艾伟_转载:基于.NET平台的Windows编程实战(一)——前言
本系列文章导航 基于.NET平台的Windows编程实战(一)——前言 基于.NET平台的Windows编程实战(二)—— 需求分析与数据库设计 基于.NET平台的Windows编程实战(四)—— 数据库操作类的编写 基于.NET平台的Windows编程实战(五)—— 问卷管理功能的实现 基于.NET平台的Windows编程实战(六)—— 题目管理功能的实现   前言:本系列文章是一个关于.NET Windows编程的入门实战教程。
1008 0
|
C# 数据库 Windows
艾伟:基于.NET平台的Windows编程实战(一)——前言
本系列文章导航 基于.NET平台的Windows编程实战(一)——前言 基于.NET平台的Windows编程实战(二)—— 需求分析与数据库设计 基于.NET平台的Windows编程实战(四)—— 数据库操作类的编写 基于.NET平台的Windows编程实战(五)—— 问卷管理功能的实现 基于.NET平台的Windows编程实战(六)—— 题目管理功能的实现   前言:本系列文章是一个关于.NET Windows编程的入门实战教程。
785 0
|
SQL 存储 关系型数据库
艾伟:小巧优美的ORM框架-doodads入门指南[转载]
  关于.net下的ORM框架,大家最为耳熟的可能就是NHibernate了,当然,很多公司正在使用自己开发的ORM框架,笔者至少见过3家不同公司的ORM框架,其实都是大同小异,借助于codesmith、mygeneration等代码生成工具,自己开发一个ORM框架也不是什么难事,关键的问题是,你能不能设计出代码优美简洁、功能灵活、定制方便以及部署容易的ORM框架。
1270 0