Hatena::ブログ(Diary)

24/7 twenty-four seven Twitter

Bloglinesで閲読登録 ADD TO Hatena::RSS Subscribe with livedoor Reader Add to Google

mail address

Follow me on twitter.

iPhone アプリケーション

Hatena touch LDR touch TV Listings LCD Clock MyWebClip MyWebClip LITE  Japan Subway Route Map こころくろっく 英辞郎 on the WEB for iPhone(アルク)
i-Radio くるりんぱ性格診断 英辞郎検索ランキング(アルク) kotobank - コトバンク miil

iPad アプリケーション

LCD Clock HD 「超」整理手帳 for the iPad

Windows 8 Store アプリケーション

クックパッド

共著

2011-01-31

UIDocumentInteractionController で特定のファイルを開くことのできるアプリケーションを調べたり、直接開いたりする。

南東京iPhone開発者勉強会 #5 - Togetter

UIDocumentInteractionController

UIDocumentInteractionController で、特定の拡張子のファイルを開けるアプリがあるかどうかを調べる方法 - iOS プログラミングメモ - iPhoneアプリ開発グループ


昨日、南東京iPhone開発者勉強会 5回目で UIDocumentInteractionController について話してきました。

UIDocumentInteractionController は下記のようにあるファイルをサポートしている(開くことのできる)アプリケーションがデバイスにインストールされているとき、そのファイルを別のアプリケーションで開くというアプリケーション連携を実現するためのクラスです。

Safari で PDF ファイルを開いたときに別のアプリケーションで開くメニューが表示されたりするので見たことがあるかもしれません。

f:id:KishikawaKatsumi:20110131234234p:image:w320


そのとき、その機能で特定のファイルについて開けるアプリがあるかどうかだけ調べたりとかできないかという話がでたので調べてみました。


まあ、そのときの結論としては UIDocumentInteractionController はプレビューするか、そのファイルを開けるアプリがある場合に選択メニューを出すかで基本的にお任せで使うものなので正攻法では無理ということなのですが、選択メニューが出せてる以上、内部的にはそういう仕組みはきっと普通にあるだろうということで調べてみました。


とりあえず、class-dump してみます。

UIDocumentInteractionController-Private.h
UIDocumentInteractionController-QLPreviewController.h
UIDocumentInteractionController-QLPreviewControllerDataSource.h
UIDocumentInteractionController-UIActionSheetDelegate.h
UIDocumentInteractionController-UIPopoverControllerDelegate.h
UIDocumentInteractionController.h

UIDocumentInteractionController-Private.h といういかにも怪しそうなファイルがあるので見てみましょう。

#import <UIKit/UIDocumentInteractionController.h>

@class UIPopoverController, _UIPreviewItemProxy;

@interface UIDocumentInteractionController (Private)
@property(readonly, nonatomic) id previewController;
@property(readonly, nonatomic) UIPopoverController *popoverController;
@property(readonly, nonatomic) _UIPreviewItemProxy *previewItemProxy;
- (void)_presentPreview:(id)arg1;
- (void)_presentOpenIn:(id)arg1;
- (void)_presentOptionsMenu:(id)arg1;
- (id)_applications:(BOOL)arg1;
- (void)_openDocumentWithApplication:(id)arg1;
- (void)_openDocumentWithCurrentApplication;
- (void)openResourceOperation:(id)arg1 didFinishCopyingResource:(id)arg2;
- (void)_finishedCopyingResource;
- (BOOL)_setupForOptionsMenu;
- (BOOL)_setupForOpenInMenu;
- (BOOL)_delegateExistsAndImplementsRequiredMethods:(id *)arg1;
- (BOOL)_setupPreviewController;
- (void)_invalidate;
- (void)_interfaceOrientationWillChange:(id)arg1;
- (id)_applicationToOpen;
- (void)_setApplicationToOpen:(id)arg1;
- (void)_setUnzippedDocumentURL:(id)arg1;
- (id)_unzippedDocumentURL;
- (BOOL)_canUnzipDocument;
- (BOOL)_isFilenameValidForUnzipping:(id)arg1;
- (BOOL)_isValidURL:(id)arg1;
- (void)_unzipDocument;
- (void)_unzipDocumentToDirectory:(id)arg1;
- (void)_zipOperationCompleted;
- (void)_cleanUpUnzippedDocument;
@end

それっぽいものが見つかりましたね。

- (id)_applications:(BOOL)arg1;
- (void)_openDocumentWithApplication:(id)arg1;

引数の意味が分かりませんがきっとこのメソッドはそのファイルを開けるアプリケーションの Array が返ってくるのでしょう。

とりあえず、呼んでみました。

NSLog(@"%@", docInteractionController.UTI);
NSLog(@"%@", [docInteractionController _applications:YES]);

私の環境では結果はこのようになりました。ちなみに引数を NO に変えてみても結果は変わらなかったので引数の意味は分かりませんです。

2011-01-31 23:20:31.788 DocInteraction[1959:307] public.plain-text
2011-01-31 23:20:31.929 DocInteraction[1959:307] (
    "LSApplicationProxy: com.hogbaysoftware.PlainText",
    "LSApplicationProxy: com.evernote.iPhone.Evernote"
)
2011-01-31 23:20:32.138 DocInteraction[1959:307] public.jpeg
2011-01-31 23:20:32.223 DocInteraction[1959:307] (
    "LSApplicationProxy: com.evernote.iPhone.Evernote"
)
2011-01-31 23:20:32.259 DocInteraction[1959:307] com.adobe.pdf
2011-01-31 23:20:32.289 DocInteraction[1959:307] (
    "LSApplicationProxy: com.lexcycle.stanza",
    "LSApplicationProxy: com.yourcompany.OpenIn",
    "LSApplicationProxy: com.evernote.iPhone.Evernote",
    "LSApplicationProxy: jp.tatsumi-sys.sidebooks",
    "LSApplicationProxy: com.apple.iBooks"
)
2011-01-31 23:20:32.315 DocInteraction[1959:307] public.html
2011-01-31 23:20:32.334 DocInteraction[1959:307] (
    "LSApplicationProxy: com.evernote.iPhone.Evernote"
)

思ったとおりそのファイルをサポートしているアプリケーションのリストが返ってきています。

LSApplicationProxy は MobileCoreServices.framework に含まれるクラスですね。

#import <MobileCoreServices/LSResourceProxy.h>

@class NSArray, NSString;

@interface LSApplicationProxy : LSResourceProxy
{
    NSArray *_privateDocumentIconNames;
    LSApplicationProxy *_privateDocumentTypeOwner;
}

+ (id)applicationProxyForIdentifier:(id)arg1;
+ (id)applicationProxyForIdentifier:(id)arg1 roleIdentifier:(id)arg2;
- (id)_initWithApplicationIdentifier:(id)arg1 roleIdentifier:(id)arg2 name:(id)arg3 resourcesDirectoryURL:(id)arg4 iconFileNames:(id)arg5 iconIsPrerendered:(BOOL)arg6;
- (void)dealloc;
@property(readonly, nonatomic) NSString *applicationIdentifier;
@property(readonly, nonatomic) NSString *roleIdentifier;
- (id)resourcesDirectoryURL;
- (id)privateDocumentIconNames;
- (void)setPrivateDocumentIconNames:(id)arg1;
- (id)privateDocumentTypeOwner;
- (void)setPrivateDocumentTypeOwner:(id)arg1;
- (id)localizedName;
- (BOOL)isEqual:(id)arg1;
- (unsigned int)hash;
- (id)description;

@end

戻り値の Array から適当なオブジェクトを引数として、先のもうひとつのメソッドに呼んであげると見事そのアプリケーションをドキュメントに関連付けて起動することができました。

NSArray *applications = [docInteractionController _applications:YES];
for (id app in applications) {
    if ([[app localizedName] isEqualToString:@"Stanza"]) {
        [docInteractionController _openDocumentWithApplication:app];
        break;
    }
}

と、まあこんな感じなのですが、なにぶん Undocumented API なのでそのまま使うのは難しいですね。

ただ使えるといろいろと便利な API だと思いますので、開放してほしいと思う方はバグレポートから要望を送ってみるといいと思いますよ。

Bug Reporting - Apple Developer

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/KishikawaKatsumi/20110131/1296485384