2015年4月3日金曜日

iOS Extensionでデータを共有する

はじめに

これまで、Apple Watch、Action ExtensionとiOS Extension機能を実装する方法を説明してきました。今回もiOS Extensionに関する話です。

iOSアプリでデータを保存する際、基本的には1つのアプリの中だけでデータを共有することが出来ます。複数のアプリ間でデータを共有するためにはApp Groupsなどを利用しなければなりません。

Extensionはベースのアプリの拡張機能として提供されるにもかかわらず、ベースのアプリから独立した領域にストレージが割り当てられます。
ベースアプリとExtension間でデータを共有するためには複数のアプリのときと同様にApp Groupsを利用する必要があります。

今回は、NSUserDefautlsとplistファイルでデータを保存する場合を例にして、ベースのアプリとExtension間でデータを共有する方法を確認していきます。

対象

前回の記事(iOS Extensionの作り方講座(Action Extension編))を読んだ方向け
iOS開発アカウントを持っている人(App Groupsを利用するために必要です)
Xcode 6.2

作業内容

Extensionの例として、Action Extensionを利用します。
実際にExtensionの機能の実装はしません。
ベースのアプリで保存したデータが、Extensionからアクセスできることを確認します。

手順

作成手順を示します。
1. iPhoneアプリを作成する
2. Action Extensionを追加する
3. App Groupsを設定する
4. App Groupsを通じて、ベースアプリとExtension間でデータを共有できることを確認する

1. iPhoneアプリを作成する

File -> new -> ProjectからiOSアプリを作成します。
TemplateはiOS -> Application -> Single View Applicationとします。
Product NameはSDSampleとします。
言語はSwiftを選択します。

2. Action Extensionを追加する

File -> New -> TargetからTargetを追加します。
TemplateはiOS -> Application Extension -> Action Extensionとします。
名前はSDActionExtensionとします。
言語はSwiftです。
Action Typeはデフォルト値(Presents User Interface)のままです。
SchemeもActivateします。

3. App Groupsを設定する

Apple developer member centerのidentifiers設定にApp Groupsの項目があります。
ここからApp GroupsのIDを設定します。ID名はgroupから始まる必要があります。
名前を”group.com.hoge”にしたとして以下説明します。

SDSampleのTargetを選択してCapabilitiesタブからApp GroupsをONにします。
このとき、iOSの開発アカウントを尋ねられます。App Groupsを設定した開発アカウントを選択します。もしここでつまづくようであれば、Xcode -> Preferences -> Accounts項目に正しくアカウントが設定されているかどうかを確認しましょう。

作成したApp GroupsのIDが一覧に表示される筈なのでチェックを入れます。

次にSDActionExtensionのTargetについても同様にApp GroupsをONにしgroupのIDのチェックを入れます。

4. App Groupsを通じて、ベースアプリとExtension間でデータを共有できることを確認する
NSUserDefaultsのデータを共有する

SDSample/ViewController.swiftのviewDidLoad内に以下を追記します。

let groupName = "group.com.hoge"
let commonUserDefaults = NSUserDefaults(suiteName: groupName)!
// save
commonUserDefaults.setValue(1, forKey: "Sample")
// load
println(commonUserDefaults.valueForKey("Sample"))
println(commonUserDefaults.valueForKey("Extension"))

次に、SDActionExtension/ActionViewController.swiftのviewDidLoad内に以下を追記します。
既にviewDidLoad内にテンプレートコードが書かれていますが、Extensionとしての機能は今回利用しないので削除してしまって問題ありません。

let groupName = "group.com.hoge"
let commonUserDefaults = NSUserDefaults(suiteName: groupName)!
// save
commonUserDefaults.setValue(1, forKey: "Extension")
// load
println(commonUserDefaults.valueForKey("Sample"))
println(commonUserDefaults.valueForKey("Extension"))
}

SDSampleとSDActionExtensionは異なるストレージを保持するので、NSUserDefaults.standardUserDefaults()を使用した際には、互いに保存したデータにアクセスすることは出来ませんが、App Groupsを経由することで、データの共有が可能になります。

まずはSDSampleをTargetに設定しビルド&実行します。
次にSDActionExtensionをTargetに設定しビルド&実行します。
SDSampleを実行した際に”Sample”という名前のKeyに値を保存し、
SDActionExtensionの実行時に”Sample”のKeyが取得できることを確認しています。
ビルドする順番を逆にした場合も同様です。

plistファイルのデータを共有する

SDSample/ViewController.swiftのviewDidLoad内に以下を追記します。
(NSUserDefaultsに関するコードは消してしまいましょう)

let groupName = "group.com.hoge"
let fileManager = NSFileManager.defaultManager()
let samplePlistData = ["id": 1, "name": "Sample"] as NSDictionary

let groupPath = fileManager.containerURLForSecurityApplicationGroupIdentifier(groupName)!.path!
let samplePlistPath = groupPath.stringByAppendingPathComponent("sample.plist")
let extensionPlistPath = groupPath.stringByAppendingPathComponent("extension.plist")
// save
let saveData = NSKeyedArchiver.archivedDataWithRootObject(samplePlistData)
fileManager.createFileAtPath(samplePlistPath, contents: saveData, attributes: nil)

// load
if fileManager.fileExistsAtPath(samplePlistPath) {
    println("Exist: \(samplePlistPath)")
    let loadData = NSData(contentsOfFile: samplePlistPath)!
    let dic = NSKeyedUnarchiver.unarchiveObjectWithData(loadData) as NSDictionary
    println(dic)
}
if fileManager.fileExistsAtPath(extensionPlistPath) {
    println("Exist: \(extensionPlistPath)")
    let loadData = NSData(contentsOfFile: extensionPlistPath)!
    let dic = NSKeyedUnarchiver.unarchiveObjectWithData(loadData) as NSDictionary
    println(dic)
}

次に、SDActionExtension/ActionViewController.swiftのviewDidLoad内に以下を追記します。

let groupName = "group.com.hoge"
let fileManager = NSFileManager.defaultManager()
let extensionPlistData = ["id": 1, "name": "Extension"] as NSDictionary

let groupPath = fileManager.containerURLForSecurityApplicationGroupIdentifier(groupName)!.path!
let samplePlistPath = groupPath.stringByAppendingPathComponent("sample.plist")
let extensionPlistPath = groupPath.stringByAppendingPathComponent("extension.plist")
// save
let saveData = NSKeyedArchiver.archivedDataWithRootObject(extensionPlistData)
fileManager.createFileAtPath(extensionPlistPath, contents: saveData, attributes: nil)

// load
if fileManager.fileExistsAtPath(samplePlistPath) {
    println("Exist: \(samplePlistPath)")
    let loadData = NSData(contentsOfFile: samplePlistPath)!
    let dic = NSKeyedUnarchiver.unarchiveObjectWithData(loadData) as NSDictionary
    println(dic)
}
if fileManager.fileExistsAtPath(extensionPlistPath) {
    println("Exist: \(extensionPlistPath)")
    let loadData = NSData(contentsOfFile: extensionPlistPath)!
    let dic = NSKeyedUnarchiver.unarchiveObjectWithData(loadData) as NSDictionary
    println(dic)
}

NSUserDefaultsの場合と同様にビルドして確認してみましょう。
お互いのplistファイルにアクセスできる筈です。

0 件のコメント :

コメントを投稿