mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-19 22:17:29 +02:00
perf(android): reduce release APK size
Keep Dart debug data outside libapp.so and archive matching symbols and R8 mappings in CI. Pack native relocations, preserve JNI exports, and recompress PNG assets losslessly. ARM64 APK shrinks from 80,306,680 to 76,080,247 bytes (5.26%). Verified with 1,877 Flutter tests, 19 native device tests, Discord SDK integration, and release startup on a 16 KiB Android emulator.
This commit is contained in:
1 parent
4be1073203
commit
b8c50b1527
11 files changed
+102
-4
No files matched your search
@@ -313,3 +313,21 @@ jobs:
|
||||
"$ANDROID_HOME/build-tools/37.0.0/apksigner" verify --verbose \
|
||||
"build/app/outputs/flutter-apk/app-${abi}-release.apk"
|
||||
done
|
||||
|
||||
- name: Record Android symbol provenance
|
||||
run: |
|
||||
test -s build/symbols/android/app.android-arm64.symbols
|
||||
test -s build/symbols/android/app.android-arm.symbols
|
||||
test -s build/app/outputs/mapping/release/mapping.txt
|
||||
git rev-parse HEAD > build/symbols/android/commit.txt
|
||||
sha256sum build/app/outputs/flutter-apk/*release.apk > build/symbols/android/apk-sha256.txt
|
||||
|
||||
- name: Retain Android debug symbols
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: android-symbols-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
path: |
|
||||
build/symbols/android/
|
||||
build/app/outputs/mapping/release/mapping.txt
|
||||
@@ -227,6 +227,24 @@ jobs:
|
||||
"$apk_dir/SpotiFLAC-${VERSION}-${abi}.apk"
|
||||
done
|
||||
|
||||
- name: Record Android symbol provenance
|
||||
run: |
|
||||
test -s build/symbols/android/app.android-arm64.symbols
|
||||
test -s build/symbols/android/app.android-arm.symbols
|
||||
test -s build/app/outputs/mapping/release/mapping.txt
|
||||
git rev-parse HEAD > build/symbols/android/commit.txt
|
||||
sha256sum build/app/outputs/flutter-apk/SpotiFLAC-*.apk > build/symbols/android/apk-sha256.txt
|
||||
|
||||
- name: Retain Android debug symbols
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: android-symbols-${{ needs.get-version.outputs.version }}-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
path: |
|
||||
build/symbols/android/
|
||||
build/app/outputs/mapping/release/mapping.txt
|
||||
|
||||
- name: Upload APK artifact
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
|
||||
@@ -82,6 +82,18 @@ remain the default. To build only ARM64, set
|
||||
run CocoaPods and the app build with `SPOTIFLAC_DISCORD_SDK=0`; an existing Pods
|
||||
installation must be regenerated with that setting.
|
||||
|
||||
Android release builds, including plain `flutter build apk --release`, keep Dart
|
||||
debug data in `build/symbols/android/app.<architecture>.symbols` to reduce APK
|
||||
size without obfuscation. An explicit `--split-debug-info` path overrides this
|
||||
default; `--analyze-size` retains Flutter's normal behavior. Keep these symbols
|
||||
with the matching APK before another local build replaces them. Decode a trace
|
||||
with `flutter symbolize --debug-info=<symbols-file> --input=crash.txt`.
|
||||
|
||||
CI and release jobs retain an `android-symbols-…` artifact with the commit, APK
|
||||
SHA-256 hashes, Dart symbols, and R8 mapping, identified by run and attempt.
|
||||
Archive it before its 90-day retention expires and match the reported APK hash
|
||||
when choosing symbols; equal version numbers do not guarantee a match.
|
||||
|
||||
For native iOS codec checks, see the [FFmpeg capability probe](scripts/README_ios_ffmpeg_capabilities.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -8,6 +8,13 @@ plugins {
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
// Flutter reads this when configuring variant tasks, after this build script.
|
||||
// Keep release AOT debug data outside libapp.so; explicit paths and size analysis take precedence.
|
||||
if (!project.hasProperty("split-debug-info") && !project.hasProperty("code-size-directory")) {
|
||||
project.extensions.extraProperties["split-debug-info"] =
|
||||
rootProject.file("../build/symbols/android").absolutePath
|
||||
}
|
||||
|
||||
val keystorePropertiesFile = rootProject.file("key.properties")
|
||||
val keystoreProperties = Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
|
||||
@@ -24,4 +24,12 @@ add_library(spotiflac_audio SHARED native_audio.cpp)
|
||||
target_compile_features(spotiflac_audio PRIVATE cxx_std_17)
|
||||
target_compile_options(spotiflac_audio PRIVATE -Wall -Wextra -Werror -fvisibility=hidden)
|
||||
target_link_libraries(spotiflac_audio PRIVATE oboe WavPack::WavPack log)
|
||||
target_link_options(spotiflac_audio PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
# Only JNI is public; static Oboe/WavPack/C++ implementation symbols must not
|
||||
# keep otherwise unused code alive. APS2 is supported by our minimum API 24.
|
||||
target_link_options(spotiflac_audio PRIVATE
|
||||
"-Wl,-z,max-page-size=16384"
|
||||
"-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/native_audio.map"
|
||||
"-Wl,--icf=safe"
|
||||
"-Wl,--pack-dyn-relocs=android")
|
||||
set_property(TARGET spotiflac_audio APPEND PROPERTY LINK_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/native_audio.map")
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
global:
|
||||
Java_com_zarz_spotiflac_NativeAudio_openOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_bitsOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_deviceOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_writeOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_startOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_flushOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_framesOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_closeOboe;
|
||||
Java_com_zarz_spotiflac_NativeAudio_openWavPack;
|
||||
Java_com_zarz_spotiflac_NativeAudio_infoWavPack;
|
||||
Java_com_zarz_spotiflac_NativeAudio_readWavPack;
|
||||
Java_com_zarz_spotiflac_NativeAudio_seekWavPack;
|
||||
Java_com_zarz_spotiflac_NativeAudio_closeWavPack;
|
||||
local: *;
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 68 KiB |
@@ -98,8 +98,10 @@ if [[ "$PLATFORM" == "android" ]]; then
|
||||
done
|
||||
|
||||
rustup target add "${ANDROID_TARGETS[@]}"
|
||||
# Align ELF segments for Android devices using 16 KB pages.
|
||||
export RUSTFLAGS="${RUSTFLAGS:-} -C link-arg=-Wl,-z,max-page-size=16384"
|
||||
# Align ELF segments for 16 KB pages and pack relocations (Android API 23+).
|
||||
# Keep APS2 rather than RELR, which requires API 28; our minimum is API 24.
|
||||
# Fold only identical functions whose addresses are not significant.
|
||||
export RUSTFLAGS="${RUSTFLAGS:-} -C link-arg=-Wl,-z,max-page-size=16384 -C link-arg=-Wl,--pack-dyn-relocs=android -C link-arg=-Wl,--icf=safe"
|
||||
for target in "${ANDROID_TARGETS[@]}"; do
|
||||
cargo build --locked --release -p spotiflac-mobile --target "$target"
|
||||
case "$target" in
|
||||
|
||||
+8
-1
@@ -4,7 +4,14 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
option(SPOTIFLAC_DISCORD_SDK "Include the staged Discord Social SDK" ON)
|
||||
add_library(spotiflac_discord SHARED src/main/cpp/presence.cpp)
|
||||
target_compile_options(spotiflac_discord PRIVATE -Wall -Wextra -Werror -fvisibility=hidden)
|
||||
target_link_options(spotiflac_discord PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
# Keep every JNI entry point while hiding the wrapper's static C++ runtime.
|
||||
target_link_options(spotiflac_discord PRIVATE
|
||||
"-Wl,-z,max-page-size=16384"
|
||||
"-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/presence.map"
|
||||
"-Wl,--icf=safe"
|
||||
"-Wl,--pack-dyn-relocs=android")
|
||||
set_property(TARGET spotiflac_discord APPEND PROPERTY LINK_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/presence.map")
|
||||
set(SDK "${CMAKE_CURRENT_SOURCE_DIR}/../sdk/android")
|
||||
if(SPOTIFLAC_DISCORD_SDK AND EXISTS "${SDK}/jni/${ANDROID_ABI}/libdiscord_partner_sdk.so")
|
||||
add_library(discord_partner_sdk SHARED IMPORTED)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
global:
|
||||
Java_com_zarz_spotiflac_discord_DiscordPresencePlugin_nativeStart;
|
||||
Java_com_zarz_spotiflac_discord_DiscordPresencePlugin_nativeTick;
|
||||
Java_com_zarz_spotiflac_discord_DiscordPresencePlugin_nativeUpdate;
|
||||
Java_com_zarz_spotiflac_discord_DiscordPresencePlugin_nativeClear;
|
||||
Java_com_zarz_spotiflac_discord_DiscordPresencePlugin_nativeStop;
|
||||
local: *;
|
||||
};
|
||||
Reference in new issue
Block a user