Skip to content

update build.yml

update build.yml #18

Workflow file for this run

name: Build Signed Android APK/AAB
on:
workflow_dispatch:
inputs:
build_type:
description: 'Build type'
required: true
default: 'release'
type: choice
options:
- debug
- release
push:
tags:
- 'v*.*.*'
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: npm install --legacy-peer-deps
- name: Expo Prebuild
run: npx expo prebuild --platform android --clean

Check failure on line 43 in .github/workflows/build.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/build.yml

Invalid workflow file

You have an error in your yaml syntax on line 43
- name: Setup Gradle cache
uses: gradle/actions/setup-gradle@v4 # or latest version
with:
gradle-home-cache-cleanup: true
- name: Decode Keystore
run: |
mkdir -p android/app
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/release.keystore
ls -lh android/app/release.keystore
echo "✅ Keystore decoded"
- name: Setup signing in gradle.properties
run: |
echo "📝 Setting up gradle.properties..."
cat >> android/gradle.properties << EOF
MYAPP_RELEASE_STORE_FILE=release.keystore
MYAPP_RELEASE_KEY_ALIAS=${{ secrets.KEY_ALIAS }}
MYAPP_RELEASE_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}
MYAPP_RELEASE_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}
EOF
echo "✅ gradle.properties configured"
echo ""
echo "📋 Verification (with secrets masked):"
cat android/gradle.properties | grep MYAPP_RELEASE_STORE_FILE
echo "MYAPP_RELEASE_KEY_ALIAS=***"
echo "MYAPP_RELEASE_STORE_PASSWORD=***"
echo "MYAPP_RELEASE_KEY_PASSWORD=***"
- name: Configure build.gradle for signing
run: |
BUILD_GRADLE="android/app/build.gradle"
echo "📝 Configuring signing..."
# Create backup
cp "$BUILD_GRADLE" "${BUILD_GRADLE}.backup"
# Step 1: Comment out Expo's debug signing in release buildType
sed -i 's/signingConfig signingConfigs\.debug/\/\/ signingConfig signingConfigs.debug (disabled)/g' "$BUILD_GRADLE"
# Step 2: Create signing config block with proper property syntax
{
echo ""
echo " signingConfigs {"
echo " release {"
echo " storeFile file('release.keystore')"
echo " storePassword project.property('MYAPP_RELEASE_STORE_PASSWORD')"
echo " keyAlias project.property('MYAPP_RELEASE_KEY_ALIAS')"
echo " keyPassword project.property('MYAPP_RELEASE_KEY_PASSWORD')"
echo " }"
echo " }"
} > /tmp/signing_block.gradle
# Step 3: Insert signing config after defaultConfig
LINE_NUM=$(grep -n "^ }$" "$BUILD_GRADLE" | head -1 | cut -d: -f1)
if [ -n "$LINE_NUM" ]; then
head -n "$LINE_NUM" "$BUILD_GRADLE" > "${BUILD_GRADLE}.tmp"
cat /tmp/signing_block.gradle >> "${BUILD_GRADLE}.tmp"
tail -n +$((LINE_NUM + 1)) "$BUILD_GRADLE" >> "${BUILD_GRADLE}.tmp"
mv "${BUILD_GRADLE}.tmp" "$BUILD_GRADLE"
echo "✅ Signing config inserted"
fi
# Step 4: Add signingConfig to release buildType
sed -i '/buildTypes {/,/release {/ { /release {/ a\ signingConfig signingConfigs.release
}' "$BUILD_GRADLE"
echo "✅ Signing configuration complete"
echo ""
echo "📋 Final signing configuration:"
grep -A 8 "signingConfigs {" "$BUILD_GRADLE" | head -10
- name: Make gradlew executable
run: chmod +x android/gradlew
- name: Clean previous builds
run: cd android && ./gradlew clean
- name: Verify gradle.properties before build
run: |
echo "📋 Checking gradle.properties..."
cat android/gradle.properties | grep MYAPP_ || echo "⚠️ Properties not found in gradle.properties"
echo ""
echo "📋 Checking if keystore exists..."
ls -lh android/app/release.keystore || echo "❌ Keystore not found!"
echo ""
echo "📋 Testing property access..."
cd android
./gradlew properties | grep MYAPP_ || echo "⚠️ Gradle cannot see MYAPP properties"
- name: Build Signed APK with explicit signing
run: |
cd android
echo "🔨 Building with signing..."
./gradlew assembleRelease \
-PMYAPP_RELEASE_STORE_FILE=release.keystore \
-PMYAPP_RELEASE_KEY_ALIAS="${{ secrets.KEY_ALIAS }}" \
-PMYAPP_RELEASE_STORE_PASSWORD="${{ secrets.KEYSTORE_PASSWORD }}" \
-PMYAPP_RELEASE_KEY_PASSWORD="${{ secrets.KEY_PASSWORD }}" \
--no-daemon \
--stacktrace \
--info 2>&1 | tee build.log
echo ""
echo "📋 Checking build log for signing..."
if grep -i "signing" build.log | grep -i "release"; then
echo "✅ Signing configuration was used"
else
echo "⚠️ Warning: No signing activity detected"
fi
- name: Build Signed AAB with explicit signing
run: |
cd android
./gradlew bundleRelease \
-PMYAPP_RELEASE_STORE_FILE=release.keystore \
-PMYAPP_RELEASE_KEY_ALIAS="${{ secrets.KEY_ALIAS }}" \
-PMYAPP_RELEASE_STORE_PASSWORD="${{ secrets.KEYSTORE_PASSWORD }}" \
-PMYAPP_RELEASE_KEY_PASSWORD="${{ secrets.KEY_PASSWORD }}" \
--no-daemon \
--stacktrace
- name: Verify APK signature
run: |
APK_PATH=$(find android/app/build/outputs/apk/release -name "*.apk" | head -1)
if [ ! -f "$APK_PATH" ]; then
echo "❌ APK not found!"
exit 1
fi
echo "📦 Verifying: $APK_PATH"
echo ""
# List all META-INF files
echo "=== META-INF Directory Contents ==="
unzip -l "$APK_PATH" | grep "META-INF/" || {
echo "❌ No META-INF directory found - APK is completely unsigned!"
exit 1
}
echo ""
# Find certificate file
CERT_FILE=$(unzip -l "$APK_PATH" | grep -o "META-INF/[A-Z0-9]*\.RSA" | head -1)
if [ -z "$CERT_FILE" ]; then
echo "❌ No RSA certificate found in APK!"
echo "This means the APK was not signed at all."
echo ""
echo "DEBUG: Checking build.gradle signing configuration..."
grep -A 15 "signingConfigs" android/app/build.gradle
exit 1
fi
echo "=== Certificate Information ==="
echo "Certificate file: $CERT_FILE"
unzip -p "$APK_PATH" "$CERT_FILE" | keytool -printcert
echo ""
echo "=== SHA1 Fingerprint ==="
SHA1=$(unzip -p "$APK_PATH" "$CERT_FILE" | keytool -printcert | grep "SHA1:" | awk '{print $2}')
echo "Current SHA1: $SHA1"
echo "Expected SHA1: 59:3D:24:BE:25:91:DF:54:6E:A8:06:17:DC:A1:73:81:3E:71:4C:A0"
if [ "$SHA1" == "59:3D:24:BE:25:91:DF:54:6E:A8:06:17:DC:A1:73:81:3E:71:4C:A0" ]; then
echo "✅ ✅ ✅ CORRECT KEYSTORE! ✅ ✅ ✅"
else
echo "⚠️ WARNING: This is a different keystore!"
echo "Google Play will reject this upload."
fi
- name: Upload APK artifact
uses: actions/upload-artifact@v4
with:
name: app-release-apk-${{ github.run_number }}
path: android/app/build/outputs/apk/release/*.apk
retention-days: 30
- name: Upload AAB artifact
uses: actions/upload-artifact@v4
with:
name: app-release-aab-${{ github.run_number }}
path: android/app/build/outputs/bundle/release/*.aab
retention-days: 30
- name: Upload debug files on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: debug-files-${{ github.run_number }}
path: |
android/build.log
android/app/build.gradle
android/app/build.gradle.backup
android/gradle.properties
retention-days: 7
- name: Cleanup sensitive files
if: always()
run: |
rm -f android/app/release.keystore
rm -f android/gradle.properties
echo "✅ Cleanup completed"