UIDocumentInteractionControllerによる、アプリケーション間のファイル受渡し

昨年、iOSの中で、アプリケーション同士が連携するためのしくみ - The iPhone Development Playgroundで、UIDocumentInteractionControllerを使ったアプリケーション間連携について簡単に説明しました。そのときに少し触れたとおり、SysStats MonitorSysStats Liteの間で、UIDocumentInteractionControllerを使った連携機能を追加しましたので、もう少し技術的な説明をしたいと思います。

処理の流れ

以下に、全体の流れを示します。

ここでは、以下の2つの目的で、UIDocumentInteractionControllerを使った連携を使用しています。

(1) SysStats Liteから、SysStats Monitorへのプロセスブックマークの移行

SysStats Liteで蓄積したプロセスブックマークを、SysStats Monitorで流用するための機能です。

(1-1) Send ユーザの操作により、UIDocumentInteractionController経由で、SysStats Monitorが自動的に起動され、プロセスブックマークデータを送られる。
そして、SysStats Monitor側のInboxと呼ばれるフォルダに、そのデータが保存される。
(1-2) Import ユーザの操作により、Inboxからブックマークデータを読み込み、現在のブックマークデータにインポートする。
(2) SysStats Monitorのプロセスブックマークを、Email経由で共有

異なるデバイスのSysStats Monitor間でプロセスブックマークを共有するための機能です。
例えば、iPhoneiPadを所有しているユーザの場合、iPhoneで蓄積したプロセスブックマークを、iPad側に取り込む(Import)ことができます。

(2-1) Export ユーザの操作により、Message UI Frameworkを使って、現在のブックマークデータ添付ファイルとするメールを作成する。
(2-2) Send Emailとして送信する。
(2-3) Send 受信側のデバイスで、Mail.appでEmailを受信し、添付ファイルを開く操作をすることで、SysStats Monitorにプロセスブックマークデータを送ることができる。
(1-1)と同様に、SysStats Monitorが自動起動され、Inboxフォルダに、そのデータが保存される。
(2-4) Import ユーザの操作により、Inboxからブックマークデータを読み込み、現在のブックマークデータにインポートする。

プロセスブックマークデータのUTI宣言

Appleは、データタイプの識別子のための構文として、UTI(uniform type identifiers)を定義しています。
UIDocumentInteractionControllerに、データタイプを認識させるためには、そのデータのUTIを宣言する必要があります。

参考ドキュメント

UTIに関しては、Uniform Type Identifiers Overviewを参照してください。
Info.plistの各項目の設定値については、Information Property List Key Referenceを参照してください。

SysStats MonitorのInfo.plistに、以下のような設定を行っています。

	<key>UTExportedTypeDeclarations</key>
	<array>
		<dict>
			<key>UTTypeIdentifier</key>
			<string>[プロセスブックマークのUTI]</string>
			<key>UTTypeDescription</key>
			<string>SysStatsMonitor&apos;s proprietary processbookmark format</string>
			<key>UTTypeConformsTo</key>
			<array>
				<string>public.item</string>
			</array>
			<key>UTTypeTagSpecification</key>
			<dict>
				<key>public.filename-extension</key>
				<array>
					<string>[プロセスブックマークの拡張子]</string>
				</array>
				<key>public.mime-type</key>
				<string>[プロセスブックマークのMIMEタイプ]</string>
			</dict>
		</dict>
	</array>
UTTypeIdentifier プロセスブックマークのUTIを指定しています。
UTTypeTagSpecification プロセスブックマークの拡張子MIMEタイプを指定しています。
UTTypeConformsTo UTIは、適合性(Conformance)に基づく階層構造の中に定義します。
プロセスブックマークは、SysStats Monitor独自のデータフォーマットなので、public.itemという、最上位階層を指定しています。
テキストファイルであるからといって、public.textを指定した場合、次で説明するLSItemContentTypesにpublic.textが指定されているすべてのアプリで開くことが可能となってしまうので、注意が必要です。

SysStats Monitorがプロセスブックマークを受取るための設定

SysStats MonitorのInfo.plistに、以下のような設定を行っています。

	<key>CFBundleDocumentTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeName</key>
			<string>SysStatsMonitor&apos;s proprietary processbookmark format</string>
			<key>CFBundleTypeRole</key>
			<string>Viewer</string>
			<key>LSHandlerRank</key>
			<string>Owner</string>
			<key>LSItemContentTypes</key>
			<array>
				<string>[プロセスブックマークのUTI]</string>
			</array>
		</dict>
	</array>

ここでのポイントは、LSItemContentTypesに、前述のUTTypeIdentifierにて指定した[プロセスブックマークのUTI]を指定しているところです。この設定によって、SysStats Monitorは、プロセスブックマークを受取ることができるようになります。

詳細は、Document Interaction Programming Topics for iOSの"Registering the File Types Your App Supports"を参照してください。

ドキュメントを送る側のコーディングイメージ

SysStats Liteの設定画面で、「SysStats Monitorへエクスポート」を選択すると、以下のような、ドキュメント送信先のアプリを選択するメニューが表示されます。

実際の処理は、UIDocumentInteractionControllerを使って以下のように記述されています。

    self.docController = [UIDocumentInteractionController interactionControllerWithURL:url];
    docController.delegate = self;
    BOOL isValid = [docController presentOpenInMenuFromRect:CGRectZero inView:self.tabBarController.view animated:YES];
    if (!isValid) {
        // 必要に応じてエラー処理(AlertPanel)
    }

メニューから、「SysStatsMon」が選択された後、UIDocumentInteractionControllerDelegateメソッドが呼び出されます。SysStats Liteでは、以下のように特に何もしていませんが、各タイミングで必要な処理があれば、それぞれに記述します。

#pragma mark UIDocumentInteractionControllerDelegate

- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application {
    NSLog(@"!!!!! Sending to: %@", application);
}

- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
    NSLog(@"!!!!! Sent to: %@", application);
}

- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
    self.docController = nil;
}

ドキュメントを受取る側のコーディングイメージ

以下に、ドキュメントを受取る側である、SysStats Monitorのコーディングイメージを示します。

UIDocumentInteractionControllerDelegate経由で起動されると、application:didFinishLaunchingWithOptions:メソッドが呼ばれます。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if (launchOptions) {
        NSURL *launchedURL = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
        if ([launchedURL isFileURL]) {
            if ([[launchedURL pathExtension] isEqualToString:kProcessBookmarkFileExtention]) {
                
                // 確認メッセージのためのファイル名などの情報を取得
                NSString *fileName = [launchedURL lastPathComponent];
				...

				// AlertPanelを表示
                
            }
            
        }
        
    }
    return YES;
    
}

SysStats Monitorでは、プロセスブックマークを受け取った時に、以下のような確認メッセージを表示しています。

[補足] Inboxフォルダのパスは、以下のようにして取得できます。
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *inboxPath = [[paths objectAtIndex:0] stringByAppendingString:@"/Inbox"];