しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

【Swift】App Groupを使ってアプリ間でファイル共有

App Groupという仕組みを使って、アプリ同士のファイル共有を試してみました。
ちなみにApp Groupは自分が開発したアプリ間でないとデータ共有できないので注意が必要です。

下記事ではUserDefaultsの共有を試したので、今回はファイル共有を試してみようと思います。

www.cl9.info

テキストの共有

前回同様、まずはプロジェクトを2つ作成します。

f:id:llcc:20170912143059p:plain

次にそれぞれのプロジェクトのCapabilitiesからAppGroupをONにします。

f:id:llcc:20170912143107p:plain

有効化したら新しいApp Groupを作成します。
+ボタンから、AppGroupを追加してください。

f:id:llcc:20170912143113p:plain

これでAppGroupを使う準備が完了しました。
次は共有処理を書いていきます。

まずは片方のアプリからデータ保存します。
MyApp1のAppDelegate.swiftを以下のようにして下さい。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.myapp")?.appendingPathComponent("file_name") {
            try? "MyText".write(to: url, atomically: true, encoding: .utf8)
        }
        
        return true
    }
}

FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:)がApp Group用のURLを生成するメソッドです。
このURLに保存されたファイルは、他アプリでも取得する事ができます。

ちなみにこのメソッドに設定してないIDを入れるとnilが返ってきます。

FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.dummy") // → nil

アプリを実行してテキストを保存します。
続けて別アプリでファイルの読み込みができるかも調べてみます。

MyApp2のAppDelegate.swiftを以下のように修正して下さい。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.myapp")?.appendingPathComponent("file_name") {
            print(try? String(contentsOf: url))
        }
        
        return true
    }
}

実行すると、MyApp1で保存したテキストがMyApp2で取得できている事が分かります。

f:id:llcc:20170912143810p:plain

App Group用URLの中身

FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.myapp")ですが、パスは下のようなものになります。

file:///Users/xxxxx(ユーザー名)/Library/Developer/CoreSimulator/Devices/xxxxxx(ランダムな文字列)/data/Containers/Shared/AppGroup/xxxxxx(ランダムな文字列)/

普通にファイルを保存する時のフォルダは下URLです。

let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .allDomainsMask, true).first
// → /Users/xxxxx(ユーザー名)/Library/Developer/CoreSimulator/Devices/xxxxxx(ランダムな文字列)/data/Containers/Data/Application/xxxxxx(ランダムな文字列)/Documents

見比べてみるとContainers以下が違っている事が分かります。

data/Containers/Shared/AppGroup/xxxxxx(ランダムな文字列)/
data/Containers/Data/Application/xxxxxx(ランダムな文字列)/Documents

画像の共有

最後に画像の共有も試してみようと思います。

MyApp1のAppDelegateを下のように修正します。
テキストを保存した時と同じように、画像をストレージに保存します。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.clhs09")?.appendingPathComponent("image") {
            try? UIImageJPEGRepresentation(#imageLiteral(resourceName: "image"), 1.0)?.write(to: url)
        }
        
        return true
    }
}

次にMyApp2で画像の取得をします。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.clhs09")?.appendingPathComponent("image") {
            print(try? Data(contentsOf: url))
            
        }
        
        return true
    }
}

実行するとデータの取得に成功したことが分かります。

f:id:llcc:20170912145155p:plain