UIDocumentInteractionController にファイルを別名で渡す

2012年3月6日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

問題


UIDocumentInteractionController で他のアプリにファイルを渡すことができる。こんな感じ。
self.documentInteractionController =
    [UIDocumentInteractionController  interactionControllerWithURL:url];
self.documentInteractionController.delegate = self;
[self.documentInteractionController presentOptionsMenuFromBarButtonItem:
    self.sendApplicationButtonItem animated:YES];

普通はアプリで作成したファイルのURLをそのまま渡せば事足りるのだが、ネットワークからダウンロードしてキャッシュしているファイルだったりすると名前が管理上の適当な名前になっているケースがある。
実名:UserDocument.pdf
キャッシュ名:js9798sfs8df9s9fsd.pdf
キャッシュファイルのURLをそのまま他のアプリへ渡すと "js9798sfs8df9s9fsd.pdf" みたいな名前で扱われて使い勝手が悪い。できれば渡した先のアプリでも "UserDocument.pdf" として扱わせたい。

UIDocumentInteractionController にはこういった目的の為に nameプロパティが用意されている。
@property(nonatomic,copy) NSString *name
This property contains the filename without any preceding path information. The default value of this property is derived from the path information in the URL property. You can change the value of this property as needed if you want to associate a different name with the file.
ところが nameプロパティを設定しても送った先のアプリでは使われず "js9798sfs8df9s9fsd.pdf" のまま。

どうしても UIDocumentInteractionController へ渡す URLのファイル名を "UserDocument.pdf" にする必要があるようだ。方法としてはキャッシュファイルをコピーする方法がある、がこれは非効率すぎる。こういう時はシンボリックリンクを使うのがいい。

(参考)ソフトリンク - Wikipedia


シンボリックリンク


iOS でもシンボリックリンクを使うことができて NSFileManagerが標準でサポートしている。
createSymbolicLinkAtURL:withDestinationURL:error:

そこで UIDocumentInteractionController へ渡す直前にシンボリックリンクを作成してそのURLを渡してみた。
if ([fileManager createSymbolicLinkAtURL:cacheURL withDestinationURL:newURL error:&error]) {
        NSLog(@"%s|%@", __PRETTY_FUNCTION__, @"a symbolic link is created");
    } else {
        NSLog(@"%s|%@", __PRETTY_FUNCTION__, error);
    }

結果は ×

ファイル名は正しく渡るのだが送り先のアプリで正しく扱われない。詳しく調べていないがシンボリックリンク自体を開いているのだがと思われる(実体へのリンク情報が書かれているだけで実質何も入っていない)。

うーむ。


ハードリンク


どうするかと考えていたところ @nakiwo さんからこんなヒントが。

ハードリンクか!

(参考)ハードリンク - Wikipedia

iOS では NSFileManager がハードリンクもサポートしている。
linkItemAtURL:toURL:error:

早速試してみた。
if ([fileManager linkItemAtURL:cacheURL toURL:newURL error:&error]) {
        NSLog(@"%s|%@", __PRETTY_FUNCTION__, @"a hard link is created");
    } else {
        NSLog(@"%s|%@", __PRETTY_FUNCTION__, error);
    }

結果は ◯

送り先のアプリで意図したファイル名 "UserDocument.pdf" として扱われ、中身もちゃんと渡っている。

GoodReader, DropBox, Numbers などで動作確認できた(4S/iOS5.0.1)。
ただ iBookのみファイル名が英数字の羅列になっていた(読み込み時は意図したファイル名が一瞬表示されるのだが)。


実装パターン


作ったハードリンクは消しておく必要がある。消さないと元のファイルを消してもハードリンクが残ってしまう(参照カウントが残っている限りファイルの実体が消えない)。作るタイミングと消すタイミングは UIDocumentInteractionControllerDelegate で用意されているアプリ送出前後のメソッドを使うのがいい。
- (void)documentInteractionController:(UIDocumentInteractionController *)controller
           willBeginSendingToApplication:(NSString *)application
{
    // ハードリンク作成 ....
}

- (void)documentInteractionController:(UIDocumentInteractionController *)controller 
           didEndSendingToApplication:(NSString *)application
{
    // ハードリンク削除 ....
}
送るメニューを出す手順の中で呼び出す [UIDocumentInteractionController interactionControllerWithURL:url] の時点では実体が存在する必要はない。先ほどのデリゲート documentInteractionController:willBeginSendingToApplication: で作っても間に合った。


- - - -

※今回はサンプル無しです。


人気の投稿(過去 30日間)