繰り返しになりますが、AppExtensionと収容アプリケーションは別アプリ扱いです。
そのため、実際のユースケースでは、AppExtensionを使った後ですぐに収容アプリケーションを起動するとは限りません。AppExtensionでのコンテンツの保存を繰り返した後に、収容アプリケーションを起動するというケースも普通にあるでしょう。
そこで、もうひと工夫して、AppExtensionでUserDefaultに保存するときに、Contents型の配列でため込んで、収容アプリケーションで取得するときにまとめて取得するようにします。
好都合なことに、Codableの配列はCodableなのでそのままエンコード、デコードできます。
UserDefaultは上書き保存ですから、AppExtensionでデータを保存するときには、いったんデータを取得してから、その配列に新たにデータを追加してから保存し直します。
これでAppExtensionでどんどん追加保存できます。
/// コンテンツをApp Groupのユーザーデフォルトに保存
///
/// - Parameter content:
private func saveContent(content: String) {
guard let userDefaults = UserDefaults.init(suiteName: "group.jp.blowbend.ios.test.AwesomeApp") else {
print("userdefault: app group suite name is nil")
return
}
//保存済みのデータの取得
var contents: [Contents] = []
if let object = userDefaults.object(forKey: "user default key content") {
if let data: Data = object as? Data {
do {
contents = try JSONDecoder().decode([Contents].self, from: data)
} catch {
print("ActionViewController: JSONDecoder decode error")
}
}
}
let c = Contents(key: 123, text: content, date: Date())
contents.append(c) //新たにデータを追加
do {
let data = try JSONEncoder().encode(contents) //Data型に変換
userDefaults.set(data, forKey: "user default key content")
userDefaults.synchronize()
} catch {
print("userdefault: contents encode error!!")
}
}
収容アプリケーションでデータを取得するときは、単純に配列で受け取ります。貯まっていたデータを受け取ったら、removeObjectでデータを削除して空にします。
/// App Groupのユーザーデフォルトからコンテンツを取得
private func getContentFromAppGroup() {
guard let userDefaults = UserDefaults.init(suiteName: "group.jp.blowbend.ios.test.AwesomeApp") else {
print("userdefault: app group suite name is nil")
return
}
guard let content = userDefaults.object(forKey: "user default key content") ?? nil else {
print("userdefault: no content")
return
}
guard let data = content as? Data else {
print("userdefault: no data")
return
}
do {
let contents = try JSONDecoder().decode([Contents].self, from: data) //Content型の配列で取得
for c in contents {
print("c.key =\(c.key)")
print("c.text=\(c.text)")
print("c.date=\(c.date)")
}
} catch {
print("userdefault: JSONDecoder decode error")
}
userDefaults.removeObject(forKey: "user default key content") //すべてのデータの削除
}
どうでしょうか。これでAppExtensionの呼び出しごとに、(実は動いていない)収容アプリケーションにデータを送っているかのように見せられますね。このあたりは、その処理に合わせて色々工夫のしどころかもしれません。
以上で、使ってみた(App Extension編)は終わりです。おつかれさまでした。
こんな風にAppExtensionを使ったアプリをリリースしました。よろしくね。
「おまけのオマケ」
App Extensionを含むアプリをiTunes Storeにリリースするときは、ビルド番号を収容アプリケーションとApp Extensionとで揃える必要があります。
もし違うままアップロードすると、
WARNING ITMS-90473: "CFBundleVersion Mismatch. The CFBundleVersion value '2' of extension 'AwsomeApp.app/PlugIns/AwsomeAppShare.appex' does not match the CFBundleVersion value '1' of its containing iOS application 'AwsomeApp.app'."
というワーニングが出ます。ワーニングなので実害はないのかもしれませんが、まぁ、不用なトラブルは避けた方がいいですよね。お気を付けください。
♪♪♪
こちらもどうぞ。
使ってみた(App Extension編) その1
使ってみた(App Extension編) その2
使ってみた(App Extension編) その3
使ってみた(App Extension編) その4
使ってみた(App Extension編) その5