App Center ビルドスクリプト
前回の記事でApp Centerを使ってPushのタイミングで自動ビルド(releaseビルド)まで行いました.
しかし,Syncfusionのライセンスキーをコード内に記述していないため,アプリ起動後に何も表示されずにアプリを利用できませんでした.
ソースコードに直接記述すれば動きはしますが,そのままGitHubなどにPushしてしまうとライセンスキーが公開されてしまうリスクが生じます.
ライセンスキーやDBへの接続文字列,APIキーなどの機密情報はソースコード内に記述したくはありません.
モバイルアプリ開発における解決方法の1つは,App Centerでビルドが実行される前にこれらの機密情報をソースコードに差し込む処理を自動で行われるようにする,というものです.
例えば,Covid19Radarであれば,settings.json
ファイルにこれらの情報をまとめて記述しておき,実行時に取り出すようになっていますが,ソースコード上では以下のように実際のキーは記述されていません.APP_VERSION
やAPI_SECRET
,ANDROID_SAFETYNETKEY
といった部分がそれです.
{ "appVersion": "APP_VERSION", "apiSecret": "API_SECRET", "apiUrlBase": "https://API_URL_BASE/api", "supportedRegions": "440", "blobStorageContainerName": "c19r", "androidSafetyNetApiKey": "ANDROID_SAFETYNETKEY", "cdnUrlBase": "https://CDN_URL_BASE/", "licenseUrl": "https://covid19radarjpnprod.z11.web.core.windows.net/license.html", "appStoreUrl": "https://itunes.apple.com/jp/app/id1516764458?mt=8", "googlePlayUrl": "https://play.google.com/store/apps/details?id=jp.go.mhlw.covid19radar", "supportEmail": "SUPPORT_EMAIL" }
また,TurnipTracker(あつまれ動物の森のカブ情報をプレーヤー間で共有するためのアプリ)ではApp.xaml.cs
ファイル内にまとめられています.
public const string GetFriendsKey = "AC_GetFriendsKey"; public const string GetFriendRequestsKey = "AC_GetFriendRequestsKey"; public const string GetFriendRequestCountKey = "AC_GetFriendRequestCountKey"; public const string PostRemoveFriendRequestKey = "AC_PostRemoveFriendRequestKey"; public const string PostApproveFriendRequestKey = "AC_PostApproveFriendRequestKey"; public const string DeleteRemoveFriendKey = "AC_DeleteRemoveFriendKey"; public const string PostSubmitFriendRequestKey = "AC_PostSubmitFriendRequestKey"; public const string PutUpdateProfileKey = "AC_PutUpdateProfileKey"; public const string PutUpdateTurnipPricesKey = "AC_PutUpdateTurnipPricesKey"; public const string PostCreateProfileKey = "AC_PostCreateProfileKey"; public static bool IsStore => "AC_IsStore" == "true" ? true : false; const string AppCenteriOS = "AC_IOS"; const string AppCenterAndroid = "AC_ANDROID"; const string AppCenterUWP = "AC_UWP"; const string SyncFusionKey = "AC_SYNC";
このように,ソースコードでは実際の機密情報を記述せずに,「置換の目印となる文字列」を記述しておき,App Centerでビルド前にこれらの文字列を機密情報に置換するという方法をとっています.
App Centerではこのようにビルド前(後)などに何らかの処理を行うスクリプトを実行することができます.
こちらの動画はTurnipTrackerの実装についてJames Montemagnoさんが紹介しているものですが,その46分39秒あたりでスクリプトを使った仕組みについて触れています.
長くなりましたが,今回はSyncfusionのライセンスキーをビルドスクリプトを使ってビルド時に差し込む方法についてです.
Syncfusionのライセンスキーの取得についてはSyncfusion公式サイトや以前の記事が参考になるかと思います.
JSONファイルの読み込み
やり方はなんでも良いですが,基本的には対象のJSONファイル(appsettings.jsonなど)をEmbedded resource
に設定して,Assemblyから文字列(もしくはstream)として読み込むのが簡単かと思います.
例えばCovid19Radarだと以下のように読み込んでいます.
そして読み込んだJSONをパースして必要な情報を取得していくといった感じです.
var assembly = Assembly.GetExecutingAssembly(); using var file = assembly.GetManifestResourceStream("Covid19Radar.settings.json"); using var sr = new StreamReader(file); var json = sr.ReadToEnd(); var j = JObject.Parse(json); AppVersion = j.Value<string>("appVersion"); LicenseUrl = j.Value<string>("licenseUrl"); AppStoreUrl = j.Value<string>("appStoreUrl"); GooglePlayUrl = j.Value<string>("googlePlayUrl"); ApiUrlBase = j.Value<string>("apiUrlBase"); ApiSecret = j.Value<string>("apiSecret"); CdnUrlBase = j.Value<string>("cdnUrlBase"); BlobStorageContainerName = j.Value<string>("blobStorageContainerName"); SupportedRegions = j.Value<string>("supportedRegions").ToUpperInvariant().Split(';', ',', ':'); AndroidSafetyNetApiKey = j.Value<string>("androidSafetyNetApiKey"); SupportEmail = j.Value<string>("supportEmail");
もしくはGeneric Hostを使ってASP.NET Coreのような設定,DIの仕組みを使う場合は以下のような方法でJSONの読み込みとデータの取得をすることもできます.
appsettings.jsonの編集
appsettings.jsonファイルを用意し,以下のようにします.
{ "SyncfusionLicenceKey": "SYNCFUSION_LICENCE_KEY" }
App Center側でこのSYNCFUSION_LICENCE_KEY
という文字列を本物のライセンスキーに置換するようにします.
念の為,"SyncfusionLicenceKey"をキーにして値を取得できるか確認してみます.ここではIConfiguration
を使った方法でやっています.
取得できています.
App Centerのビルドスクリプトの作成
次にApp Center側でビルド前に実行するスクリプトを作成します.
ビルド前後の3つのタイミングで実行されるスクリプトをそれぞれ作成してリポジトリに含んでおくことで,App Centerでのビルド時にそれらが実行されます.
以下のタイミングでそれぞれ実行されます.
Post-clone(cloneの後) :
appcenter-post-clone.sh
-> リポジトリがcloneされた直後.Pre-build(ビルド前) :
appcenter-pre-build.sh
-> ビルドの直前.Post-build(ビルド後) :
appcenter-post-build.sh
->ビルドの直後.
これらのスクリプトは用意されているビルトインの変数だけでなく,任意の環境変数を作成して利用することができたり,基本的には何でもできます.
これらのファイルをソリューション,プロジェクトのどこに置くのかというと,ソリューションファイル(sln)やプロジェクトファイル(csproj)と同じ階層ということです.
Place the scripts with the format specified below next to the project-level (.xcodeproj, .csproj, .sln, or package.json) file or module-level (build.gradle) file that you've selected in the build configuration and we'll run them as custom build steps.
Androidプロジェクトの直下にappcenter-post-clone.sh
を配置しました.
TurnipTrackerのビルドスクリプトを参考にして以下のように一箇所だけ置換するスクリプトを書きました.
#! /usr/bin/env bash echo "Variables:" APP_SETTINGS_FILE=$BUILD_REPOSITORY_LOCALPATH/XFMyDecode2020/XFMyDecode2020/appsettings.json sed -i '' "s|SYNCFUSION_LICENCE_KEY|$SYNCFUSION_LICENCE_KEY|g" $APP_SETTINGS_FILE # print out for reference cat $APP_SETTINGS_FILE
$BUILD_REPOSITORY_LOCALPATH
はビルトインの環境変数(?)なのでしょうか,どうやらこのリポジトリのルートフォルダのパスを表すようです.
sed
コマンドで,指定したファイル(appsettings.json)内のSYNCFUSION_LICENCE_KEY
という文字列を環境変数SYNCFUSION_LICENCE_KEY
の値で置換する,という内容です.
あと,確認のために置換後にappsettings.jsonの内容を出力するようにしてあります.
App Centerに環境変数を追加する
App Centerを開き,以下のようにメニューのBuild
を開きます.
右上に🔧のようなアイコンがあるので,これをクリックすると,ビルドの設定画面が開きます.
ここで,Environment variales
をOnにして,SYNCFUSION_LICENCE_KEY
をキー,Syncfusionのライセンスキーを値とするペアを登録します.
Save
ボタンを押して変更を保存します.
ちなみにこの時点でBuild scripts
はNone
になっています.まだPushしてないので.
それではここまでの変更をGitHubにプッシュします.
プッシュの最中にビルドの設定画面を開くと,Build scripts
にPost-clone
が表示されていました.ビルドスクリプトは認識されたようです.
ビルドは成功しましたが,ビルドスクリプトは実行されませんでした.
どうやら,
- ビルドスクリプトを追加
- GitHubへPush
- App CenterがGitHubからリポジトリをclone
- ビルドスクリプトも認識されている
- でも,ビルドスクリプト認識後に設定が「保存されていない」
- ビルドスクリプトがない設定でビルドされる
ということのようです.
このように,ビルドスクリプトを追加してpushした後,App Center側で設定を「保存」しなおす必要がありました.
なので,ビルドスクリプト追加後の1回目のビルドはすぐにキャンセルしてしまえばよいと思います.