perf: reduce APK size - switch to audio-only FFmpeg, enable ProGuard, split APK by ABI

This commit is contained in:
zarzet 2026-01-01 19:54:45 +07:00
parent d4d3a48167
commit c033c73a95
7 changed files with 77 additions and 16 deletions

View file

@ -71,12 +71,18 @@ jobs:
run: dart run flutter_launcher_icons
- name: Build APK (Release)
run: flutter build apk --release
run: flutter build apk --release --split-per-abi
- name: Rename APK
- name: Rename APKs
run: |
VERSION=${{ steps.get_version.outputs.version }}
mv build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/SpotiFLAC-${VERSION}-android.apk
cd build/app/outputs/flutter-apk
# Rename split APKs
mv app-arm64-v8a-release.apk SpotiFLAC-${VERSION}-arm64.apk || true
mv app-armeabi-v7a-release.apk SpotiFLAC-${VERSION}-arm32.apk || true
# Also rename universal if exists
mv app-release.apk SpotiFLAC-${VERSION}-universal.apk || true
ls -la
- name: Upload APK artifact
uses: actions/upload-artifact@v4
@ -185,7 +191,8 @@ jobs:
Download Spotify tracks in FLAC quality from Tidal, Qobuz & Amazon Music.
### Downloads
- **Android**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-android.apk`
- **Android (arm64)**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-arm64.apk` (recommended for most devices)
- **Android (arm32)**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-arm32.apk` (for older devices)
- **iOS**: `SpotiFLAC-${{ needs.build-android.outputs.version }}-ios-unsigned.ipa` (requires sideloading)
### Features

View file

@ -29,13 +29,34 @@ android {
versionCode = flutter.versionCode
versionName = flutter.versionName
multiDexEnabled = true
// Only include arm64-v8a for smaller APK (most modern devices)
// Remove this line if you need to support older 32-bit devices
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("debug")
isMinifyEnabled = false
isShrinkResources = false
// Enable code shrinking and resource shrinking
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
// Split APKs by ABI for smaller individual downloads
splits {
abi {
isEnable = true
reset()
include("arm64-v8a", "armeabi-v7a")
isUniversalApk = true // Also generate universal APK
}
}
}

33
android/app/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,33 @@
# Flutter specific rules
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
# Go backend (gobackend.aar)
-keep class gobackend.** { *; }
-keep class go.** { *; }
# FFmpeg Kit
-keep class com.arthenica.ffmpegkit.** { *; }
-keep class com.arthenica.smartexception.** { *; }
# Keep native methods
-keepclasseswithmembernames class * {
native <methods>;
}
# Kotlin coroutines
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keepclassmembers class kotlinx.coroutines.** {
volatile <fields>;
}
# Prevent R8 from removing metadata
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keepattributes Signature
-keepattributes Exceptions

View file

@ -2,8 +2,8 @@ import 'dart:async';
import 'dart:io';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart';
import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:ffmpeg_kit_flutter_new_audio/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new_audio/return_code.dart';
import 'package:spotiflac_android/models/download_item.dart';
import 'package:spotiflac_android/models/settings.dart';
import 'package:spotiflac_android/models/track.dart';

View file

@ -1,6 +1,6 @@
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:ffmpeg_kit_flutter_new_audio/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new_audio/return_code.dart';
/// FFmpeg service for audio conversion and remuxing
class FFmpegService {

View file

@ -313,14 +313,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
ffmpeg_kit_flutter_new:
ffmpeg_kit_flutter_new_audio:
dependency: "direct main"
description:
name: ffmpeg_kit_flutter_new
sha256: d127635f27e93a7f21f0a14ce0a1a148e80919c402dac4a2118d73bfb17ce841
name: ffmpeg_kit_flutter_new_audio
sha256: "0a698b46cd163c8e9917af75325c84d27871a2a8b2c37de3b40486cd0ab662ae"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
version: "2.0.0"
ffmpeg_kit_flutter_platform_interface:
dependency: transitive
description:

View file

@ -48,8 +48,8 @@ dependencies:
device_info_plus: ^12.3.0
share_plus: ^10.1.4
# FFmpeg for audio conversion
ffmpeg_kit_flutter_new: ^4.1.0
# FFmpeg for audio conversion (audio-only version - much smaller)
ffmpeg_kit_flutter_new_audio: ^2.0.0
open_filex: ^4.7.0
dev_dependencies: