Skip to content

Commit db33704

Browse files
committed
update build.yml
1 parent 202e716 commit db33704

1 file changed

Lines changed: 67 additions & 200 deletions

File tree

.github/workflows/build.yml

Lines changed: 67 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,25 @@
1-
name: Build Signed Android APK/AAB
2-
3-
on:
4-
workflow_dispatch:
5-
inputs:
6-
build_type:
7-
description: "Build type"
8-
required: true
9-
default: "release"
10-
type: choice
11-
options:
12-
- debug
13-
- release
14-
push:
15-
tags:
16-
- "v*.*.*"
17-
181
jobs:
192
build-android:
203
runs-on: ubuntu-latest
21-
4+
225
steps:
236
- name: Checkout code
247
uses: actions/checkout@v4
258

269
- name: Set up Node.js
2710
uses: actions/setup-node@v4
2811
with:
29-
node-version: "20"
30-
cache: "npm"
12+
node-version: '20'
13+
cache: 'npm'
3114

3215
- name: Set up JDK 17
3316
uses: actions/setup-java@v4
3417
with:
35-
distribution: "temurin"
36-
java-version: "17"
18+
distribution: 'temurin'
19+
java-version: '17'
20+
21+
- name: Setup Android SDK
22+
uses: android-actions/setup-android@v3
3723

3824
- name: Install dependencies
3925
run: npm install --legacy-peer-deps
@@ -42,217 +28,98 @@ jobs:
4228
run: npx expo prebuild --platform android --clean
4329

4430
- name: Setup Gradle cache
45-
uses: gradle/actions/setup-gradle@v4
31+
uses: gradle/actions/setup-gradle@v3
4632
with:
4733
gradle-home-cache-cleanup: true
4834

4935
- name: Decode Keystore
5036
run: |
51-
mkdir -p android/app
52-
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/release.keystore
53-
ls -lh android/app/release.keystore
54-
echo "✅ Keystore decoded"
55-
56-
- name: Setup signing in gradle.properties
57-
run: |
58-
echo "📝 Setting up gradle.properties..."
59-
cat >> android/gradle.properties << EOF
60-
MYAPP_RELEASE_STORE_FILE=release.keystore
61-
MYAPP_RELEASE_KEY_ALIAS=${{ secrets.KEY_ALIAS }}
62-
MYAPP_RELEASE_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}
63-
MYAPP_RELEASE_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}
64-
EOF
65-
66-
echo "✅ gradle.properties configured"
67-
echo ""
68-
echo "📋 Verification (with secrets masked):"
69-
cat android/gradle.properties | grep MYAPP_RELEASE_STORE_FILE
70-
echo "MYAPP_RELEASE_KEY_ALIAS=***"
71-
echo "MYAPP_RELEASE_STORE_PASSWORD=***"
72-
echo "MYAPP_RELEASE_KEY_PASSWORD=***"
73-
74-
- name: Configure build.gradle for signing
75-
run: |
76-
BUILD_GRADLE="android/app/build.gradle"
77-
cp "$BUILD_GRADLE" "${BUILD_GRADLE}.backup"
78-
79-
echo "📝 Adding release signing config..."
80-
81-
# Add release signing config to signingConfigs block
82-
awk '
83-
/signingConfigs \{/ {
84-
print
85-
print " release {"
86-
print " def propsFile = rootProject.file(\"gradle.properties\")"
87-
print " if (propsFile.exists()) {"
88-
print " def props = new Properties()"
89-
print " propsFile.withInputStream { props.load(it) }"
90-
print " storeFile file(props[\"MYAPP_RELEASE_STORE_FILE\"])"
91-
print " storePassword props[\"MYAPP_RELEASE_STORE_PASSWORD\"]"
92-
print " keyAlias props[\"MYAPP_RELEASE_KEY_ALIAS\"]"
93-
print " keyPassword props[\"MYAPP_RELEASE_KEY_PASSWORD\"]"
94-
print " }"
95-
print " }"
96-
next
97-
}
98-
{ print }
99-
' "$BUILD_GRADLE" > "${BUILD_GRADLE}.tmp"
100-
mv "${BUILD_GRADLE}.tmp" "$BUILD_GRADLE"
101-
102-
echo "📝 Removing conflicting debug signing from release buildType..."
103-
104-
# Remove ALL signingConfig lines from release buildType, then add back the correct one
105-
sed -i '/buildTypes {/,/^ }$/ {
106-
/release {/,/^ }$/ {
107-
/signingConfig/d
108-
}
109-
}' "$BUILD_GRADLE"
110-
111-
# Add the correct signingConfig at the start of release block
112-
sed -i '/buildTypes {/,/^ }$/ {
113-
/release {/a\
114-
signingConfig signingConfigs.release
115-
}' "$BUILD_GRADLE"
116-
117-
echo "✅ Configuration complete"
118-
echo ""
119-
echo "📋 Final configuration:"
120-
grep -B 2 -A 30 "signingConfigs {" "$BUILD_GRADLE"
121-
echo ""
122-
echo "📋 Release buildType:"
123-
grep -A 15 "release {" "$BUILD_GRADLE" | head -20
37+
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > release.keystore
38+
echo "✅ Keystore decoded to release.keystore"
12439
12540
- name: Make gradlew executable
12641
run: chmod +x android/gradlew
12742

128-
- name: Clean previous builds
129-
run: cd android && ./gradlew clean
130-
131-
- name: Verify gradle.properties before build
43+
# Build the UNsigned Release APK
44+
- name: Build Release APK (Unsigned)
13245
run: |
133-
echo "📋 Checking gradle.properties..."
134-
cat android/gradle.properties | grep MYAPP_ || echo "⚠️ Properties not found in gradle.properties"
135-
136-
echo ""
137-
echo "📋 Checking if keystore exists..."
138-
ls -lh android/app/release.keystore || echo "❌ Keystore not found!"
139-
140-
echo ""
141-
echo "📋 Testing property access..."
14246
cd android
143-
./gradlew properties | grep MYAPP_ || echo "⚠️ Gradle cannot see MYAPP properties"
47+
./gradlew assembleRelease --no-daemon
14448
145-
- name: Build Signed APK with explicit signing
49+
# Sign the APK manually using apksigner
50+
- name: Sign APK
51+
id: sign_apk
52+
run: |
53+
# Find the unsigned APK
54+
APK_PATH=$(find android/app/build/outputs/apk/release -name "*-release-unsigned.apk" -o -name
55+
"*-release.apk" | head -1)
56+
echo "Found APK: $APK_PATH"
57+
58+
# Align the APK (Optimization step required before signing)
59+
$ANDROID_HOME/build-tools/34.0.0/zipalign -v -p 4 "$APK_PATH" release-aligned.apk
60+
61+
# Sign the APK
62+
$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks release.keystore \
63+
--ks-key-alias "${{ secrets.KEY_ALIAS }}" \
64+
--ks-pass "pass:${{ secrets.KEYSTORE_PASSWORD }}" \
65+
--key-pass "pass:${{ secrets.KEY_PASSWORD }}" \
66+
--out release-signed.apk \
67+
release-aligned.apk
68+
69+
echo "✅ APK Signed successfully"
70+
echo "signed_apk_path=release-signed.apk" >> $GITHUB_OUTPUT
71+
72+
# Build the AAB (Android App Bundle)
73+
- name: Build Release AAB
14674
run: |
14775
cd android
76+
./gradlew bundleRelease --no-daemon
14877
149-
echo "🔨 Building with signing..."
150-
./gradlew assembleRelease \
151-
-PMYAPP_RELEASE_STORE_FILE=release.keystore \
152-
-PMYAPP_RELEASE_KEY_ALIAS="${{ secrets.KEY_ALIAS }}" \
153-
-PMYAPP_RELEASE_STORE_PASSWORD="${{ secrets.KEYSTORE_PASSWORD }}" \
154-
-PMYAPP_RELEASE_KEY_PASSWORD="${{ secrets.KEY_PASSWORD }}" \
155-
--no-daemon \
156-
--stacktrace \
157-
--info 2>&1 | tee build.log
158-
159-
echo ""
160-
echo "📋 Checking build log for signing..."
161-
if grep -i "signing" build.log | grep -i "release"; then
162-
echo "✅ Signing configuration was used"
163-
else
164-
echo "⚠️ Warning: No signing activity detected"
165-
fi
166-
167-
- name: Build Signed AAB with explicit signing
78+
# Sign the AAB manually using jarsigner
79+
- name: Sign AAB
16880
run: |
169-
cd android
170-
./gradlew bundleRelease \
171-
-PMYAPP_RELEASE_STORE_FILE=release.keystore \
172-
-PMYAPP_RELEASE_KEY_ALIAS="${{ secrets.KEY_ALIAS }}" \
173-
-PMYAPP_RELEASE_STORE_PASSWORD="${{ secrets.KEYSTORE_PASSWORD }}" \
174-
-PMYAPP_RELEASE_KEY_PASSWORD="${{ secrets.KEY_PASSWORD }}" \
175-
--no-daemon \
176-
--stacktrace
81+
# Find the AAB
82+
AAB_PATH=$(find android/app/build/outputs/bundle/release -name "*-release.aab" | head -1)
83+
echo "Found AAB: $AAB_PATH"
84+
85+
# Sign using jarsigner (AABs use jarsigner, not apksigner)
86+
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
87+
-keystore release.keystore \
88+
-storepass "${{ secrets.KEYSTORE_PASSWORD }}" \
89+
-keypass "${{ secrets.KEY_PASSWORD }}" \
90+
"$AAB_PATH" "${{ secrets.KEY_ALIAS }}"
91+
92+
mv "$AAB_PATH" release-signed.aab
93+
echo "✅ AAB Signed successfully"
17794
17895
- name: Verify APK signature
17996
run: |
180-
APK_PATH=$(find android/app/build/outputs/apk/release -name "*.apk" | head -1)
181-
182-
if [ ! -f "$APK_PATH" ]; then
183-
echo "❌ APK not found!"
184-
exit 1
185-
fi
186-
187-
echo "📦 Verifying: $APK_PATH"
188-
echo ""
189-
190-
# List all META-INF files
191-
echo "=== META-INF Directory Contents ==="
192-
unzip -l "$APK_PATH" | grep "META-INF/" || {
193-
echo "❌ No META-INF directory found - APK is completely unsigned!"
194-
exit 1
195-
}
196-
echo ""
197-
198-
# Find certificate file
199-
CERT_FILE=$(unzip -l "$APK_PATH" | grep -o "META-INF/[A-Z0-9]*\.RSA" | head -1)
200-
201-
if [ -z "$CERT_FILE" ]; then
202-
echo "❌ No RSA certificate found in APK!"
203-
echo "This means the APK was not signed at all."
204-
echo ""
205-
echo "DEBUG: Checking build.gradle signing configuration..."
206-
grep -A 15 "signingConfigs" android/app/build.gradle
207-
exit 1
208-
fi
209-
210-
echo "=== Certificate Information ==="
211-
echo "Certificate file: $CERT_FILE"
212-
unzip -p "$APK_PATH" "$CERT_FILE" | keytool -printcert
213-
214-
echo ""
215-
echo "=== SHA1 Fingerprint ==="
216-
SHA1=$(unzip -p "$APK_PATH" "$CERT_FILE" | keytool -printcert | grep "SHA1:" | awk '{print $2}')
217-
echo "Current SHA1: $SHA1"
218-
echo "Expected SHA1: 59:3D:24:BE:25:91:DF:54:6E:A8:06:17:DC:A1:73:81:3E:71:4C:A0"
219-
220-
if [ "$SHA1" == "59:3D:24:BE:25:91:DF:54:6E:A8:06:17:DC:A1:73:81:3E:71:4C:A0" ]; then
221-
echo "✅ ✅ ✅ CORRECT KEYSTORE! ✅ ✅ ✅"
222-
else
223-
echo "⚠️ WARNING: This is a different keystore!"
224-
echo "Google Play will reject this upload."
225-
fi
97+
echo "📦 Verifying: release-signed.apk"
98+
99+
# Use apksigner verify which is more robust
100+
$ANDROID_HOME/build-tools/34.0.0/apksigner verify --print-certs release-signed.apk
101+
102+
# Quick check for your specific SHA1 if needed
103+
SHA1=$($ANDROID_HOME/build-tools/34.0.0/apksigner verify --print-certs release-signed.apk |
104+
grep "SHA-1 digest:" | head -1 | awk '{print $3}')
105+
echo "Detected SHA1: $SHA1"
226106
227107
- name: Upload APK artifact
228108
uses: actions/upload-artifact@v4
229109
with:
230110
name: app-release-apk-${{ github.run_number }}
231-
path: android/app/build/outputs/apk/release/*.apk
111+
path: release-signed.apk
232112
retention-days: 30
233113

234114
- name: Upload AAB artifact
235115
uses: actions/upload-artifact@v4
236116
with:
237117
name: app-release-aab-${{ github.run_number }}
238-
path: android/app/build/outputs/bundle/release/*.aab
118+
path: release-signed.aab
239119
retention-days: 30
240120

241-
- name: Upload debug files on failure
242-
if: failure()
243-
uses: actions/upload-artifact@v4
244-
with:
245-
name: debug-files-${{ github.run_number }}
246-
path: |
247-
android/build.log
248-
android/app/build.gradle
249-
android/app/build.gradle.backup
250-
android/gradle.properties
251-
retention-days: 7
252-
253121
- name: Cleanup sensitive files
254122
if: always()
255123
run: |
256-
rm -f android/app/release.keystore
257-
rm -f android/gradle.properties
124+
rm -f release.keystore
258125
echo "✅ Cleanup completed"

0 commit comments

Comments
 (0)