[iOS] Info.plistにカスタムUTIを追加し、iOSがデフォルトで認識できないタイプのファイルを受け取れるようにする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは。モバイルアプリサービス部の平屋です。

本記事では、Info.plistにカスタムUTIを追加し、iOSがデフォルトで認識できないタイプのファイルを受け取れるようにする方法を紹介します。

検証環境

  • Xcode Version 8.2.1
  • iPhone 6s, iOS 10.2.1

目次

  • カスタムUTIを追加
  • Document Typesを追加
  • AppDelegateにメソッドを追加
  • 動作確認

カスタムUTIを追加

カスタムUTIを追加したいTARGETを開き、Infoを選択します。

ios-adding-a-custom-uti-1

「Exported UTIs」を展開し、「Description」「Identifier」「Conforms To」を入力します。

入力する内容 参考
Description UTIの説明
Identifier UTIの識別子
Conforms To どのUTIを継承するか Uniform Type Identifiers Reference

ios-adding-a-custom-uti-2

「Conforms To」のすぐ下の「Additional exported UTI properties」を展開し、「Click here to ...」と書かれている部分をクリックします。

ios-adding-a-custom-uti-3

UTIのプロパティを入力できるようになるので、以下の値を設定します。

  • UTTypeTagSpecificationを追加し、TypeをDictionaryにする
  • Dictionaryの要素を1つ追加し、名前をpublic.filename-extensionに、TypeをArrayにする
  • Arrayに要素を1つ追加し、値に拡張子を設定する

ios-adding-a-custom-uti-4

カスタムUTI追加の作業は以上で完了です。

Info.plistをソースコード表示すると、以下の値が追加されていることを確認できます。

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.data</string>
        </array>
        <key>UTTypeDescription</key>
        <string>Custom File</string>
        <key>UTTypeIdentifier</key>
        <string>com.example.document.custom</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <array>
                <string>custom</string>
            </array>
        </dict>
    </dict>
</array>

Document Typesを追加

「Document Types」を展開し、「Name」「Types」を入力します。

そして、カスタムUTIの場合と同じ要領で、「Additional document type properties」に「CFBundleTypeRole」と「LSHandlerRank」を追加します。

キー 定義 設定できる値
CFBundleTypeRole ドキュメントタイプに対するアプリの役割 Editor, Viewer, None
LSHandlerRank ドキュメントタイプをどの程度サポートしているか Owner(当該ファイルを作成可能), Alternate(閲覧可能), None(扱えないがドロップは可能), Default(扱えない)

ios-adding-a-custom-uti-5

Info.plistをソースコード表示すると、以下の値が追加されていることを確認できます。

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeIconFiles</key>
        <array/>
        <key>CFBundleTypeName</key>
        <string>Custom File</string>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSHandlerRank</key>
        <string>Owner</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.example.document.custom</string>
        </array>
    </dict>
</array>

AppDelegateにメソッドを追加

AppDelegateにapplication(_:open:options:)メソッドを追加すると、他のアプリが出力したファイルのURLを取得できます。

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    // ... 

    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        print("url: ", url)

        // ファイルを扱う処理
        // ... 

        return true
    }
}

動作確認

標準のメールアプリを使用して動作を確認してみます。

サンプルアプリが入ったデバイス宛に、カスタムタイプのファイルを添付したメールを送ります。

メールを開くと以下のように添付ファイルが表示されるのでタップします。

ios-adding-a-custom-uti-6

どのアプリで開くかを聞かれるので、サンプルアプリを選択します。

ios-adding-a-custom-uti-7

サンプルアプリが開きます。

ios-adding-a-custom-uti-8

サンプルアプリが出力するログを見ると、受け取ったURLのログを確認できました。

url:  file:///private/var/mobile/Containers/Data/Application/XXXXX/Documents/Inbox/sample.custom
extension:  custom

さいごに

本記事では、Info.plistにカスタムUTIを追加し、カスタムタイプのファイルを受け取れるようにする方法を紹介しました。

アプリで受け取りたいUTIがシステム側で定義されていない場合、public.dataなどの汎用的なUTIを使用するしかないと思っていたんですが、Technical Q&Aに今回紹介したやり方が載っていたので試してみました。

アプリ間のファイル連携実装の参考になれば幸いです!

今回解説したサンプルコードは以下のリポジトリで公開していますのであわせてご覧ください!

参考資料