API key や SecretKey はハードコードダメ、git リポジトリでの管理もダメ、というわけでどうしたもんかと。
Android アプリ開発では、
のような仕組みで、システム環境変数をビルド時の変数に inject してくれる仕組みがあるのでいいですね。
Xamarin(というか .NET アプリケーション、MSBuild)のエコシステムには、そういう仕組みがなさそう(見つからなかった…)なので、自力でやるしかなさそうです。
ケース1:Google Maps の API キー
私は Xamarin.Forms.GoogleMaps というライブラリを開発していて、それの サンプルアプリケーションのコードも 公開しています。
Android や iOS で Google Maps を使うには、各々の API Key を入手して、ライブラリに設定する必要があるわけで、サンプルアプリケーションでそれをやっているのですが、API key をソースコードに直書きしてしまうと、それをうっかりコミットしてしまう危険があるし、これを Fork してくれる人にもそのような間違いを起こして欲しくありません。
STEP1:APIキーの定義を分離する
まずは APIキーを Static なクラスに追い出します。
// Variables.cs
public static class Variables
{
// https://developers.google.com/maps/documentation/android-api/signup
public const string GOOGLE_MAPS_ANDROID_API_KEY = "your_google_maps_android_api_v2_api_key";
// https://developers.google.com/maps/documentation/ios-sdk/start#step_4_get_an_api_key
public const string GOOGLE_MAPS_IOS_API_KEY = "your_google_maps_sdk_for_ios_api_key";
// https://msdn.microsoft.com/windows/uwp/maps-and-location/authentication-key
public const string BING_MAPS_UWP_API_KEY = "your_bing_maps_apikey";
}
static readonly
なプロパティにせず const
にしているのは、Android での API Key の指定が属性になっている からです。
STEP2:Variables.cs を .gitignore に追加する
Variables.cs を .gitignore に追加して、 git で管理しないようにします。
これで Variables.cs
に正しいAPIKeyを設定しても、コミット対象にならないので、間違えて API Key が流出することが防げます。
ただ、開発者がどんな Variables.cs
を用意すればいいか分からないので、Variables.cs
を Variables_sample.cs
という名前でコミットしておきます。もちろんこちらには正しい APIKey は記述しません。
これで、 README.md
などに、 「Variable_sample.cs
を Variable.cs
にリネームして、あなたのAPIKeyを設定して使ってください」とでも記述しておけば、大抵の開発者は理解できると思います。
STEP3:ビルドイベントで Variables_sample.cs
を Variables.cs
にコピーする
このままでもまあよいのですが、git clone してすぐビルドしてエラーになるのは悪いような良いような…。
Visual Studio、Xamarin Studio のビルドシステムには「ビルドイベント」という、ビルド前後などに任意のコマンドを実行する機能があるので、それを使って Variables_sample.cs
を Variables.cs
にコピーできます。
.csproj
に次のように追加します。全ソースは こちら 。
// XFGoogleMapSample.csproj
(前略)
</ProjectExtensions>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<PreBuildEvent>if not exist "$(ProjectDir)Variables.cs" copy "$(ProjectDir)Variables_sample.cs" "$(ProjectDir)Variables.cs" >nul</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
<PreBuildEvent>rsync -u "$(ProjectDir)Variables_sample.cs" "$(ProjectDir)Variables.cs"</PreBuildEvent>
</PropertyGroup>
</Project>
Windows と Mac 両方に対応しないといけないのが面倒な点1。
これは Condition=" '$(OS)' == 'Windows_NT' "
と Condition=" '$(OS)' != 'Windows_NT' "
で行っています。
しかも、Visual Studio でビルドイベントを設定すると Condition
が設定できないし、Xamarin Studio と Visual Studio で .csproj
に記述される書式が違うしで、結局 .csproj
に手書きするしかありませんでした。
次に、「Variables.cs
が既に存在していたらコピーしない」としたいが、
- Windows の
copy
コマンドは「上書きしない」オプションがないらしく、if not exist
を使う羽目に… - Mac の
cp
コマンドは「上書きしない」オプションはあるものの、上書きしない場合にエラーコードを返すらしく、それを MSBuild が検知してビルド失敗してしまうため、rsync
を使う羽目に…
と、それぞれ回りくどいことが必要なのが面倒な点2。
ここまでしてなんとか実現できました。
これで、「ソースを取得してすぐビルドできるけど、 Variables.cs
は git では管理されない」ようになりました。
ケース2:CI(継続的インテグレーション)への対応
Visual Studio Team Services(VSTS)などの CI サービスで自動ビルドすることを考えると、CIサービスの機能で Variables.cs
に、正しい APIKey を設定してやる必要があります。
冒頭で紹介した Android でのビルドの事例は、 gradle を使い、システム環境変数を AndroidManifest.xml に伝搬させています(manifestPlaceholders
という仕組みなのかな?)。
.NET のビルドシステムである MSBuild に同類の機能があることを確認できなかったので、CIサービスが提供する一般的な機能を使って実現するしかなさそうです。
- (本番用のAPIKeyが記述された)
Variables.cs
をコピーする -
Variables.cs
の内容を置換して本番用のAPIKeyを注入する
などです。
の例では、Perl を使って AndroidManifest.xml
のプレースホルダを置換してAPIKeyを差し込んでいるようです。
Visual Studio Mobile Center ではどうよ?
Connect(); で発表され、今はプレビュー版を誰でも試せるようになっている
にも、github などからソースを取得して自動ビルドできる機能があります。
が、今のところ、VSTS や他のCIサービスほど機能が用意されていない為か、ビルド前に任意のコマンドを実行させることはできません、今のところ(期待を込めて2回言った)。
求む!ベストプラクティス
というわけで、泥臭い方法をいくつか使わないと実現できないのがなんだかなあ、という感じです。
「こういうもの」なのか、「もっとスマートな方法がある」のか、情報をお待ちしております。
これと同じ事を Xamarin というか .NET アプリでやりたいよ~。MSBuild でできる? /【Android Studio】Api keyを始めとしたgit管理したくない定数を環境変数で管理する https://t.co/OPfOZSCjDS
— これがあめいの選択だよ (@amay077) 2016年12月16日
やばい
とりあえずこんなんでどうかな… https://t.co/2teIgC2NkQ https://t.co/zJjgsvvMdT
— Atsushi Eno (@atsushieno) 2016年12月20日