iOS PhotoKit 初用


前言


咱們公司作了一個DLNA的投屏軟件,可是iOS是不能跨應用訪問數據的,因此對於局域網投屏視頻和圖片須要把圖片或者視頻寫入到應用的沙盒路徑下。
在我以前的前輩用的是AssetsLibrary,他是在進入界面以前寫入,等到徹底都寫完了纔會去顯示。以前拍照的照片大小不是很大,並且手機的存儲空間也不大,對於用戶來講這麼處理徹底是沒有問題的。可是,後來有用戶反饋說在本地媒體界面一直都有那個「菊花轉」。後來咱們發現多是用戶的本地媒體數據過於大,卻是程序假死。
咱們老大說,你把這個功能優化一下,目標就是像微信那樣是最好的。後來咱們就選用的PhotoKit這個框架。git


研究


以前並無具體用過這個框架,因此就如今網上研究了一下。很幸運,我找到了一個很相似的DEMO。
咱們只要在相應的控制器界面導入#import <Photos/Photos.h>就行。咱們還須要在info.plist中添加相冊的訪問權限。
github

在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須要設置一下,代碼以下:async

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

在上面獲取到的相冊的名稱,我在控制檯打出來的都是英文的
ide

英文相冊名

可是咱們想要的並非英文的。

解決2:

依舊是在info.plist中,以下圖:
fetch

修改屬性

顯示圖片,這裏用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;
    }];複製代碼

這裏顯示的只是一個縮略圖,並非很清晰,若是放到滿屏看就會很模糊,那麼還有另外一種方式去得到清晰的圖片:ui

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

相關文章
相關標籤/搜索