[iOS][Swift] アプリ間のファイル連携について

2016.08.08

今回はアプリ間でファイル連携する方法についてです。

この記事では、

Xcode 7.3.1
Swift 2.2
iOS 8.1以上

の環境を前提として記載してます。

ファイルを送る

ファイルを送るにはUIDocumentInteractionControllerを使います。
UIDocumentInteractionControllerは1ファイルしか送れないという制限がありますが、手軽に実装出来るのが特徴です。
受け取り側は自分で作成するか、Dropboxなどのたぶん何でも受け取れるアプリを用意すると検証が容易になると思います。

UIDocumentInteractionController

PNGファイルを送るサンプル

imageViewに表示されている画像をPNGファイルとして送る例です。
処理の内容としては、一度TemporaryDirectoryにtmp.pngという名前で保存し、UIDocumentInteractionControllerにそのURLを渡すだけです。

        // 送る対象の画像
        guard let image = imageView.image else {
            print("対象の画像が見つかりません")
            return
        }
        let data = UIImagePNGRepresentation(image)

        // ファイル一時保存してNSURLを取得
        let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("tmp.png")
        data?.writeToURL(url, atomically: true)

        controller = UIDocumentInteractionController.init(URL: url)

        if !(controller!.presentOpenInMenuFromRect(view.frame, inView: view, animated: true)) {
            print("ファイルに対応するアプリがありません")
        }

presentOpenInMenuFromRect()の戻り値はBoolで、送るファイルに対応するアプリが無い場合はfalseが返ってきて表示されません。

ファイルを受け取る

ファイルを受け取れるようにするには、TargetのInfoタブを選択し、Document Typesに受け取るファイルを設定します。 Typesに設定するUTI(Uniform Type Identifiers)を設定します。
UTIはUniform Type Identifiers Referenceに一覧が載っているので、ここから調べることができます。

一部を例として抜粋しました。

Identifier (Constant) Tags Comments
public.jpeg 'JPEG', .jpg, .jpeg, image/jpeg JPEG image.
public.png 'PNGf', .png, image/png PNG image
public.html 'HTML', .html, .htm, text/html, Apple HTML pasteboard type HTML text.
public.xml .xml, text/xml XML text.
com.apple.quicktime-movie 'MooV', .mov, .qt, video/quicktime QuickTime movie.
public.mpeg 'MPG ', 'MPEG', .mpg, .mpeg, .m75, .m15, video/mpg, video/mpeg, video/x-mpg, video/x-mpeg MPEG-1 or MPEG-2 content.
public.mpeg-4 'mpg4', .mp4, video/mp4, video/mp4v MPEG-4 content.
public.3gpp .3gp, .3gpp, '3gpp', video/3gpp, audio/3gpp 3GPP movie.
public.3gpp2 .3g2 , .3gp2 , '3gp2', video/3gpp2, audio/3gpp2 3GPP2 movie.
public.mp3 'MPG3', 'mpg3', 'Mp3 ', 'MP3 ', 'mp3!', 'MP3!', .mp3, audio/mpeg, audio/mpeg3, audio/mpg, audio/mp3, audio/x-mpeg, audio/x-mpeg3, audio/x-mpg, audio/x-mp3 MPEG-3 audio.
public.mpeg-4-audio 'M4A ', .m4a MPEG-4 audio.
com.apple.protected-​mpeg-4-audio 'M4P ', 'M4B ', .m4p, .m4b Protected MPEG-4 audio. (iTunes music store format)

public.dataを設定すれば色々なファイルを受け付けることができます。逆にpublic.jpegのように設定するとjpegファイルの場合のみ受け取ることが出来ます。また、UTIは複数設定出来ます。public.dataなどを設定すると、扱えないファイルまでも受け取ってしまうので、扱えるファイルのみを個別に記載する方が良いかもしれません。

イメージ図

受け取った後の実装

AppDelegate の openURL で受け取ります。

iOS8までは
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool

iOS9からは
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool
で処理を行います。

urlにそのファイルが保存されているパスが届くので、必要に応じて適宜実装をします。
下記の例では、受け取った後に拡張子のチェックを行い、TemporaryDirectoryに保存しています。

    func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

        if let ext = url.pathExtension?.lowercaseString {

            let tempFilePath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("\(NSUUID().UUIDString).\(ext)")

            do {
                try NSFileManager().copyItemAtURL(url, toURL: tempFilePath)
            } catch {
                print("ファイルのコピーが失敗")
            }

        } else {
            print("拡張子が取得出来ない")
        }

        return true
    }

さいごに

他にも、 [iOS 8] App Extension #6 – Embedded Framework と App Group を利用して Action Extension を実装するのように共有領域を使って連携する方法もあります。

また、標準アプリに対しての連携やライブラリにファイルの保存するなどの用途で使うならUIActivityViewControllerの方が最適です。
下記は画像を送った場合のUIActivityViewControllerの画面になります。

UIActivityViewController

UIDocumentInteractionControllerと比べるとSave ImageやCopy、Print ...etc が増えてます。

参考

UIDocumentInteractionControllerを使ったデータ共有|Toyship.org
[iOS] アプリ内で管理している画像を Instagram へ投稿する|Developers.IO