能登 要

札幌在住のiOSアプリ開発者。SwiftUI により分割されたデバイス間を縦横にやりとりできる考え方に転換しています。

iOSアプリ開発者。2009年のiPhoneアプリ開発開始時期から活動。開発言語のアップデートの中でSwiftUIおよび周辺技術に着目中。

Settings.BundleとSwifUI @AppStorage - SwiftUI100行チャレンジ⑥

端的にいうと

SwiftUI100行チャレンジ エピソード6。アプリ情報の永続化とUIの手軽さが魅力のSettings.BundleとSwiftUIとの組み合わせサンプル。SwiftUIからアプリ開発に取り組み始めた開発にとってはTipsとして機能するかもしれない。

2020/3/1 @AppStoreの更新タイミングについて追記。

発端

Settings.Bundleは欲しい的に調べ物をしても見つかりづらくなる程度にはクラシックなノウハウといえる。検索で調べても2014年の記事が出てくるくらいは定番すぎて内容として新鮮味がない。

[iOS] アプリの設定画面にバージョン表記と謝辞を自動で設定する | DevelopersIO

私自身Settings.Bundleについてすっかり忘れてしまったので備忘録とSwiftUIの新機能である@AppStorageと組み合わせて紹介およびサンプルコードを記載する。

1) 設定アプリのサードパーティ製設定

iOSの設定アプリにはサードパーティ製アプリ設定項目がある。サードパーティ製アプリ設定項目はアプリ毎に用意されているが存在しないアプリも見受けられる。

設定アプリ - サードパーティ製アプリ設定にアプリが表示される一般的な条件としてはOSが提供する機能へのアクセス許可の有無が決定している。セキュリティやプライバシーへのアクセスを設定アプリにまとめられている理由はセキュリティやプライバシーの制御を利用者が決定できるため(OSの一機能である)設定アプリ側に持たせているというAppleの判断があると思われる。

サードパーティ製アプリ設定にアプリが表示されるかつては一般的だった条件がある。Settings.Bundleと呼ばれるアプリ情報の永続化機能をUI付きでアプリ設定に追加することができる。

Settings.BundleはiOS SDK公開当初のiPhone上でのアプリがウィジットライクな扱いだった際には設定アプリにサードパーティ製のアプリ設定が含まれることは妥当だった。iPhoneが人気となるとアプリ数が膨張とアプリ毎の設定が複雑化した結果、利用者がアプリを制御しカスタマイズするという当初の意図を達成しているとは言えない状況にある。

余談だが設定アプリからのカスタマイズで限界があった利用者によるアプリのカスタマイズはSiri、Siri Shortcutといった、アプリから提案されるIntent(意図)を音声呼び出しやワークフロー化としてAppleから提案されるようになった。

Custom Intent を理解するキーワードIntent、User Activity、Donate - Siri Intent Extension

2) Settings.bundleとSwiftUI

用途が減ったSettings.bundleだが2020年代でもiOS SDKの重要な技術、UserDefaultと結びついている。UserDefaultはアプリ情報の永続化のための仕組みで巨大なデータを格納することはできないがiCloudとの同期やバックアップ対象になっているなどiOSアプリ開発ではよく使われる。

SwiftUIでもUserDefault機能が組み込まれている。@AppStorageはUserDefaultの値へのアクセスとObservedプログラミングでの利用しやすくなっている。

2020年において2008年からほぼ形を変えていないクラシックなノウハウであるSettings.bundleと2020年に発表されたSwiftUIの@AppStorageはUserDefaultで1つに繋がることになった。

Settings.bundle自体はiOSアプリのリソースの一部として組み込む。データそのものはplist(XML)構造を採用し、ローカライズに対応。

SettingsUserDefaultAppStorage

Settings.bundleの概要についてはAppleのドキュメントに記述してある。

Implementing an iOS Settings Bundle

記述できる要素はグループ、テキスト入力(TextField)、トグル(ToggleSwifth)、スライダー)(Slider)となっている。変更できる設定はUserDefaultに格納される。

3) サンプルコード

以下にサンプルコードを記述する。ソースコードはSwiftUI使用新規プロジェクトでContentView.swiftを置き換えれば済む形となっているが別途Settings.bundleリソースをプロジェクトに追加する必要がある。

Settings.bundleリソースの追加は、iOSプロジェクトにNew File(Command+N)で新しいファイルを追加する。検索欄にSettings Bundleを入力すると目的の形式がみつかるのでアイコンを選択しNextをタップする(2020年現在Xcode12確認)。

新規追加時にテンプレートに含まれるグループ、テキスト入力、スイッチ、スライダーのプリセット要素からスイッチの値をそのまま使用している。

実行の際はBuild後、設定アプリに含まれるアプリの設定項目についかされたスイッチを切り替え、アプリに切り替えて表示を比べて欲しい。画面下にToolbarの表示が切り替わりを確認できる。

struct ContentView: View {
@AppStorage(wrappedValue: false, "enabled_preference") var enabled_preference
var body: some View {
NavigationView {
Text("The toolbar is displayed in conjunction with the switch On/Off in the Settings application - Third Party Application Settings - Sample Application Settings.\n\nNote: The AppStorage value will revert to its initial value after each app transfer after the build, so build carefully.")
.padding()
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
if enabled_preference {
Spacer()
Button("Log") {
}
}
}
}
.navigationTitle("AppStorage example")
}
.navigationBarTitleDisplayMode(.inline)
}
}

4)Observerタイミング

@AppStoreのObserverはアプリがアクティブとなった時点で通知される。SwiftUI以前からあるUserDefaultでのKVO変更通知と変化はない。

UserDefaultの値変更監視は以下のBlogが参考になる。

【Swift】KVOでUserDefaultsの値の変更を監視する - Qiita

5) 考えられる用途

ユーザーアカウントを持たないシンプルアプリは設定アプリに設定を置くのはありかもしれない(Appleがシンプルなアプリを審査に通すかは別問題だが)。

設定アプリ内のサードパーティアプリ設定はiPhone利用者からしてみれば奥まった場所にある設定なのでいつもは利用しない機能(不具合ログ共有のUI)を出し分けるなどのユーザーサポートの一部として利用すると良いかもしれない。

6) 良い点/それほどでもない点

良い点は、アプリ設定がOSの設定に統合できること。OSの設定が含まれる設定アプリに他アプリの設定が含まれているのは自然に見える。悪い点は設定項目の自由度が乏しい点、Appleが想定したアプリ設定の用途をサードアプリが超えた点にある。

それほどでもない点1) 設定項目の柔軟性が乏しい OS機能の一部である設定アプリのため不正アクセスが含まれるダイナミックな動きが抑えられた構造となっており設定記述方法もSettings.bundleがplist(xml形式)のみとなっている。

それほどでもない点2) Appleが想定したアプリ設定の用途をサードアプリが超えた iPhoneが発売されてのち、iPhone普及の一因となったSNSアプリではアカウント毎に設定を持つためアプリと利用者が1対1の存在ではなくなった。

あまり利用されなくなったと言ってもAppleの基本技術であるplist形式をベースとしたテクノロジーなので今後も設定アプリの一機能としては残っていくと考えられる。

6) 今後の展開

以下雑感。

Appleはアプリ開発者にとってはモバイルアプリのプラットフォーマーとして度々仕様変更を繰り返してきたがそれでも基盤部分の互換性今回紹介したSettings.BundleのようにiPhoneアプリ開発可能となった2008年から互換性が維持され続けているものもある。

今後も大きな変化はない様に思えるがそうとも言えない。2019年ごろから動的な動きを担保しつつもビルド段階で整合性が確認する手法をSwift言語を介してAppleは提供してきた。SwiftUIやDiffable Data Sourceでがそれにあたる。

時代の変化に応じて進化するCollectionView ~Compositional LayoutsとDiffable Data Sources~ - Qiita

設定がOSに統合されている事自体は悪いことではない、設定アプリは各種設定を検索フィールドからの検索に対応するなどうまく機能すればユーザーの利便性につながる。

データ構造についても考えることがある。1990年代に主流だったXML技術を基盤としたRADツール(Storyboard, Interfacebuilder)が果たしてきた役割は大きいがデータ形式の冗長さ、データ整合性が不確か、multiplatform対応など課題がある。RADツールに関してはUI記述のためのドメイン特化言語(DSL)でありSwiftソースコードでもあるSwiftUIの提供を始めている。

他の要望に対してAppleの優先度は低いかもしれないがSettings.bundleをSwift言語を使用して置き換える可能性はあるかもしれない。