iAEONアプリのCI/CDのご紹介 〜Android編〜
この記事は、AEON Advent Calendar 2023の22日目です。
お疲れ様です!イオンスマートテクノロジーのiAEON開発チーム Nabeeeです。
今回は、「iAEONアプリでビルドやアプリの申請をどのような感じでやってるのか?」についてご紹介させて頂きます。
「そもそもiAEONって何?」という方は是非こちらの記事もご覧ください!
本日は〜Android編〜
ということでAndroidにフォーカスしてiAEONアプリのCI/CDフローをご紹介します。
弊社ではAzure DevOpsをどっぷり使っており、iAEONアプリのビルドやアプリの申請に関してもAzure Pipelinesを使ってます。ビルドやデプロイなどの処理にはfastlaneを使っています。
iAEONアプリのCI/CDにご興味があるマニアックな方は是非読み進めていただければと思います!
全体のフローはこんな感じです
iAEONアプリのCI/CD(ビルド・デプロイ処理)のフローはざっくりこんな感じになってます。
Azure Pipelinesでパイプラインを実行し、fastlaneを呼び出し、fastlaneでビルドやデプロイなど他サービスへの連携などの処理を行っています。
全体のフローはこちらです。すみません、ちょっとちっちゃいですね。。。
フロー毎にもうちょい詳しく説明します
次にシーケンスに記載の処理をもうちょい詳しく説明していきたいと思います。
今回はAndroidにフォーカスして、パイプライン実行からiAEONアプリをデプロイするまでのフローを説明します。
パイプライン実行
該当フローを抜粋するとこちらです。でかっ!
こちらが、Azure Pipelinesでパイプラインを実行するときのダイアログです。
パイプライン実行時に、以下のパラメータを設定しています。
iAEONアプリはIonic+Cordovaのハイブリッドアプリで実装されており、ソースコードの管理はiOSとAndroidで分かれていません。そのため、パイプラインはプラットフォーム毎に分けずに、1つのパイプラインでパラメータを指定して各プラットフォームのアプリをビルドできるようにしています。
ビルドする環境についても同様で、sit(テスト環境)/stg(ステージング環境)/prd(本番環境)とパイプライン実行時のパラメータで指定するようになっています。
ビルド情報を記録する
該当フローを抜粋するとこちらです。
iAEONでは複数の機能開発が並行して行われており、検証用アプリの配布なども頻繁に行われています。ビルドしたアプリが、何のためにビルドしたのか?、いつ時点の修正まで反映されているのか?などが分かるようにGoogleスプレッドシートにビルドの情報を記録しています。
Googleスプレッドシートへの書き込みはfastlaneで行い、google-drive-rubyというライブラリを使って実装しています。
Googleスプレッドシートへの書き込みイメージはこちらになります。
Androidビルド&デプロイ処理
該当フローを抜粋するとこちらです。
こちらのフローでは以下の処理を行います。apk(aab)を生成し、生成したapk(aab)をアップロードするまでを行います。
- ビルドの事前準備
- ビルド&デプロイ処理を呼び出し
- ビルド開始通知
- ビルド開始を記録
- apk or aabを生成
- apk or aabをアップロード
- デプロイ完了を記録
- デプロイ完了通知
1. ビルドの事前準備
ビルドマシンには、Microsoft-hosted agentsでホストされているmacOS 12を利用しています。
「ビルドの事前準備」では、以下の設定をビルドマシンに行います。
- 必要なソフトウェアのインストールやバージョン設定
- Azure Pipelines > secure filesに保存しているGoogle Play ConsoleやFirebase App DistributionにアクセスするためのAPI認証キーのダウンロード
具体的には、パイプラインの設定ファイル(YAMLファイル)で以下の手順を定義しています。
steps:
- task: JavaToolInstaller@0
inputs:
versionSpec: '11'
jdkArchitectureOption: 'x64'
jdkSourceOption: 'PreInstalled'
- task: NodeTool@0
inputs:
versionSpec: 18.x
# secure filesで管理しているAPI認証キーをダウンロード
# 本番ビルドの場合、Google Play Cosonleへアップロードする。
# テスト, ステージング環境の場合、Firebase App Distirubutionへアップロードする
- task: DownloadSecureFile@1
name: apiAuthKey
displayName: 'Download API Auth Key'
inputs:
${{ if eq(parameters.env, 'prd') }}:
secureFile: 'GooglePlayDeveloperAPI_auth_key.json'
${{ else }}:
secureFile: 'firebase-app-distribution_${{ parameters.env }}_auth_key.json'
# ionic, cordovaのインストール
- script: npm i -g @ionic/cli@6.20.9 cordova@11.1.0
displayName: 'Install Ionic CLI'
- task: UseRubyVersion@0
inputs:
versionSpec: '3.0'
# fastlaneなどをインストール
- script: bundle install --path ./vendor/bundle
displayName: 'Bundle vendor install'
2. ビルド&デプロイ処理を呼び出し
次に、パイプラインの設定ファイル(YAMLファイル)から、fastlaneで実装されているビルド&デプロイ処理を呼び出します。
以下のパラメータをfastlaneに渡して、ビルド&デプロイ処理を実行します。
- env: パイプライン実行時に設定したEnvironmentの値を設定
- build_type: debug or releaseを設定。基本的にはreleaseを設定
- api_key_path:
DownloadSecureFile
でAPI認証キーをダウンロードしたパスを設定 - app_version: パイプライン実行時に設定したアプリバージョンの値を設定
- build_number: パイプライン実行時に設定したビルド番号の値を設定
- ci_build_id: 実行したパイプライン番号を設定
具体的には、パイプラインの設定ファイル(YAMLファイル)で以下の手順を定義し、fastlaneを実行しています。
# Androidビルド&デプロイ処理を呼び出す
- script: bundle exec fastlane android upload env:${{ parameters.env }} build_type:${{ parameters.buildType }} api_key_path:'$(apiAuthKey.secureFilePath)' app_version:'${{ parameters.appVersion }}' build_number:'${{ parameters.buildNumber }}' ci_build_id:'$(Build.BuildId)'
displayName: 'fastlane: android upload ${{ parameters.env }} ${{ parameters.buildType }}'
3. ビルド開始通知
fastlaneのアクションslackを利用して、slackへのビルド開始通知を行っています。
こんな感じで、fastlaneだと簡単にslack通知が実装できるので便利ですよねー
slack(
slack_url: distribution_slack_url,
message: "*iAEONアプリのビルドを開始しました!*:fire:",
payload: {
"【対象OS】" => "#{os}",
"【バージョン】" => "#{app_version_info}",
"【リリースノート】" => "#{release_notes}",
"【アプリ配信先】" => "#{app_distribution_destination[:title]}",
"【ビルド詳細】" => "#{build_log_url(ci_build_id)}",
},
default_payloads: [:git_branch],
)
slackへのビルド開始通知のイメージはこちらになります。
4. ビルド開始を記録
Googleスプレッドシートに、ビルドが開始されたことを記録します。
Googleスプレッドシートへの書き込みは、google-drive-rubyというライブラリを使って実装しています。
Googleスプレッドシートへの書き込みイメージはこちらになります。
5. apk or aabを生成
パイプライン実行時に設定した環境によって、apkとaabのどちらかを生成します。
ionic cordova buildを利用し、apk or aabを生成しています。
- sit(テスト環境)、stg(ステージング環境)の場合、
apk
を生成
# apk生成
# debugビルド
ionic cordova build android --debug -- -- --packageType=apk --keystore=./debug.keystore --alias=androiddebugkey
# releaseビルド
ionic cordova build android --prod --release -- -- --packageType=apk
- prd(本番環境)の場合、
aab
を生成
# aab生成
# debugビルド
ionic cordova build android --debug -- -- --packageType=bundle --keystore=./debug.keystore --alias=androiddebugkey
# releaseビルド
ionic cordova build android --prod --release -- -- --packageType=bundle
また、署名はそれぞれ以下のコマンドを利用し、実行しています。
- apkの場合には、apksignerを利用する。以下のコマンドを実行し、apkの署名を行う。
# apk署名
apksigner sign --ks ./#{base_package_name}.jks --ks-pass pass:#{pass} #{apk_name}
apksigner verify -v #{apk_name}
- aabの場合には、jarsignerを利用する。以下のコマンドを実行し、aabの署名を行う。
# aab署名
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ./#{base_package_name}.jks #{aab_name} -storepass #{storepass} #{alias_name}
6. apk or aabをアップロード
生成したapk or aabはそれぞれ以下のプラットフォームにアップロードします。
- apkの場合は
Firebase App Distribution
にアップロードします。
firebase_app_distributionを利用し、アップロードしています。設定するパラメータもこちらに記載してあります。
Firebase App Distributionへのアップロードもfastlaneのプラグインが提供されているので、ほんと楽ですねー
# Firebase App Distributionへアップロード
firebase_app_distribution(
app: firebase_android_app_id,
apk_path: "#{Dir.pwd}/#{apk_name}",
service_credentials_file: options[:api_key_path],
groups: groups,
release_notes: "#{fb_release_notes}"
)
- aabの場合は
Google Play Console
にアップロードします。
upload_to_play_storeを利用し、アップロードしています。設定するパラメータもこちらに記載してあります。
track: "internal"
とrelease_status: "draft"
を指定しているので、Google Play Consoleの内部テストに下書き状態でアップロードされます。
# Google Play Consoleへアップロード
upload_to_play_store(
package_name: package_name,
track: "internal", # internal=内部テスト(The track of the application to use. The default available tracks are: production, beta, alpha, internal)
release_status: "draft", # draft=下書きの状態(Release status (used when uploading new apks/aabs) - valid values are completed, draft, halted, inProgress)
skip_upload_apk: true,
skip_upload_metadata: true,
skip_upload_changelogs: true,
skip_upload_images: true,
skip_upload_screenshots: true,
aab: "#{Dir.pwd}/#{aab_name}",
json_key: options[:api_key_path],
)
7. デプロイ完了を記録
4. ビルド開始を記録と基本的には同じ処理になります。
Googleスプレッドシートに、デプロイが完了したことを記録します。
8. デプロイ完了通知
3. ビルド開始通知と基本的には同じ処理になります。
image_url: "https://chart.apis.google.com/chart?chs=120x120&cht=qr&chl=#{app_distribution_destination[:url]}"
で、アプリインストールURLをQRコードで生成しています。QRコードをAndroid実機でスキャンしてもらうとテスターの方が該当バージョンのアプリをすぐにインストールすることができます。
slack(
slack_url: distribution_slack_url,
message: "*iAEONアプリを配信しました!*:rocket:\nテスト端末でQRコードを読み込んで、\n該当バージョンのアプリをインストールしてください。",
payload: {
"【対象OS】" => "#{os}",
"【バージョン】" => "#{app_version_info}",
"【リリースノート】" => "#{release_notes}",
"【アプリ配信先】" => "#{app_distribution_destination[:title]}#{app_distribution_destination[:finish_text]}\n#{app_distribution_destination[:url]}",
"【ビルド詳細】" => "#{build_log_url(ci_build_id)}",
},
default_payloads: [:git_branch],
attachment_properties: { # Optional, lets you specify any other properties available for attachments in the slack API (see https://api.slack.com/docs/attachments).
# This hash is deep merged with the existing properties set using the other properties above. This allows your own fields properties to be appended to the existing fields that were created using the `payload` property for instance.
image_url: "https://chart.apis.google.com/chart?chs=120x120&cht=qr&chl=#{app_distribution_destination[:url]}",
},
)
slackへのビルド終了通知のイメージはこちらになります。
おわりに
やりたいことが簡単に実装できるし、ドキュメントも豊富でコミュニティも活発で、fastlaneは本当に便利ですね!
今回の記事はiOSも書こうと思いましたが力尽きました。結構端折って書いているつもりでしたが長くなってしまいました。。。また機会があれば、iOSについても書ければと思います。
最期にイオンスマートテクノロジーではエンジニアを絶賛採⽤中です!
Discussion