Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ jobs:
fi
yes | "$sdkmanager" --licenses >/dev/null || true
"$sdkmanager" \
"platforms;android-35" \
"build-tools;34.0.0" \
"platforms;android-36" \
"build-tools;36.0.0" \
"ndk;29.0.14206865"
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/29.0.14206865" >> "$GITHUB_ENV"

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ jobs:
fi
yes | "$sdkmanager" --licenses >/dev/null || true
"$sdkmanager" \
"platforms;android-35" \
"build-tools;34.0.0" \
"platforms;android-36" \
"build-tools;36.0.0" \
"ndk;29.0.14206865"
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/29.0.14206865" >> "$GITHUB_ENV"

Expand Down Expand Up @@ -99,7 +99,7 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
assets=(dist/release/*.apk dist/release/*.aab dist/release/SHA256SUMS)
assets=(dist/release/*.apk dist/release/*.aab dist/release/*-native-debug-symbols.zip dist/release/SHA256SUMS)
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$GITHUB_REF_NAME" "${assets[@]}" \
--repo "$GITHUB_REPOSITORY" \
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ The command-line build does not require Android Studio. It requires:
- Go 1.26 or newer
- `gomobile`
- Android SDK Platform 35
- Android Build Tools 34.0.0
- Android SDK Platform 36 and Build Tools 36.0.0
- Android NDK 29.0.14206865

Example environment on macOS:
Expand Down Expand Up @@ -294,9 +294,10 @@ universal APK used for reproducible F-Droid verification:
The scripts read the default signing key from `$HOME/AndroidApkKey` and its password from
`$HOME/.my-tokens/android-key-password`. Override these with `MEGAPROXY_KEYSTORE_PATH`,
`MEGAPROXY_KEY_ALIAS`, `MEGAPROXY_KEY_PASSWORD_FILE`, and `MEGAPROXY_KEY_PASSWORD`. The signed
ABI-specific and universal APKs, the signed universal App Bundle, and `SHA256SUMS` are
written to `dist/release`. The App Bundle contains every supported ABI; app stores generate and
serve optimized device-specific APK splits from it.
ABI-specific and universal APKs, the signed universal App Bundle, its native debug-symbol archive,
and `SHA256SUMS` are written to `dist/release`. The App Bundle contains every supported ABI; app
stores generate and serve optimized device-specific APK splits from it. Go native symbols are
provided as `mega-proxy-native-debug-symbols.zip` for upload in Play Console.

Pushing a version tag runs the GitHub release workflow, builds and verifies every APK and the App
Bundle, and attaches the artifacts to a GitHub Release. The tag must match `versionName` exactly:
Expand Down
7 changes: 4 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ val gitCommitHash = providers.environmentVariable("GITHUB_SHA")

android {
namespace = "net.megaproxy487"
compileSdk = 35
buildToolsVersion = "34.0.0"
compileSdk = 36
buildToolsVersion = "36.0.0"

defaultConfig {
applicationId = "net.megaproxy487"
minSdk = 26
targetSdk = 35
targetSdk = 36
// Each APK has a unique, monotonically ordered code. Keeping the
// universal code below the ABI variants lets app stores prefer the
// smaller compatible APK when both are available.
Expand Down Expand Up @@ -73,6 +73,7 @@ android {
signingConfig = signingConfigs.findByName("release")
isMinifyEnabled = true
isShrinkResources = true
ndk.debugSymbolLevel = "SYMBOL_TABLE"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id("com.android.application") version "8.7.3" apply false
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
6 changes: 3 additions & 3 deletions scripts/build-release-apks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ mkdir -p "$MEGAPROXY_RELEASE_DIR" "$project_dir/app/libs"
# Avoid carrying artifacts from an older version into SHA256SUMS or a release.
find "$MEGAPROXY_RELEASE_DIR" -maxdepth 1 -type f \
\( -name 'mega-proxy-*.apk' -o -name SHA256SUMS \) -delete
apksigner="$ANDROID_HOME/build-tools/34.0.0/apksigner"
apksigner="$ANDROID_HOME/build-tools/36.0.0/apksigner"
if [[ ! -x "$apksigner" ]]; then
echo "Android apksigner 34.0.0 is unavailable: $apksigner" >&2
echo "Android apksigner 36.0.0 is unavailable: $apksigner" >&2
exit 1
fi

Expand All @@ -90,7 +90,7 @@ verify_release_version_code() {
local expected_version_code="$2"
local actual_version_code
actual_version_code="$(
"$ANDROID_HOME/build-tools/34.0.0/aapt" dump badging "$apk" \
"$ANDROID_HOME/build-tools/36.0.0/aapt" dump badging "$apk" \
| sed -n "s/^package:.*versionCode='\([^']*\)'.*/\1/p"
)"
if [[ "$actual_version_code" != "$expected_version_code" ]]; then
Expand Down
63 changes: 59 additions & 4 deletions scripts/build-release-bundle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fi
export JAVA_HOME ANDROID_HOME ANDROID_NDK_HOME
export PATH="$JAVA_HOME/bin:$HOME/go/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"

for command in go gomobile java jarsigner keytool unzip; do
for command in go gomobile java jarsigner keytool unzip zip; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "Required command is unavailable: $command" >&2
exit 1
Expand Down Expand Up @@ -56,7 +56,8 @@ keytool -list \
-alias "$MEGAPROXY_KEY_ALIAS" >/dev/null

mkdir -p "$MEGAPROXY_RELEASE_DIR" "$project_dir/app/libs"
find "$MEGAPROXY_RELEASE_DIR" -maxdepth 1 -type f -name 'mega-proxy.aab' -delete
find "$MEGAPROXY_RELEASE_DIR" -maxdepth 1 -type f \
\( -name 'mega-proxy.aab' -o -name 'mega-proxy-native-debug-symbols.zip' \) -delete

temporary_dir="$(mktemp -d "${TMPDIR:-/tmp}/megaproxy-bundle.XXXXXX")"
original_aar="$project_dir/app/libs/megaproxy.aar"
Expand All @@ -75,6 +76,14 @@ restore_workspace() {
}
trap restore_workspace EXIT

llvm_bin_dirs=("$ANDROID_NDK_HOME"/toolchains/llvm/prebuilt/*/bin)
llvm_objcopy="${llvm_bin_dirs[0]}/llvm-objcopy"
llvm_readelf="${llvm_bin_dirs[0]}/llvm-readelf"
if [[ ! -x "$llvm_objcopy" || ! -x "$llvm_readelf" ]]; then
echo "NDK LLVM tools are unavailable under $ANDROID_NDK_HOME" >&2
exit 1
fi

export MEGAPROXY_KEYSTORE_PATH
export MEGAPROXY_KEYSTORE_PASSWORD="$keystore_password"
export MEGAPROXY_KEY_ALIAS
Expand All @@ -83,15 +92,43 @@ export MEGAPROXY_KEY_PASSWORD
echo "Building universal native AAR for the App Bundle"
(
cd "$project_dir/native"
# External linking preserves the ELF symbol table and DWARF data in the
# input libraries. AGP strips the packaged copies and extracts the
# requested SYMBOL_TABLE metadata for Play Console symbolication.
gomobile bind \
-target=android \
-androidapi 26 \
-trimpath \
-ldflags="-s -w -buildid=" \
-ldflags="-linkmode=external -buildid= -extldflags=-Wl,--build-id=sha1" \
-o ../app/libs/megaproxy.aar \
./mobile
)

# gomobile provides the Go shared libraries as an AAR dependency, so AGP does
# not retain their symbols automatically. Create the Play-compatible archive
# first, then replace the AAR copies with stripped libraries for the bundle.
aar_contents="$temporary_dir/aar"
symbols_dir="$temporary_dir/native-debug-symbols"
mkdir -p "$aar_contents" "$symbols_dir"
unzip -q "$original_aar" -d "$aar_contents"
for library in "$aar_contents"/jni/*/libgojni.so; do
abi="$(basename "$(dirname "$library")")"
mkdir -p "$symbols_dir/$abi"
"$llvm_objcopy" --strip-debug "$library" "$symbols_dir/$abi/libgojni.so.dbg"
"$llvm_objcopy" --strip-all "$library" "$library.stripped"
mv "$library.stripped" "$library"
done
output_symbols="$MEGAPROXY_RELEASE_DIR/mega-proxy-native-debug-symbols.zip"
(
cd "$symbols_dir"
zip -q -r "$output_symbols" .
)
rm "$original_aar"
(
cd "$aar_contents"
zip -q -r "$original_aar" .
)

echo "Building signed App Bundle"
(
cd "$project_dir"
Expand Down Expand Up @@ -122,6 +159,8 @@ fi
expected_abis=(arm64-v8a armeabi-v7a x86 x86_64)
bundle_entries="$temporary_dir/bundle-entries.txt"
unzip -Z1 "$output_bundle" > "$bundle_entries"
symbol_entries="$temporary_dir/symbol-entries.txt"
unzip -Z1 "$output_symbols" > "$symbol_entries"
for abi in "${expected_abis[@]}"; do
for library in libandroidx.graphics.path.so libgojni.so; do
entry="base/lib/$abi/$library"
Expand All @@ -130,18 +169,34 @@ for abi in "${expected_abis[@]}"; do
exit 1
fi
done
symbol_entry="$abi/libgojni.so.dbg"
if ! grep -Fxq "$symbol_entry" "$symbol_entries"; then
echo "Native debug-symbol archive is missing $symbol_entry" >&2
exit 1
fi
done

arm64_symbols="$temporary_dir/libgojni-arm64.so.dbg"
unzip -p "$output_symbols" arm64-v8a/libgojni.so.dbg > "$arm64_symbols"
if ! "$llvm_readelf" -S "$arm64_symbols" 2>/dev/null | grep '\.symtab' >/dev/null; then
echo "Native debug-symbol archive does not contain an ELF symbol table" >&2
exit 1
fi

(
cd "$MEGAPROXY_RELEASE_DIR"
checksum_files=()
while IFS= read -r file; do
checksum_files+=("$file")
done < <(find . -maxdepth 1 -type f \( -name 'mega-proxy-*.apk' -o -name 'mega-proxy.aab' \) -print | sort)
done < <(find . -maxdepth 1 -type f \
\( -name 'mega-proxy-*.apk' -o -name 'mega-proxy.aab' -o -name 'mega-proxy-native-debug-symbols.zip' \) \
-print | sort)
shasum -a 256 "${checksum_files[@]}" > SHA256SUMS
)

echo
echo "Signed release App Bundle:"
ls -lh "$output_bundle"
echo "Native debug symbols:"
ls -lh "$output_symbols"
echo "Checksums: $MEGAPROXY_RELEASE_DIR/SHA256SUMS"