From afccda1b692e34879700770df4d4d32852238309 Mon Sep 17 00:00:00 2001 From: sh <37271604+shumvgolove@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:00:59 +0000 Subject: [PATCH] android: determinstic build in Android Studio (#6502) * apps/android: pass and adjust PATH to shell script * scripts/compress-and-sign: attempt to make determenistic build * android: strip app-lib from project paths * scripts/compress-and-sign-apk: compatability with MacOS * apps/android: remove redundant cmake flag from app-lib * scripts/compress-and-sign-apk: fix permissions + timestamp normalization * scripts/compress-and-sign-apk: fix file ordering some weird mac issues, i dunno * apps/android: strip comment sections and do not embed build-id in libapp * scripts/compress-and-sign-apk: disable verbose logging --------- Co-authored-by: Evgeny Poberezkin --- apps/multiplatform/android/build.gradle.kts | 5 ++- .../src/commonMain/cpp/android/CMakeLists.txt | 17 ++++++++- scripts/android/compress-and-sign-apk.sh | 37 +++++++++++++++---- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/apps/multiplatform/android/build.gradle.kts b/apps/multiplatform/android/build.gradle.kts index 9b4e7ad58c..5255319194 100644 --- a/apps/multiplatform/android/build.gradle.kts +++ b/apps/multiplatform/android/build.gradle.kts @@ -192,7 +192,10 @@ tasks { } exec { workingDir("../../scripts/android") - environment = mapOf("JAVA_HOME" to "$javaHome") + environment = mapOf( + "JAVA_HOME" to "$javaHome", + "PATH" to "${System.getenv("PATH")}:$javaHome/bin" + ) commandLine = listOf( "./compress-and-sign-apk.sh", "${rootProject.extra["compression.level"]}", diff --git a/apps/multiplatform/common/src/commonMain/cpp/android/CMakeLists.txt b/apps/multiplatform/common/src/commonMain/cpp/android/CMakeLists.txt index 49794a8ab5..fcba574974 100644 --- a/apps/multiplatform/common/src/commonMain/cpp/android/CMakeLists.txt +++ b/apps/multiplatform/common/src/commonMain/cpp/android/CMakeLists.txt @@ -53,12 +53,19 @@ add_library( support SHARED IMPORTED ) set_target_properties( support PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libsupport.so) +target_compile_options(app-lib PRIVATE + -g0 +) + # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. # https://developer.android.com/guide/practices/page-sizes#cmake -target_link_options(app-lib PRIVATE "-Wl,-z,max-page-size=16384") +target_link_options(app-lib PRIVATE + "-Wl,-z,max-page-size=16384" + "-Wl,--build-id=none" +) target_link_libraries( # Specifies the target library. app-lib @@ -67,4 +74,10 @@ target_link_libraries( # Specifies the target library. # Links the target library to the log library # included in the NDK. - ${log-lib}) + ${log-lib} +) + +add_custom_command(TARGET app-lib POST_BUILD + COMMAND ${CMAKE_STRIP} --remove-section=.comment $ + COMMENT "Stripping .comment section from app-lib" +) diff --git a/scripts/android/compress-and-sign-apk.sh b/scripts/android/compress-and-sign-apk.sh index 74d59203c4..d9e46a015f 100755 --- a/scripts/android/compress-and-sign-apk.sh +++ b/scripts/android/compress-and-sign-apk.sh @@ -29,20 +29,43 @@ for ORIG_NAME in "${ORIG_NAMES[@]}"; do ORIG_NAME_COPY=$ORIG_NAME-copy mv "$ORIG_NAME" "$ORIG_NAME_COPY" - (cd apk && zip -r -q -"$level" ../"$ORIG_NAME" .) - # Shouldn't be compressed because of Android requirement - (cd apk && zip -r -q -0 ../"$ORIG_NAME" resources.arsc) + # Determenistic build + find apk -type f -exec chmod 644 {} + + find apk -type d -exec chmod 755 {} + + find apk -exec touch -h -d '2025-12-01T00:00:00' {} + + + ( + cd apk + find . -not -path './res/*' -not -name 'resources.arsc' -type f -print0 | sort -z | xargs -0 zip -X -r -q -"$level" ../"$ORIG_NAME" + ) if [ $case_insensitive -eq 1 ]; then # For case-insensitive file systems - list_of_files=$(unzip -l "$ORIG_NAME_COPY" | grep res/ | sed -e "s|.*res/|res/|") - for file in $list_of_files; do unzip -o -q -d apk "$ORIG_NAME_COPY" "$file" && (cd apk && zip -r -q -0 ../"$ORIG_NAME" "$file"); done + list_of_files=$(unzip -l "$ORIG_NAME_COPY" | grep res/ | sed -e "s|.*res/|res/|" | sort -z) + for file in $list_of_files; do + unzip -o -q -d apk "$ORIG_NAME_COPY" "$file" + ( + cd apk + chmod 644 "$file" + touch -h -d '2025-12-01T00:00:00' "$file" + zip -X -r -q -0 ../"$ORIG_NAME" "$file" + ) + done else # This method is not working correctly on case-insensitive file systems since Android AAPT produce the same names of files # but with different case like xX.png, Xx.png, xx.png, etc - (cd apk && zip -r -q -0 ../"$ORIG_NAME" res) + ( + cd apk + find res -type f -print0 | sort -z | xargs -0 zip -X -r -q -0 ../"$ORIG_NAME" + ) fi + # Shouldn't be compressed because of Android requirement + ( + cd apk + find resources.arsc -type f -print0 | sort -z | xargs -0 zip -X -r -q -0 ../"$ORIG_NAME" + ) + #(cd apk && 7z a -r -mx=$level -tzip -x!resources.arsc ../$ORIG_NAME .) #(cd apk && 7z a -r -mx=0 -tzip ../$ORIG_NAME resources.arsc) @@ -61,4 +84,4 @@ for ORIG_NAME in "${ORIG_NAMES[@]}"; do rm "$ORIG_NAME_COPY" 2> /dev/null || true rm -rf apk || true rm "${ORIG_NAME}".idsig 2> /dev/null || true -done \ No newline at end of file +done