[iOS 8] PhotoKit 12 – 位置情報付の写真をフォトライブラリに複数枚追加する
はじめに
位置情報付の写真を「写真アプリ」上のフォトライブラリに追加するサンプルプロジェクトを作ってみました。
https://github.com/hirayaCM/AddPhotosSample
アルバムアプリ等の開発で、シミュレータでのデバックを行う時などを想定しています。 シミュレータには元々5枚程度しか写真が入っていないので、枚数がもっと欲しい方や、位置情報付の写真が欲しい方にピッタリです。
↓こんな感じで位置情報付きの写真をフォトライブラリに追加できます。
素材ファイルについて
当サンプルプロジェクトでは、以下のようなJSONファイルを基に写真ファイルを読み込むようにしてあります。 (JSONファイル/jpgファイルをXcodeプロジェクトにバンドルさせておきます。)
[ { "imageName": "001.jpg", "latitude": 35.70208, "longitude": 139.767935 }, { "imageName": "002.jpg", "latitude": 35.697431, "longitude": 139.774696 }, { "imageName": "003.jpg", "latitude": 35.700722, "longitude": 139.697358 }, { "imageName": "004.jpg", "latitude": 35.715298, "longitude": 139.772757 }, { "imageName": "005.jpg", "latitude": 35.549393, "longitude": 139.779839 } ]
実装
写真の取り込みが目的なのでFirstViewController(UIViewControllerのサブクラス)クラスにゴリゴリ書いてます。
[18行目〜] viewDidLoadメソッド
viewDidLoadメソッド内でcheckAuthorizationStatusメソッドを呼んでいます。
[111行目〜] checkAuthorizationStatusメソッド
アルバムへのアクセスが許可されていれば、createAlbumメソッドを呼んでいます。
[27行目〜] createAlbumメソッド
指定の名前のアルバムが未作成であれば作成し、addAssetsメソッドを呼んでいます。
[53行目〜] addAssetsメソッド
JSONファイルからNSDictionaryを作成し、1要素ごとにaddAssetWithAssetInfoメソッドを呼んでいます。
[65行目〜] addAssetWithAssetInfo:メソッド
引数のNSDictionaryからPHAssetを作成し、フォトライブラリに追加しています。また、追加したPHAssetに位置情報を付加しています。
#import "FirstViewController.h" @import Photos; @import CoreLocation; static NSString * const AlbumTitle = @"ContainLocationInfo"; @interface FirstViewController () @property (nonatomic, strong) PHAssetCollection *assetCollection; @end @implementation FirstViewController #pragma mark - methods - (void)viewDidLoad { [super viewDidLoad]; [self checkAuthorizationStatus]; } #pragma mark - methods - (void)createAlbum { PHFetchOptions *options = [PHFetchOptions new]; options.predicate = [NSPredicate predicateWithFormat:@"localizedTitle == %@", AlbumTitle]; PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options]; if (albums.count > 0) { // Album is exist self.assetCollection = albums[0]; [self addAssets]; } else { // Create new album. [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:AlbumTitle]; } completionHandler:^(BOOL success, NSError *error) { if (!success) { NSLog(@"Error creating AssetCollection: %@", error); } else { PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options]; self.assetCollection = albums[0]; [self addAssets]; } }]; } } - (void)addAssets { // Read asset infomation from JSON file NSString *path = [[NSBundle mainBundle] pathForResource:@"assetInfo" ofType:@"json"]; NSData *jsonData = [NSData dataWithContentsOfFile:path options:kNilOptions error:nil]; NSArray *assetInfoList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil]; for (NSDictionary *assetInfo in assetInfoList) { [self addAssetWithAssetInfo:assetInfo]; } } - (void)addAssetWithAssetInfo:(NSDictionary *)assetInfo { __block NSString *localIdentifier; [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // Create PHAsset from UIImage NSString *imageName = assetInfo[@"imageName"]; PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[UIImage imageNamed:imageName]]; PHObjectPlaceholder *assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset; localIdentifier = assetPlaceholder.localIdentifier; // Add PHAsset to PHAssetCollection PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection]; [assetCollectionChangeRequest addAssets:@[assetPlaceholder]]; } completionHandler:^(BOOL success, NSError *error) { if (!success) { NSLog(@"creating Asset Error: %@", error); } else { NSLog(@"creating Asset Success"); PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil]; PHAsset *asset = assets[0]; NSNumber *latitude = assetInfo[@"latitude"]; NSNumber *longitude = assetInfo[@"longitude"]; if (latitude && longitude) { // add location data CLLocation *location = [[CLLocation alloc]initWithLatitude:latitude.doubleValue longitude:longitude.doubleValue]; if ([asset canPerformEditOperation:PHAssetEditOperationProperties]) { [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset]; [request setLocation:location]; } completionHandler:^(BOOL success, NSError *error) { if (success) { NSLog(@"%s add location data success", __PRETTY_FUNCTION__); } }]; } } else { NSLog(@"latitude or longitude value is nil"); } } }]; } - (void)checkAuthorizationStatus { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; switch (status) { case PHAuthorizationStatusAuthorized: // The user has explicitly granted your app access to the photo library. NSLog(@"%s authorizationStatus is PHAuthorizationStatusAuthorized", __PRETTY_FUNCTION__); [self createAlbum]; break; case PHAuthorizationStatusNotDetermined: { // Explicit user permission is required for photo library access, but the user has not yet granted or denied such permission. NSLog(@"%s authorizationStatus is PHAuthorizationStatusNotDetermined", __PRETTY_FUNCTION__); // Requests the user’s permission, if needed, for accessing the Photos library. [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status){ [self createAlbum]; }]; } break; case PHAuthorizationStatusRestricted: NSLog(@"%s authorizationStatus is PHAuthorizationStatusRestricted", __PRETTY_FUNCTION__); break; case PHAuthorizationStatusDenied: NSLog(@"%s authorizationStatus is PHAuthorizationStatusDenied", __PRETTY_FUNCTION__); break; } } @end
まとめ
本記事は、位置情報付の写真をフォトライブラリに追加する実装例の紹介でした。サンプルプロジェクトは以下のリポジトリで公開しています。