iToverDose/Software· 14 MAY 2026 · 16:07

How to Publish Your Flutter App on F-Droid Without Friction

Learn a step-by-step method to package and release your Flutter app on F-Droid while meeting strict privacy standards. Avoid common pitfalls and automate builds with GitHub Actions.

DEV Community4 min read0 Comments

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 dependenciesInfo block:
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 myapp

Store 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.txt

Automate 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 of keystore_b64.txt
  • KEYSTORE_PASSWORD – The password used to protect the keystore
  • KEY_ALIAS – The alias specified when you created the keystore
  • KEY_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/symbols

Run 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: r25b

F-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.

Comments

00
LEAVE A COMMENT
ID #IQTR0M

0 / 1200 CHARACTERS

Human check

9 + 9 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.