Publishing a Flutter application on F-Droid transforms your project into a privacy-first option for users who avoid proprietary app stores. The process demands precision—your app must meet F-Droid’s open-source requirements, use signed builds, and pass automated verification. This guide walks you through configuring your project, setting up GitHub Actions for automated builds, and submitting the correct metadata to F-Droid’s repository.
Start with F-Droid’s Core Requirements
F-Droid enforces strict policies to ensure all apps are fully open-source and free of proprietary components. Before automating your build, audit your project for any non-permissible dependencies. Common exclusions include Google Play Services, closed-source analytics libraries, and proprietary crash reporting tools. If your app relies on these, you must document them under F-Droid’s anti-features policy, but removal is strongly encouraged.
Update your Android build configuration to align with F-Droid’s expectations. Open the android/app/build.gradle.kts file and modify these three critical sections:
- Signing configuration: Adjust the signing block to load credentials dynamically from environment variables during CI builds. Use the code below to handle signing in either local or CI environments:
signingConfigs {
if (System.getenv("CI") == "true") {
create("release") {
keyAlias = System.getenv("KEY_ALIAS")
keyPassword = System.getenv("KEY_PASSWORD")
storeFile = System.getenv("KEYSTORE_PATH")?.let { file(it) }
storePassword = System.getenv("KEYSTORE_PASSWORD")
}
}
}
buildTypes {
release {
signingConfig = if (System.getenv("CI") == "true") {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
isMinifyEnabled = true
isShrinkResources = true
}
}- Strip proprietary dependencies: Exclude Google’s closed-source modules from your APK by adding this configuration under the
dependenciesInfoblock:
dependenciesInfo {
includeInApk = false
includeInBundle = false
}- Split APKs by architecture: F-Droid prefers separate APKs for each CPU architecture. Use this snippet to generate version codes that remain compatible with F-Droid’s build system:
val abiCodes = mapOf("armeabi-v7a" to 1, "arm64-v8a" to 2, "x86_64" to 3)
android.applicationVariants.configureEach {
variant.outputs.forEach { output ->
val abiVersionCode = abiCodes[output.filters.find { it.filterType == "ABI" }?.identifier]
if (abiVersionCode != null) {
(output as ApkVariantOutputImpl).versionCodeOverride = variant.versionCode * 10 + abiVersionCode
}
}
}Generate and Secure Your Signing Keystore
A signing keystore is mandatory for releasing updates. Create one locally using this command:
keytool -genkey -v -keystore myapp-release.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myappStore the keystore file securely and back it up immediately. Loss of this file prevents future updates. Convert the keystore into a Base64 string to safely pass it to GitHub Actions:
base64 -i myapp-release.jks > keystore_b64.txtAutomate Builds with GitHub Actions
A manual process won’t scale. Set up GitHub Actions to build, sign, and split your APKs automatically. Begin by adding these repository secrets in your GitHub project under Settings > Secrets and variables > Actions:
KEYSTORE_BASE64– Paste the contents ofkeystore_b64.txtKEYSTORE_PASSWORD– The password used to protect the keystoreKEY_ALIAS– The alias specified when you created the keystoreKEY_PASSWORD– The password for the keystore alias
Next, create a workflow file named release.yml in your repository’s .github/workflows directory. This workflow ensures compatibility with F-Droid’s build servers by hardcoding the Flutter version and stripping unnecessary build metadata:
jobs:
build_apk:
name: Build Split APKs
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '21'
- name: Setup Flutter
uses: subosito/flutter-action@v2
id: flutter-action
with:
channel: 'stable'
flutter-version: '3.41.9'
- name: Install dependencies
run: flutter pub get
- name: Strip C++ build IDs
run: |
find ${{ steps.flutter-action.outputs.PUB-CACHE-PATH }}/hosted/pub.dev -name CMakeLists.txt -exec sed -i 's/-Wl,/-Wl,--build-id=none,/' {} \;
- name: Decode keystore
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/release-keystore.jks
- name: Build and split APKs
env:
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEYSTORE_PATH: release-keystore.jks
run: |
flutter build apk --release --split-per-abi --split-debug-info=build/symbolsRun this workflow manually or trigger it on Git tag creation. Ensure the workflow produces APKs and uploads them as artifacts to a GitHub Release tagged with a semantic version (e.g., v1.2.3).
Submit Metadata to F-Droid’s Repository
F-Droid does not build from your APKs directly—it builds from source using your Git repository. To link your app correctly, fork the F-Droid Data repository on GitLab, then add a metadata file in the metadata/ directory named after your app’s unique identifier (e.g., io.github.yourname.appname.yml).
Use this template as a starting point, replacing placeholders with your app’s details:
Categories:
- Utilities
License: GPL-3.0-only
AuthorName: Your Name
AuthorWebSite:
SourceCode:
IssueTracker:
Builds:
- versionName: 1.2.3
versionCode: 123
commit: v1.2.3
subdir: android
gradle:
- yes
rm:
- build-tools/*
scanignore:
- gradle/wrapper/gradle-wrapper.jar
sudo:
- apt-get update || true
- apt-get install -y cmake ninja-build
build:
- flutter pub get
- flutter build apk --release --split-per-abi
ndk: r25bF-Droid’s build process runs on standardized servers. To prevent signature mismatches, include sudo commands to install missing tools and use mv commands if needed to realign paths. Submit a merge request to the F-Droid Data repository and monitor the build status through F-Droid’s verification system.
Final Steps and Future Outlook
Once your app appears in F-Droid’s repository, users can install it directly from the F-Droid client. Regularly update your metadata and workflow to keep pace with Flutter and F-Droid policy changes. Consider automating metadata updates by integrating your release pipeline with F-Droid’s GitLab API for seamless long-term maintenance.
AI summary
Learn how to release your Flutter app on F-Droid with open-source compliance. Follow this guide to configure builds, automate APK splitting, and submit metadata correctly.