APIキーやサードパーティサービスのトークンなど、アプリに必要なシークレットを隠す従来の方法はご存知かもしれません。しかし最近では、SwiftPMを使ってアプリをモジュール化するアプローチがますます人気になっています。
例えば、Point-Freeにはこのトピックに関する優れた無料エピソードがありますし、Majid Jabrayilovは最近「Microapps architecture」シリーズを4回にわたって執筆しました(1、2、3、4)。始める際にはどちらもお勧めです。
また、公開のオープンソースライブラリでシークレットを隠したいケースもあるでしょう。例えば、サードパーティサービス連携のユニットテストで、ライブラリのユーザーは自分のトークンを提供しますが、テストは自分のトークンで実行したいという場合です。
これらの状況に共通するのは、手動でメンテナンスするPackage.swiftファイルをベースにしているということです。Xcodeがアプリプロジェクトに依存関係を追加する際に自動管理してくれるPackage.swiftではありません。アプリやプロジェクトは多くの小さなモジュールに分割され、対応する.xcodeprojファイルはなく、Xcodeが直接Package.swiftファイルを開くだけです。プロジェクトファイルは不要です。
これはまた、個々のモジュールに対してXcode内でビルド設定やビルドスクリプトを指定する方法がなく、すべてをPackage.swiftマニフェストファイル内で行う必要があるということも意味します。
このような機能はSwiftPMに順次追加されていますが(SE-303、SE-325、SE-332など)、.xcconfigファイルのようなXcode固有の機能がサポートされる兆しはありません。
では、シークレットがGitにコミットされないようにして、Gitプロバイダーやリポジトリにアクセスできる他の人にシークレットが漏洩しないようにするには、今日の時点でどうすればいいのでしょうか?
SwiftPMリソースとJSONDecoder
これに対する唯一の「正解」はないと思いますし、もっと賢い方法を考えつく人もいるでしょう。しかし私は物事をシンプルに保つのが好きですし、基本的な機能を使うのも好みです。なぜなら、よく知っている機能なので他の開発者もすぐに理解できると期待できますし、将来にわたって使えると確信できるからです。
私が使いたいアプローチは、Web開発で一般的な古典的な.envファイルアプローチです。ただし、カスタムフォーマットの.envファイルの代わりに、シークレットを入れた.jsonファイルを使います。JSONファイルは多くのiOS開発者にとって馴染みがあり、SwiftではJSONDecoderのおかげでパースのビルトインサポートがあります。ファイルやより一般的にリソースの読み込みも、Swift 5.3からSwiftPMでサポートされています(SE-271)。
シークレットをGitから隠す基本的なアイデアは以下の通りです。
キーのみで値のない
secrets.json.sampleファイルをGitにチェックインする開発者がそれを複製し、
.sample拡張子を削除して値を追加する.gitignoreでsecrets.jsonファイルを無視してチェックインされないようにするシークレットを読み取るための
Decodableに準拠したシンプルなstructを提供する
この記事の残りは、このアプローチを適用する手順ガイドです。私のオープンソースの翻訳ツールBartyCrouchのユニットテスト(2つのサードパーティ翻訳サービスと連携)を例として使います。
⚠️ このアプローチをユーザーに出荷するアプリターゲットに適用する場合、このNSHipster記事の
.xcconfigアプローチで説明されているのと同じ問題に遭遇する可能性があります。私の方法はシークレットをGitから隠すことにのみ役立ちます。ユーザーに出荷する場合は追加の難読化が必要です。
secrets.jsonリソースファイルの追加
まず、プロジェクトにsecrets.jsonファイルを追加しましょう。対応するsecrets.json.sampleとSecrets.swiftファイルもあるので、最初にSecretsフォルダを作成し、次にsecrets.jsonという名前の空ファイルを作成して、2つのキーを持つシンプルなJSON辞書構造を追加します。

これでCIもシークレットを漏洩させることなく安全にアクセスできるようにセットアップされました。

