diff --git a/config/fastlane/common.Fastfile b/config/fastlane/common.Fastfile index 1c8a35c..399c23b 100644 --- a/config/fastlane/common.Fastfile +++ b/config/fastlane/common.Fastfile @@ -20,6 +20,9 @@ MAJOR_MULTIPLIER = 10000000 MINOR_MULTIPLIER = 10000 PATCH_MULTIPLIER = 100 +FDROID_ABI_VERSION_CODES = { "armeabi-v7a" => 1, "arm64-v8a" => 2, "x86" => 3, "x86_64" => 4 }.freeze +FDROID_ABI_MULTIPLIER = 10 + TYPE_ALPHA = "alpha" TYPE_RC = "rc" TYPE_FINAL = "final" @@ -60,6 +63,15 @@ platform :android do uploadToHuawei(versionCode: versionInfo["versionCode"], isPrerelease: isPrerelease) end + desc "Build ABI APKs for F-Droid in app/build/fdroid/" + lane :buildFdroid do + gradle( + task: ":app:assembleGenericRelease", + flags: "--init-script fastlane/fdroid.init.gradle", + properties: { "fdroidAbiSplit" => true } + ) + end + desc "Print version info" lane :printVersionInfo do versionInfo = getVersionInfo() @@ -70,6 +82,9 @@ platform :android do print "Minor: #{versionComponents["minor"]}\n" print "Patch: #{versionComponents["patch"]}\n" print "Build: #{versionComponents["build"]}\n" + fdroidAbiVersionCodes(versionCode: versionInfo["versionCode"]).each do |abi, versionCode| + print "F-Droid #{abi} version code: #{versionCode}\n" + end end # Usage: fastlane incrementVersion type:(major|minor|patch|rc|final) @@ -141,6 +156,13 @@ platform :android do test end + desc "Generate F-Droid versionCode per ABI, must match fdroid.init.gradle" + private_lane :fdroidAbiVersionCodes do |options| + versionCode = options[:versionCode] + base = (versionCode / MAJOR_MULTIPLIER) * MAJOR_MULTIPLIER + (versionCode % MAJOR_MULTIPLIER) * FDROID_ABI_MULTIPLIER + FDROID_ABI_VERSION_CODES.transform_values { |abiCode| base + abiCode } + end + desc "Compute version name from version code" private_lane :generateVersionName do |versionComponents| suffix = "" diff --git a/config/fastlane/fdroid.init.gradle b/config/fastlane/fdroid.init.gradle new file mode 100644 index 0000000..9b15457 --- /dev/null +++ b/config/fastlane/fdroid.init.gradle @@ -0,0 +1,46 @@ +gradle.beforeProject { project -> + if (project.path != ':app' || !project.providers.gradleProperty('fdroidAbiSplit').isPresent()) { + return + } + if (project.extensions.extraProperties.has('nextcloudFdroidConfigured')) { + return + } + project.extensions.extraProperties.set('nextcloudFdroidConfigured', true) + + project.pluginManager.withPlugin('com.android.application') { + def abiVersionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4] + def majorMultiplier = 10000000 + def abiMultiplier = 10 + def androidComponents = project.extensions.getByName('androidComponents') + + def buildDirectory = project.layout.buildDirectory.get() + project.layout.buildDirectory.set(buildDirectory.dir('fdroid')) + + androidComponents.finalizeDsl { android -> + ([android.defaultConfig] + android.buildTypes.toList() + android.productFlavors.toList()).each { config -> + config.ndk.abiFilters.clear() + } + android.splits.abi.enable = true + android.splits.abi.reset() + android.splits.abi.include(*abiVersionCodes.keySet().toArray(new String[0])) + android.splits.abi.universalApk = false + } + + androidComponents.beforeVariants(androidComponents.selector().all()) { variant -> + variant.enable = variant.name == 'genericRelease' + } + + androidComponents.onVariants(androidComponents.selector().withName('genericRelease')) { variant -> + variant.outputs.each { output -> + def abi = output.filters.find { it.filterType.name() == 'ABI' }?.identifier + if (!abiVersionCodes.containsKey(abi)) { + throw new GradleException("Unexpected F-Droid APK ABI: ${abi}") + } + def versionCode = output.versionCode.get() + def base = versionCode.intdiv(majorMultiplier) * majorMultiplier + + (versionCode % majorMultiplier) * abiMultiplier + output.versionCode.set(base + abiVersionCodes[abi]) + } + } + } +} diff --git a/config/fastlane/fdroid.init.gradle.license b/config/fastlane/fdroid.init.gradle.license new file mode 100644 index 0000000..b6fc737 --- /dev/null +++ b/config/fastlane/fdroid.init.gradle.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors +SPDX-License-Identifier: GPL-3.0-or-later