エンジニアになりたい文系大学生

プログラミングを始めてからもうすぐ1年。iOSアプリ開発が中心。最近Webサービスの開発をやりたいのでRuby on Railsに触れ始めてます。

【iOS8】ドキュメントプロバイダ 実装

実装編

  1. Host appへUIDocumentMenuViewControllerを追加
  2. Containing appからDocument Providerにデータを渡す
  3. DocumentPickerViewControllerの編集

1. Host appへUIDocumentMenuViewControllerを追加

- デリゲート設定
<UIDocumentMenuDelegate, UIDocumentPickerDelegate>
- UIDocumentMenuViewController追加
// UIDocumentMenuViewControllerをImportモードで表示
- (IBAction)showImportMenu:(id)sender {
    NSArray *utis = @[(NSString *)kUTTypeRTF,(NSString *)kUTTypePNG,(NSString *)kUTTypeText,
                      (NSString *)kUTTypePlainText,(NSString *)kUTTypePDF, (NSString *)kUTTypeImage];
    UIDocumentMenuViewController *menu = [[UIDocumentMenuViewController alloc]
                                        initWithDocumentTypes:utis inMode:UIDocumentPickerModeImport];
    menu.delegate = self;
    [self presentViewController:menu animated:YES completion:nil];
}

// UIDocumentMenuViewControllerをExportモードで表示
- (IBAction)showExportMenu:(id)sender {
    NSURL *path = [[NSBundle mainBundle] URLForResource:@"2" withExtension:@"jpeg"];
    UIDocumentMenuViewController *menu = [[UIDocumentMenuViewController alloc]
                                          initWithURL:path inMode:UIDocumentPickerModeExportToService];
    menu.delegate = self;
    [self presentViewController:menu animated:YES completion:nil];
}

// メニューの中から選択されたUIDocumentPickerViewControllerを表示
- (void)documentMenu:(UIDocumentMenuViewController *)documentMenu didPickDocumentPicker:(UIDocumentPickerViewController *)documentPicker{
    documentPicker.delegate = self;
    [self presentViewController:documentPicker animated:YES completion:nil];
}

- (void)documentMenuWasCancelled:(UIDocumentMenuViewController *)documentMenu{
    NSLog(@"cancel");
}
- UIDocumentPickerViewControllerのデリゲートメソッド
// UIDocumentPickerViewControllerで選択したデータのURLが返ってくる
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url{
    NSLog(@"%@",url);
}

// 失敗した場合か、キャンセルされた時に呼ばれる
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller{
    NSLog(@"cancel");
}

2. Containing appからDocument Providerにデータを渡す

  • Document ProviderはContaining appとは異なるサンドボックスを持っているため、Document ProviderからContaining app内のデータへアクセスはできない。そのため、あらかじめデータを渡しておかなければならない。
- NSUserDefaultsでデータを渡す場合
NSUserDefaults *df = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.ContainingApp"];
[df setObject:@"sample" forKey:@"hello"];
- NSFileManagerからデータを渡す場合
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *url = [fm containerURLForSecurityApplicationGroupIdentifier:@"group.com.ContainingApp"];
NSData *imgData = [[NSData alloc] initWithData:UIImagePNGRepresentation([UIImage imageNamed:@"1.jpg"])];
NSString *path = [[url path] stringByAppendingPathComponent:@"1.jpg"];
if (![fm fileExistsAtPath:path]) {
    BOOL success = [fm createFileAtPath:path contents:imgData attributes:nil];
    if (!success) {
        NSLog(@"error");
    }
}

3. DocumentPickerViewControllerの編集

- UIDocumentPickerMode毎のUIの設定など
- (void)prepareForPresentationInMode:(UIDocumentPickerMode)mode {
    if (mode == UIDocumentPickerModeImport) {
        self.exportButton.alpha = 0.0;
    } else if (mode == UIDocumentPickerModeExportToService) {
        self.importButton.alpha = 0.0;
    }
}
- Host appにURLを返すためのメソッド
// UIDocumentPickerModeImportの場合
- (IBAction)import:(id)sender {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *documentURL = [fm containerURLForSecurityApplicationGroupIdentifier:@"group.com.ContainingApp"];
    NSString *path = [[documentURL path] stringByAppendingPathComponent:@"1.jpg"];
    [self dismissGrantingAccessToURL:[NSURL fileURLWithPath:path]];
}

// UIDocumentPickerModeExportToServiceの場合
- (IBAction)export:(id)sender {
    [self dismissGrantingAccessToURL:self.originalURL];
}

4. HostAppで渡されたデータを確認する

・HostAppのNSTemporaryDirectoryにデータが保存されている
・保存先は指定されているので、指定されたディレクトリへのアクセスが必要

// HostApp内で行い、allFileNamesに保存されたデータ名が入っている
NSFileManager *fm = [NSFileManager defaultManager];
NSString *tmp = NSTemporaryDirectory();
NSString *path = [tmp stringByAppendingPathComponent:@"DocumentPickerIncoming"];
NSArray *allFileNames = [fm contentsOfDirectoryAtPath:path error:nil];

余裕があったのでexportについても少しですが調べられました。 設定は同じなので、導入編で確認してください。

【iOS8】ドキュメントプロバイダ 導入

導入編

iOS8から追加されたextensionの一つ、ドキュメントプロバイダについて調べる機会があったので忘れないように載せておきます。

【ドキュメントプロバイダの主な機能】
  • import
  • export
  • open
  • move

今回やりたかったことは、「アプリAからアプリBに写真選択のリクエストを送る、アプリBからアプリAに選択された写真データを渡す」という感じ。
これを import でやってみました。

アプリへの導入

いろいろと設定するものがあるので、長くなりますが載せてみます。
import、export、open、move、どれでも同じように設定するようです。
プロジェクトが二つ必要になるので、HostApp、ContainingAppを用意しておく。

  1. DocumentProviderの追加(Containing app)
  2. App Groupsの設定(Containing app)
  3. iCloudの設定(Host app)

1. DocumentProviderの追加(Containing app)

<ターゲットの追加>
・【File】→【New】→【Target】→【DocumentProvider】を選択

f:id:DOORS:20141114161847p:plain

【Include a File Provider extension】:open, moveを使用する際チェック

・新たにターゲットとDocumentPickerViewControllerクラスなどが追加される

2. App Groupsの設定(Containing app)

・【TARGETS】の【Capabilities】を選択

f:id:DOORS:20141117222744p:plain

使用するApp Groupsにチェックを入れる
ContainingApp,MyDocumentProvider共に設定が必要
※ App Groupsの管理はiOS Dev CenterのCertificates, Identifires内で可能

3. iCloudの設定(Host app)

・【TARGETS】の【Capabilities】を選択

f:id:DOORS:20141114162506p:plain

iCloudの設定をONに
iCloud Documentsにチェック

コードを書き始める前に必要な設定はこのぐらいかと思います。
また時間のある時に実装の方法も載せておきたいです。