213 lines
7.9 KiB
YAML
213 lines
7.9 KiB
YAML
name: 'Flutter Build Android'
|
|
description: 'Configures Android keystore signing, builds release AAB/APK artifacts, and optionally deploys to Google Play Console and Shorebird.'
|
|
inputs:
|
|
working_directory:
|
|
description: 'Path to the Flutter app package directory (e.g., packages/hfw_flutter or .)'
|
|
required: false
|
|
default: '.'
|
|
build_aab:
|
|
description: 'Whether to build an Android App Bundle (.aab)'
|
|
required: false
|
|
default: 'true'
|
|
build_apk:
|
|
description: 'Whether to build a release APK (.apk)'
|
|
required: false
|
|
default: 'false'
|
|
build_args:
|
|
description: 'Extra arguments passed to flutter build appbundle / apk (e.g., --dart-define=...)'
|
|
required: false
|
|
default: ''
|
|
artifact_prefix:
|
|
description: 'Optional prefix for copied versioned artifacts in output_dir (e.g., hfw-android -> hfw-android-v1.0.0.apk)'
|
|
required: false
|
|
default: ''
|
|
output_dir:
|
|
description: 'Directory to copy versioned artifacts into when artifact_prefix is set'
|
|
required: false
|
|
default: 'artifacts'
|
|
keystore_base64:
|
|
description: 'Base64-encoded Android release keystore file'
|
|
required: false
|
|
default: ''
|
|
key_alias:
|
|
description: 'Android signing key alias'
|
|
required: false
|
|
default: ''
|
|
key_password:
|
|
description: 'Android signing key password'
|
|
required: false
|
|
default: ''
|
|
store_password:
|
|
description: 'Android keystore password'
|
|
required: false
|
|
default: ''
|
|
google_play_service_account_json:
|
|
description: 'Google Play service account JSON content for Play Store upload'
|
|
required: false
|
|
default: ''
|
|
google_play_service_account_file:
|
|
description: 'Fallback path to Google Play service account JSON file (relative to repo root)'
|
|
required: false
|
|
default: ''
|
|
google_play_track:
|
|
description: 'Google Play track to deploy to (internal, alpha, beta, production)'
|
|
required: false
|
|
default: 'beta'
|
|
google_play_status:
|
|
description: 'Google Play release status (completed, draft, inProgress, halted)'
|
|
required: false
|
|
default: 'completed'
|
|
google_play_script:
|
|
description: 'Path to the Dart Google Play upload script (relative to repo root)'
|
|
required: false
|
|
default: 'scripts/upload_play_store.dart'
|
|
shorebird_token:
|
|
description: 'Shorebird token for optional Shorebird release'
|
|
required: false
|
|
default: ''
|
|
shorebird_artifact:
|
|
description: 'Shorebird artifact type (apk or aab)'
|
|
required: false
|
|
default: 'apk'
|
|
|
|
outputs:
|
|
version:
|
|
description: 'Resolved package version from pubspec.yaml'
|
|
value: ${{ steps.build.outputs.version }}
|
|
aab_path:
|
|
description: 'Path to the built AAB file'
|
|
value: ${{ steps.build.outputs.aab_path }}
|
|
apk_path:
|
|
description: 'Path to the built APK file'
|
|
value: ${{ steps.build.outputs.apk_path }}
|
|
|
|
runs:
|
|
using: 'composite'
|
|
steps:
|
|
- name: Configure Android Signing Keystore
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
KEYSTORE_BASE64: ${{ inputs.keystore_base64 }}
|
|
KEY_ALIAS: ${{ inputs.key_alias }}
|
|
KEY_PASSWORD: ${{ inputs.key_password }}
|
|
STORE_PASSWORD: ${{ inputs.store_password }}
|
|
run: |
|
|
if [ -n "$KEYSTORE_BASE64" ]; then
|
|
echo "Decoding Android Keystore..."
|
|
mkdir -p "$WORK_DIR/android/app"
|
|
echo "$KEYSTORE_BASE64" | base64 --decode > "$WORK_DIR/android/app/release.keystore"
|
|
printf "storePassword=%s\nkeyPassword=%s\nkeyAlias=%s\nstoreFile=release.keystore\n" \
|
|
"$STORE_PASSWORD" "$KEY_PASSWORD" "$KEY_ALIAS" > "$WORK_DIR/android/key.properties"
|
|
echo "Configured $WORK_DIR/android/key.properties"
|
|
else
|
|
echo "Notice: keystore_base64 not configured. Building unsigned / default debug signing."
|
|
fi
|
|
|
|
- name: Build Android Release Artifacts
|
|
id: build
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
BUILD_AAB: ${{ inputs.build_aab }}
|
|
BUILD_APK: ${{ inputs.build_apk }}
|
|
BUILD_ARGS: ${{ inputs.build_args }}
|
|
ARTIFACT_PREFIX: ${{ inputs.artifact_prefix }}
|
|
OUTPUT_DIR: ${{ inputs.output_dir }}
|
|
run: |
|
|
ROOT_DIR="$(pwd)"
|
|
VERSION=$(grep '^version: ' "$WORK_DIR/pubspec.yaml" | head -n 1 | cut -d ' ' -f 2 | tr -d '\r')
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
|
|
cd "$WORK_DIR"
|
|
if [ "$BUILD_AAB" = "true" ]; then
|
|
echo "Building Android App Bundle (AAB)..."
|
|
# shellcheck disable=SC2086
|
|
flutter build appbundle --release $BUILD_ARGS
|
|
fi
|
|
|
|
if [ "$BUILD_APK" = "true" ]; then
|
|
echo "Building Android APK..."
|
|
# shellcheck disable=SC2086
|
|
flutter build apk --release $BUILD_ARGS
|
|
fi
|
|
cd "$ROOT_DIR"
|
|
|
|
AAB_REL="$WORK_DIR/build/app/outputs/bundle/release/app-release.aab"
|
|
APK_REL="$WORK_DIR/build/app/outputs/flutter-apk/app-release.apk"
|
|
AAB_REL="${AAB_REL#./}"
|
|
APK_REL="${APK_REL#./}"
|
|
|
|
if [ -n "$ARTIFACT_PREFIX" ]; then
|
|
mkdir -p "$OUTPUT_DIR"
|
|
if [ -f "$AAB_REL" ]; then
|
|
cp "$AAB_REL" "$OUTPUT_DIR/${ARTIFACT_PREFIX}-v${VERSION}.aab"
|
|
AAB_OUT="$OUTPUT_DIR/${ARTIFACT_PREFIX}-v${VERSION}.aab"
|
|
fi
|
|
if [ -f "$APK_REL" ]; then
|
|
cp "$APK_REL" "$OUTPUT_DIR/${ARTIFACT_PREFIX}-v${VERSION}.apk"
|
|
APK_OUT="$OUTPUT_DIR/${ARTIFACT_PREFIX}-v${VERSION}.apk"
|
|
fi
|
|
echo "Collected Android artifacts for version $VERSION in $OUTPUT_DIR"
|
|
fi
|
|
|
|
echo "aab_path=${AAB_OUT:-$AAB_REL}" >> "$GITHUB_OUTPUT"
|
|
echo "apk_path=${APK_OUT:-$APK_REL}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload AAB to Google Play Console
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
PLAY_STORE_JSON: ${{ inputs.google_play_service_account_json }}
|
|
PLAY_STORE_FILE: ${{ inputs.google_play_service_account_file }}
|
|
PLAY_TRACK: ${{ inputs.google_play_track }}
|
|
PLAY_STATUS: ${{ inputs.google_play_status }}
|
|
PLAY_SCRIPT: ${{ inputs.google_play_script }}
|
|
run: |
|
|
AAB_FILE="$WORK_DIR/build/app/outputs/bundle/release/app-release.aab"
|
|
AAB_FILE="${AAB_FILE#./}"
|
|
if [ ! -f "$AAB_FILE" ]; then
|
|
echo "No AAB file found at $AAB_FILE; skipping Google Play upload."
|
|
exit 0
|
|
fi
|
|
|
|
DEFAULT_SA_FILE="$WORK_DIR/android/app/google_play.json"
|
|
DEFAULT_SA_FILE="${DEFAULT_SA_FILE#./}"
|
|
SA_FILE="${PLAY_STORE_FILE:-$DEFAULT_SA_FILE}"
|
|
|
|
if [ -n "$PLAY_STORE_JSON" ] && [ -f "$PLAY_SCRIPT" ]; then
|
|
echo "Google Play service account secret detected. Uploading AAB to track '$PLAY_TRACK'..."
|
|
echo "$PLAY_STORE_JSON" > /tmp/google_play_service_account.json
|
|
dart "$PLAY_SCRIPT" \
|
|
--aab "$AAB_FILE" \
|
|
--service-account /tmp/google_play_service_account.json \
|
|
--track "$PLAY_TRACK" \
|
|
--status "$PLAY_STATUS"
|
|
rm -f /tmp/google_play_service_account.json
|
|
elif [ -f "$SA_FILE" ] && [ -f "$PLAY_SCRIPT" ]; then
|
|
echo "Using repository service account file ($SA_FILE) for Google Play upload to track '$PLAY_TRACK'..."
|
|
dart "$PLAY_SCRIPT" \
|
|
--aab "$AAB_FILE" \
|
|
--service-account "$SA_FILE" \
|
|
--track "$PLAY_TRACK" \
|
|
--status "$PLAY_STATUS"
|
|
else
|
|
echo "Skipping Google Play upload (credentials or upload script not configured)."
|
|
fi
|
|
|
|
- name: Release via Shorebird (Optional)
|
|
if: inputs.shorebird_token != ''
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
SHOREBIRD_TOKEN: ${{ inputs.shorebird_token }}
|
|
SHOREBIRD_ARTIFACT: ${{ inputs.shorebird_artifact }}
|
|
run: |
|
|
if [ -n "$SHOREBIRD_TOKEN" ]; then
|
|
ROOT_DIR="$(pwd)"
|
|
cd "$WORK_DIR"
|
|
flutter pub global activate shorebird_cli
|
|
shorebird release android --artifact="$SHOREBIRD_ARTIFACT"
|
|
cd "$ROOT_DIR"
|
|
fi
|