Azure DevOpsパイプラインでAPKをビルドする(Android SDK/Flutter/Firebase)
2025-08-06
azblob://2025/08/06/eyecatch/2025-08-06-azurepipeline-app-000_0.jpeg

はじめに


前回はiOSをビルドできるようにスクリプトを組んでいましたが、今回はDevOpsパイプラインでAPKをビルドできるようにしてみました。

新卒が入ってきて自分も、先輩エンジニアになりましたが、まだ実感がないです。

中高時代の後輩とはまた違うので、距離感が難しいですね。中高時代の後輩にはお母さんみたいと言われていました。

なんでも話せていたのか、過干渉だったのか?

過干渉されるのは、私は大嫌いなので、人にやっていたら最悪ですが、多分よくクッキーを作っていたからかな?と推測してます。

自分が後輩なら「ス○ラおばさん」とあだ名つけますね。(最低)

本題に行きます。

このブログでわかること


  • Flutterのバージョン管理にfvmを利用し、安定したFlutter SDK(3.24.3)を使ってAPKをビルド。
  • Android SDKやJDK17をCI環境上でインストールし、ビルドに必要な環境を自動構築。
  • keystoreやFirebaseの設定ファイルをAzure DevOpsのSecure Files機能から安全にダウンロードし、ビルドに利用
  • Flutterのビルド時にObfuscate(難読化)やsplit-per-abi(ABI毎にAPK分割)を行い、リリース用の最適化を実施。

上記の内容を含んでいます。

必要な前提と準備


  • Azure DevOpsの変数グループに、ビルドで使うAPIキーやドメインなどの環境変数を登録しておく必要があります。
  • Secure Filesに以下のファイルを登録しておく必要がある。

    • key.properties (署名用設定ファイル)
    • key.jks(Android署名用キーストア)
    • stg_firebase_options.dart、(Firebase設定ファイル)※
    • google-services.json(Firebase Android設定ファイル)※

    ※部分は開発で使用しているものに応じて変更してください。

  •  

ビルドの流れ


  • Flutter SDKはリポジトリからクローンして直接インストールしますが、fvmを使いFlutterバージョンを固定・切り替えしています。
  • Android SDKはコマンドラインツールから必要なビルドツールやプラットフォームをインストールしています。
  • Flutterのビルド時に--obfuscateや--split-debug-infoで難読化とデバッグ情報の分割を行い、リリースビルドとして最適化をしています。

セキュリティ・機密情報について


  • key.jksやkey.propertiesはアプリの署名に使う重要情報なので、絶対にリポジトリに直接含めず、Azure DevOpsのSecure Filesからのみ取得しています。
  • Firebase設定ファイルやAPIキーも機密情報として扱い、直接公開しないようにしています。

スクリプト例


trigger:
  - main
  - develop

pr:
  branches:
    include:
      - '*'

variables:
  # Azure DevOpsの変数グループから機密情報を読み込み
  - group: APP_RELEASE_STG

pool:
  vmImage: 'ubuntu-latest'

jobs:
  - job: BuildAndScan
    pool:
      vmImage: 'ubuntu-latest'

    steps:
      # --- Secure Files のダウンロード ---
      # Android署名に使うkey.propertiesをSecure Filesから取得
      - task: DownloadSecureFile@1
        name: downloadKeyProperties
        inputs:
          secureFile: 'key.properties'

      # Android署名用のキーストア(key.jks)をSecure Filesから取得
      - task: DownloadSecureFile@1
        name: downloadKeystore
        inputs:
          secureFile: 'key.jks'

      # Firebase用のDart設定ファイル(stg環境)をSecure Filesから取得
      - task: DownloadSecureFile@1
        name: downloadStgFirebaseOptions
        inputs:
          secureFile: 'stg_firebase_options.dart'

      # Firebase Android設定ファイル(google-services.json)をSecure Filesから取得
      - task: DownloadSecureFile@1
        name: downloadGoogleServices
        inputs:
          secureFile: 'google-services.json'

      # --- ファイルの配置 ---

      # FirebaseのDartファイルをlib/srcに配置(stg)
      - script: |
          mkdir -p lib/src
          cp $(downloadStgFirebaseOptions.secureFilePath) lib/src/stg_firebase_options.dart
        displayName: 'Copy stg_firebase_options.dart to source folder'

      # google-services.jsonをandroid/app/srcに配置
      - script: |
          mkdir -p android/app/src
          cp $(downloadGoogleServices.secureFilePath) android/app/src/google-services.json
        displayName: 'Copy google-services.json to android/app/src'

      # key.propertiesとkey.jksをandroidディレクトリに配置
      - script: |
          mkdir -p android
          cp $(downloadKeyProperties.secureFilePath) android/key.properties
          cp $(downloadKeystore.secureFilePath) android/key.jks
        displayName: 'Copy key.properties and keystore to android directory'

      # --- Flutter SDKのインストール ---
      - script: |
          # Flutterリポジトリをクローン(stableブランチ)
          git clone https://github.com/flutter/flutter.git  -b stable
          echo "##vso[task.setvariable variable=FLUTTER_HOME]$(pwd)/flutter"
          # PATHにFlutterのbinディレクトリを追加
          echo "##vso[task.prependpath]$(pwd)/flutter/bin"
        displayName: 'Install Flutter and set PATH'

      # fvm (Flutter Version Manager) のインストール
      - script: |
          flutter pub global activate fvm
          echo '##vso[task.prependpath]$(HOME)/.pub-cache/bin'
        displayName: 'Install fvm'

      # fvmでFlutter 3.24.3をインストールし利用設定
      - script: |
          fvm install 3.24.3
          fvm use 3.24.3
        displayName: 'Setup Flutter via fvm'

      # --- JDK 17のインストール ---
      - script: |
          sudo apt-get update
          sudo apt-get install -y openjdk-17-jdk
          echo "##vso[task.setvariable variable=JAVA_HOME]/usr/lib/jvm/java-17-openjdk-amd64"
        displayName: 'Install JDK 17'

      # --- Android SDKのインストールとセットアップ ---
      - script: |
          sudo apt-get update
          sudo apt-get install -y wget unzip
          export ANDROID_SDK_ROOT=$HOME/android-sdk
          mkdir -p $ANDROID_SDK_ROOT/cmdline-tools
          
          # Android SDKコマンドラインツールのダウンロードと展開
          wget https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip  -O cmdline-tools.zip   
          unzip -q cmdline-tools.zip -d $ANDROID_SDK_ROOT/cmdline-tools
          mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest
          rm cmdline-tools.zip
          
          # PATHにSDKツールを追加
          export PATH=$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools
          
          # ライセンスに同意
          yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT --licenses
          
          # 必要なSDKパッケージのインストール
          $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "platform-tools" "platforms;android-34" "build-tools;34.0.0"
        displayName: 'Install Android SDK & Build Tools'

      # --- Flutter APKのビルド ---
      - script: |
          export FLUTTER_HOME=$(FLUTTER_HOME)
          export ANDROID_SDK_ROOT=$HOME/android-sdk
          export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
          export PATH=$FLUTTER_HOME/bin:$PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools

          mkdir -p android
          cp $(downloadKeyProperties.secureFilePath) android/key.properties
          cp $(downloadKeystore.secureFilePath) android/key.jks

          # SDKライセンス再確認
          yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT --licenses

          # Flutter packagesの取得
          fvm flutter pub get

          # build_runnerによるコード生成(競合ファイルを削除)
          fvm flutter pub run build_runner build --delete-conflicting-outputs

          # Flutterのローカライズコード生成
          fvm flutter gen-l10n

          # APKビルド(flavor=stgで、難読化・ABI分割・デバッグ情報分割を実施)
          fvm flutter build apk --split-per-abi --obfuscate --split-debug-info=symbols/ --flavor=stg \
            --dart-define=CMS_BASE_DOMAIN=$(CMS_BASE_DOMAIN) \
            --dart-define=CMS_API_KEY=$(CMS_API_KEY) \
            --dart-define=MY_PORTAL_DOMAIN=$(MY_PORTAL_DOMAIN) \
            --dart-define=MY_API_DOMAIN=$(MY_API_DOMAIN) \
            --dart-define=MY_API_KEY=$(MY_API_KEY) \
            --verbose
        displayName: 'Build Flutter APK'

まとめ


Build Flutter APKの部分はだいぶ割愛していますが、記述方法は開発スタイル次第なので、こちらは適宜変更してください。

リリース目的というよりは、脆弱性診断を行うためのスクリプトを組んでいて、APKビルドは通過点であるため、現状はビルドまでの公開となっています。

次回は、脆弱性診断を行うために、MobSFをDockerコンテナで起動し、ビルドしたAPKを自動でアップロード・スキャンし、スキャン結果をJSON形式で取得してアーティファクトとして保存するまでの構成を書きます。

Github Actionを利用した記事はありましたが、DevOpsの記事が古かったので、誰かの参考になれば幸いです。