From 1e8c19e5c95e11a34b140ef86f0d1fba80749c3f Mon Sep 17 00:00:00 2001 From: virtus Date: Fri, 10 Apr 2026 13:11:48 +0700 Subject: [PATCH] feat: Enhance Android release signing process with improved key alias resolution and error handling --- .gitea/workflows/build-aab.yml | 25 +++++++++++++++++++++--- .gitea/workflows/build-apk.yml | 25 +++++++++++++++++++++--- android/app/build.gradle.kts | 2 +- android/app/google-services.json | 33 ++++++++++++++++++++++++++++++-- android/gradle.properties | 1 + 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/build-aab.yml b/.gitea/workflows/build-aab.yml index 52228ca..3be92c6 100644 --- a/.gitea/workflows/build-aab.yml +++ b/.gitea/workflows/build-aab.yml @@ -84,7 +84,7 @@ jobs: - name: Prepare Android release signing run: | - if [ -n "${ANDROID_KEYSTORE_BASE64}" ] && [ -n "${ANDROID_KEYSTORE_PASSWORD}" ] && [ -n "${ANDROID_KEY_ALIAS}" ] && [ -n "${ANDROID_KEY_PASSWORD}" ]; then + if [ -n "${ANDROID_KEYSTORE_BASE64}" ] && [ -n "${ANDROID_KEYSTORE_PASSWORD}" ] && [ -n "${ANDROID_KEY_PASSWORD}" ]; then echo "Preparing release keystore from secrets" if ! python3 -c "import base64,os,re,sys; s=os.environ.get('ANDROID_KEYSTORE_BASE64',''); s=s.strip().strip(chr(34)).strip(chr(39)); s=s.replace('\\n',''); s=re.sub(r'^data:[^,]*,','',s); s=re.sub(r'\\s+','',s); s=s + ('=' * (-len(s) % 4)); (print('ANDROID_KEYSTORE_BASE64 is empty after normalization'), sys.exit(1)) if not s else None; d=base64.b64decode(s, validate=False); open('android/app/release.keystore','wb').write(d); print('Decoded keystore bytes:', len(d))" @@ -103,15 +103,34 @@ jobs: exit 1 fi + RESOLVED_KEY_ALIAS="${ANDROID_KEY_ALIAS}" + if [ -z "$RESOLVED_KEY_ALIAS" ]; then + RESOLVED_KEY_ALIAS=$(keytool -list -v -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" | awk -F': ' '/Alias name:/{print $2; exit}') + fi + + if [ -z "$RESOLVED_KEY_ALIAS" ]; then + echo "Could not resolve key alias from keystore" + exit 1 + fi + + if ! keytool -list -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" -alias "$RESOLVED_KEY_ALIAS" >/dev/null 2>&1; then + echo "Configured key alias does not exist in keystore: $RESOLVED_KEY_ALIAS" + keytool -list -v -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" | sed -n 's/^Alias name: /Available alias: /p' + exit 1 + fi + + echo "Using keystore alias: $RESOLVED_KEY_ALIAS" + { echo "storeFile=release.keystore" echo "storePassword=${ANDROID_KEYSTORE_PASSWORD}" - echo "keyAlias=${ANDROID_KEY_ALIAS}" + echo "keyAlias=${RESOLVED_KEY_ALIAS}" echo "keyPassword=${ANDROID_KEY_PASSWORD}" } > android/key.properties else echo "Release signing secrets are required for tagged release builds." - echo "Please configure: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD" + echo "Please configure: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_PASSWORD" + echo "Optional: ANDROID_KEY_ALIAS (auto-detected if omitted)" exit 1 fi diff --git a/.gitea/workflows/build-apk.yml b/.gitea/workflows/build-apk.yml index e1094e9..fd10398 100644 --- a/.gitea/workflows/build-apk.yml +++ b/.gitea/workflows/build-apk.yml @@ -84,7 +84,7 @@ jobs: - name: Prepare Android release signing run: | - if [ -n "${ANDROID_KEYSTORE_BASE64}" ] && [ -n "${ANDROID_KEYSTORE_PASSWORD}" ] && [ -n "${ANDROID_KEY_ALIAS}" ] && [ -n "${ANDROID_KEY_PASSWORD}" ]; then + if [ -n "${ANDROID_KEYSTORE_BASE64}" ] && [ -n "${ANDROID_KEYSTORE_PASSWORD}" ] && [ -n "${ANDROID_KEY_PASSWORD}" ]; then echo "Preparing release keystore from secrets" if ! python3 -c "import base64,os,re,sys; s=os.environ.get('ANDROID_KEYSTORE_BASE64',''); s=s.strip().strip(chr(34)).strip(chr(39)); s=s.replace('\\n',''); s=re.sub(r'^data:[^,]*,','',s); s=re.sub(r'\\s+','',s); s=s + ('=' * (-len(s) % 4)); (print('ANDROID_KEYSTORE_BASE64 is empty after normalization'), sys.exit(1)) if not s else None; d=base64.b64decode(s, validate=False); open('android/app/release.keystore','wb').write(d); print('Decoded keystore bytes:', len(d))" @@ -103,15 +103,34 @@ jobs: exit 1 fi + RESOLVED_KEY_ALIAS="${ANDROID_KEY_ALIAS}" + if [ -z "$RESOLVED_KEY_ALIAS" ]; then + RESOLVED_KEY_ALIAS=$(keytool -list -v -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" | awk -F': ' '/Alias name:/{print $2; exit}') + fi + + if [ -z "$RESOLVED_KEY_ALIAS" ]; then + echo "Could not resolve key alias from keystore" + exit 1 + fi + + if ! keytool -list -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" -alias "$RESOLVED_KEY_ALIAS" >/dev/null 2>&1; then + echo "Configured key alias does not exist in keystore: $RESOLVED_KEY_ALIAS" + keytool -list -v -keystore android/app/release.keystore -storepass "${ANDROID_KEYSTORE_PASSWORD}" | sed -n 's/^Alias name: /Available alias: /p' + exit 1 + fi + + echo "Using keystore alias: $RESOLVED_KEY_ALIAS" + { echo "storeFile=release.keystore" echo "storePassword=${ANDROID_KEYSTORE_PASSWORD}" - echo "keyAlias=${ANDROID_KEY_ALIAS}" + echo "keyAlias=${RESOLVED_KEY_ALIAS}" echo "keyPassword=${ANDROID_KEY_PASSWORD}" } > android/key.properties else echo "Release signing secrets are required for tagged release builds." - echo "Please configure: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD" + echo "Please configure: ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_PASSWORD" + echo "Optional: ANDROID_KEY_ALIAS (auto-detected if omitted)" exit 1 fi diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 3f6062d..38bb3c7 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -34,7 +34,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.reader_app" + applicationId = "dev.fevirtus.reader" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/google-services.json b/android/app/google-services.json index 95230ff..bcfb5fd 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -14,11 +14,11 @@ }, "oauth_client": [ { - "client_id": "308259929553-6k3q1g76skt3id4e2mk9k6pr5l7gdtju.apps.googleusercontent.com", + "client_id": "308259929553-7cdc4g8fe7os799trig7hk7ugkuansov.apps.googleusercontent.com", "client_type": 1, "android_info": { "package_name": "com.example.reader_app", - "certificate_hash": "fa21a3e6a319b71b2dd0ef9573b22046dba5d55c" + "certificate_hash": "f7e9f7ec9bafd1de69934b2c9b52ee491d73bad7" } }, { @@ -41,6 +41,35 @@ ] } } + }, + { + "client_info": { + "mobilesdk_app_id": "1:308259929553:android:14f7828b9b9ca9d31c34f0", + "android_client_info": { + "package_name": "dev.fevirtus.reader" + } + }, + "oauth_client": [ + { + "client_id": "308259929553-9oame596io3s4lcj9cdb5db6v3i6f6rk.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBibgTrvBWtJBL4PGeIyahBwRlYKcjQ47k" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "308259929553-9oame596io3s4lcj9cdb5db6v3i6f6rk.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } } ], "configuration_version": "1" diff --git a/android/gradle.properties b/android/gradle.properties index fbee1d8..5e2750f 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,2 +1,3 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +org.gradle.java.home=/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home android.useAndroidX=true