Flutter で環境を分けつつ iOS の AppExtension を利用する
ハマりどころが多かったので、備忘録として残しておく
AppExtension とは
iOSにおいて、アプリ外の部分で機能を提供したい場合に利用するもの
例
- ウィジェット
- 通知領域のカスタマイズ
- ...
AppExtension をアプリに追加する
該当する Extension のターゲットを追加する
例 Notification Service Extension の導入
Flutter の環境分けについて(Flutter3.7以上)
dart-define-from-file
オプションを利用し、 BundleId やアプリ名を環境ごとに切り替える事ができる
参考↓
AppExtension で環境毎の値を読み取る
AppExtension の BundleId はアプリ本体の BundleId をベースに作成する必要がある(環境ごとの値を読み取る必要がある)。が、単に AppExtension を追加しただけでは dart-define-from-file
の値を読み取れないため、追加で作業が必要になる
前提: dart-define-from-file
オプションがやっていること
-
ios/Flutter/Generated.xcconfig
に値を埋め込む - 1 の内容を
ios/Flutter/Release.xcconfig
及びios/Flutter/Debug.xcconfig
から参照する - 2 の xcconfig を Runner ターゲットに紐付ける ( Xcode の Project -> Configrations から確認できる)
ここまでは Flutter 側が勝手にやってくれているが、 AppExtension への紐付けは行ってくれないため自力で設定する。
- AppExtension 側のターゲット用に xcconfig を作成する (例:
ios/${ExtensionTarget}/Debug.xcconfig
) - 1 で作成した xcconfig から、
ios/Flutter
配下で生成された xcconfig を参照する
#include "../Flutter/Generated.xcconfig"
- 2 の xcconfig を AppExtension ターゲットに紐付ける ( Xcode の Project -> Configrations から設定する)
これにより、 dart-define-from-file
で渡した値も AppExtension 側で利用することができる
その他ハマりポイント
Flutter... とは関係なく AppExtension を利用するにあたって、いくつかハマった部分があったのでメモしておく
Profile の設定
ProvisioningProfile も AppExtension 用に別で作成するので、手動で Profile を設定する場合は ExportOptions に追記する必要がある
<key>provisioningProfiles</key>
<dict>
<key>com.example.app</key>
<string>{アプリ本体用の Profile 名}</string>
</dict>
<key>provisioningProfiles</key>
<dict>
<key>com.example.app</key>
<string>{アプリ本体用の Profile 名}</string>
<key>com.example.app.extension</key>
<string>{AppExtension 用の Profile 名}</string>
</dict>
Development Target の設定
AppExtension を作成する際、デフォルトだとアプリ本体の Development Target に追従しないため、後から手動で設定する必要がある。
例: アプリ本体の Development Target を 11.0 にしていても、新規作成した AppExtension の Development Target が 16.0 になっている
自分は Notification Service を使うために AppExtension を追加したが、上記の問題のせいで通知に画像を添付することができず、丸一日溶かした。(ビルド自体は通るため原因に気づきにくい)
おわりに
資料も少なくハマりどころも多かったため、今後この実装を行う人の助けになれば幸いです。
Discussion