Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 151 additions & 2 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ plugins {
val appVersionName = "1.5.1"
val appVersionCode = 10

// Load local.properties for secrets like GITHUB_CLIENT_ID
val localProps = Properties().apply {
val file = rootProject.file("local.properties")
if (file.exists()) file.inputStream().use { this.load(it) }
Expand Down Expand Up @@ -129,6 +128,8 @@ kotlin {
// Room
implementation(libs.androidx.room.runtime)
implementation(libs.sqlite.bundled)

implementation(libs.kotlinx.coroutinesSwing)
Comment on lines +131 to +132
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: JVM-specific dependency in commonMain will break Android builds.

kotlinx.coroutinesSwing requires the Swing library, which is JVM-specific and not available on Android or other platforms. Adding this to commonMain.dependencies will cause compilation failures for non-JVM targets.

🐛 Proposed fix

Move this dependency back to jvmMain.dependencies:

         // Room
         implementation(libs.androidx.room.runtime)
         implementation(libs.sqlite.bundled)
-
-        implementation(libs.kotlinx.coroutinesSwing)
     }

And add it to jvmMain.dependencies:

jvmMain {
    kotlin.srcDir(layout.buildDirectory.dir("generated/buildconfig/jvm"))

    dependencies {
        implementation(compose.desktop.currentOs)
        // Koin core
        implementation(libs.koin.core)
        // Ktor client for JVM Desktop
        implementation(libs.ktor.client.core)
        implementation(libs.ktor.client.java)
        implementation(libs.ktor.client.content.negotiation)
        implementation(libs.ktor.serialization.kotlinx.json)
        implementation(libs.kotlinx.serialization.json)
        implementation(libs.kotlinx.coroutinesSwing)
    }
}
🤖 Prompt for AI Agents
In @composeApp/build.gradle.kts around lines 131 - 132, The
kotlinx.coroutinesSwing dependency is incorrectly added to commonMain
(implementation(libs.kotlinx.coroutinesSwing)), which is JVM-only and will break
Android/other targets; move this dependency out of commonMain.dependencies and
add it to jvmMain.dependencies instead (alongside the other JVM-specific deps in
the jvmMain block) so only the JVM target pulls in kotlinx.coroutinesSwing.

}
Comment on lines +131 to 133
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the build.gradle.kts file around the flagged lines
find . -name "build.gradle.kts" -path "*/composeApp/*" | head -5

Repository: rainxchzed/Github-Store

Length of output: 96


🏁 Script executed:

# Read the file to see the context around lines 131-133 and the source sets
cat -n composeApp/build.gradle.kts | sed -n '120,145p'

Repository: rainxchzed/Github-Store

Length of output: 1071


🏁 Script executed:

# Get the full picture of source sets and all dependencies sections
cat -n composeApp/build.gradle.kts | grep -A 5 -B 2 "commonMain\|jvmMain\|dependencies"

Repository: rainxchzed/Github-Store

Length of output: 2883


🏁 Script executed:

# Check the full commonMain.dependencies block to see all dependencies
cat -n composeApp/build.gradle.kts | sed -n '77,133p'

Repository: rainxchzed/Github-Store

Length of output: 2670


🏁 Script executed:

# Check what targets are configured in the kotlin block
cat -n composeApp/build.gradle.kts | grep -A 20 "kotlin {" | head -30

Repository: rainxchzed/Github-Store

Length of output: 890


🏁 Script executed:

# Look for the libs.kotlinx.coroutinesSwing definition in gradle catalog
find . -name "*.toml" -o -name "libs.gradle" | xargs grep -l "coroutinesSwing" 2>/dev/null || echo "Checking for version catalog..."
find . -name "libs.versions.toml" | head -1 | xargs cat 2>/dev/null | grep -A 2 -B 2 "coroutinesSwing"

Repository: rainxchzed/Github-Store

Length of output: 638


🌐 Web query:

kotlinx-coroutines-swing library JVM Swing-only compatibility

💡 Result:

Short answer: kotlinx-coroutines-swing is a JVM-only module that provides a Swing (EDT) MainCoroutineDispatcher (Dispatchers.Swing / Main on JVM). If you need Dispatchers.Main for Swing on the JVM (including desktop Kotlin/JVM or the JVM target of a multiplatform project) you must add the org.jetbrains.kotlinx:kotlinx-coroutines-swing artifact to your runtime dependencies. [1][2]

Sources:

  • kotlinx-coroutines-swing package (documents Dispatchers.Swing / jvm). [1]
  • Dispatchers.Main docs (notes that on JVM Main maps to Android/JavaFX/Swing and that you must add the corresponding artifact at runtime). [2]

Move kotlinx.coroutinesSwing from commonMain to jvmMain

kotlinx-coroutines-swing is JVM-only (provides Dispatchers.Swing for desktop/Swing applications). Placing it in commonMain.dependencies makes it available to all targets including androidTarget, where it has no meaning and cannot be used. Move it to jvmMain.dependencies.

Fix
         commonMain.dependencies {
             // ... other dependencies
-            implementation(libs.kotlinx.coroutinesSwing)
         }
         jvmMain {
             kotlin.srcDir(layout.buildDirectory.dir("generated/buildconfig/jvm"))
 
             dependencies {
                 implementation(compose.desktop.currentOs)
+                implementation(libs.kotlinx.coroutinesSwing)
                 // Koin core
🤖 Prompt for AI Agents
In @composeApp/build.gradle.kts around lines 131 - 133, The dependency
implementation(libs.kotlinx.coroutinesSwing) is currently declared under
commonMain (commonMain.dependencies) but kotlinx-coroutines-swing is JVM-only;
move that dependency entry from the commonMain.dependencies block into the
jvmMain.dependencies block so it is only added for the JVM target (look for the
implementation(libs.kotlinx.coroutinesSwing) line and the commonMain / jvmMain
dependency blocks and relocate the line accordingly).

commonTest.dependencies {
implementation(libs.kotlin.test)
Expand All @@ -143,7 +144,6 @@ kotlin {

dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.kotlinx.coroutinesSwing)
// Koin core
implementation(libs.koin.core)
// Ktor client for JVM Desktop
Expand Down Expand Up @@ -260,3 +260,152 @@ compose.desktop {
}
}
}

val appId = "zed.rainxch.githubstore"
val appName = "GitHub-Store"
val flatpakDir = layout.buildDirectory.dir("flatpak")
val flatpakSourceDir = layout.buildDirectory.dir("flatpak-source")

// Define copy tasks separately to avoid configuration cache issues
val copyFlatpakBinary = tasks.register<Copy>("copyFlatpakBinary") {
dependsOn("packageAppImage")

val appImageOutput = layout.buildDirectory.dir("compose/binaries/main/app/$appName")

from(appImageOutput)
into(flatpakDir.map { it.asFile.resolve("build") })

doFirst {
val targetDir = outputs.files.singleFile
if (targetDir.exists()) {
targetDir.deleteRecursively()
}
targetDir.mkdirs()
}
}
Comment on lines +270 to +285
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd "build.gradle.kts" | head -5

Repository: rainxchzed/Github-Store

Length of output: 111


🏁 Script executed:

git ls-files | grep -E "composeApp.*build\.gradle\.kts"

Repository: rainxchzed/Github-Store

Length of output: 94


🏁 Script executed:

head -300 composeApp/build.gradle.kts | tail -50

Repository: rainxchzed/Github-Store

Length of output: 1594


🏁 Script executed:

rg "packageAppImage|register.*AppImage" composeApp/build.gradle.kts -B 2 -A 5

Repository: rainxchzed/Github-Store

Length of output: 407


🏁 Script executed:

rg "OperatingSystem|isLinux|isWindows|isMac" composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 49


🏁 Script executed:

rg "outputs\.files\.singleFile" composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 164


🏁 Script executed:

head -50 composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 1652


🏁 Script executed:

rg "import|onlyIf" composeApp/build.gradle.kts | head -20

Repository: rainxchzed/Github-Store

Length of output: 222


🏁 Script executed:

rg "packageAppImage" . -A 3 -B 1 --type kotlin

Repository: rainxchzed/Github-Store

Length of output: 408


🏁 Script executed:

rg "onlyIf.*Linux|onlyIf.*Windows|onlyIf.*platform" composeApp/build.gradle.kts -B 2 -A 2

Repository: rainxchzed/Github-Store

Length of output: 49


🏁 Script executed:

grep -n "onlyIf" composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 83


🏁 Script executed:

rg "System.getProperty|os\.name" composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 49


🏁 Script executed:

cat -n composeApp/build.gradle.kts | sed -n '200,350p'

Repository: rainxchzed/Github-Store

Length of output: 5541


🏁 Script executed:

cat -n composeApp/build.gradle.kts | sed -n '360,380p'

Repository: rainxchzed/Github-Store

Length of output: 878


🏁 Script executed:

rg "System\.getenv|System\.getProperty" composeApp/build.gradle.kts

Repository: rainxchzed/Github-Store

Length of output: 49


🌐 Web query:

Gradle Copy task outputs.files.singleFile fragile alternative

💡 Result:

Short answer: don’t rely on outputs.files.singleFile for a Copy task. declare a concrete output (OutputFile or outputs.file with a Provider) or make the Copy produce a known filename and register that exact file as the task’s output.

Why: Copy’s outputs.files is an approximation (and can be a directory or multiple files), so singleFile is brittle. Gradle docs recommend explicitly declaring outputs or using doNotTrackState for weird dirs. [1][2]

Two concise patterns:

  1. If you can pick a stable output path (recommended)
  • Make the Copy write a single known file (rename or into a unique dir) and declare that file as the task output.
    Groovy example:
    task myCopy(type: Copy) {
    from 'src/x/foo.zip'
    into "$buildDir/out"
    rename { 'app.zip' }
    }
    tasks.myCopy.outputs.file("$buildDir/out/app.zip")

Kotlin DSL:
val myCopy = tasks.register("myCopy") {
from(layout.projectDirectory.file("src/x/foo.zip"))
into(layout.buildDirectory.dir("out"))
rename { "app.zip" }
}
myCopy.configure { outputs.file(layout.buildDirectory.file("out/app.zip")) }

  1. If you can’t know the filename at configuration time, expose a Provider/explicit output property from a custom task (annotate with @OutputFile or return Provider) or compute and register the exact output file via a Provider so Gradle knows the single output without calling .singleFile.
  • Implement a small custom task class with an @OutputFile property (or register outputs.file(someProvider)) and set that provider from the copy spec.

References:

  • Gradle “Working with files” / copy behavior and outputs explanation. [1]
  • Copy task DSL and outputs/file APIs. [2]

If you want, tell me which Gradle version and show your current Copy task and I’ll give the exact code to make it robust.


🌐 Web query:

Gradle org.gradle.internal.os.OperatingSystem internal API alternative

💡 Result:

Use Gradle's public OperatingSystem types (not the internal org.gradle.internal.*). Options:

  • org.gradle.platform.OperatingSystem (public enum, since Gradle 7.6). [1]
  • org.gradle.nativeplatform.platform.OperatingSystem (public interface used by native-platform APIs). [2]
  • Or, if you just need a simple runtime check, use Java System properties (System.getProperty("os.name")) and parse it yourself. [3]

Do not depend on org.gradle.internal.* — the Gradle public-API docs mark internal packages unsupported. [4]

Sources:
[1] Gradle Javadoc — org.gradle.platform.OperatingSystem.
[2] Gradle Javadoc — org.gradle.nativeplatform.platform.OperatingSystem.
[3] Typical approach: System.getProperty("os.name") (Java SE).
[4] Gradle Public APIs documentation.


copyFlatpakBinary: add Linux guard (using public API) and safer cleanup target

This task depends on packageAppImage and assumes a Linux environment (Flatpak is Linux-only), but has no platform guard. Additionally, using outputs.files.singleFile is fragile; prefer the explicit destination directory.

The proposed fix is on the right track for the cleanup logic, but uses org.gradle.internal.os.OperatingSystem which is an unsupported internal API. Use a public alternative instead (e.g., System.getProperty("os.name") or Gradle's public OperatingSystem from org.gradle.platform if Gradle 7.6+).

Revised fix
 val copyFlatpakBinary = tasks.register<Copy>("copyFlatpakBinary") {
+    onlyIf { System.getProperty("os.name").lowercase().contains("linux") }
     dependsOn("packageAppImage")
 
+    val targetDir = flatpakDir.map { it.asFile.resolve("build") }
-    val appImageOutput = layout.buildDirectory.dir("compose/binaries/main/app/$appName")
+    val appImageOutput = layout.buildDirectory.dir("compose/binaries/main/app/$appName")
 
     from(appImageOutput)
-    into(flatpakDir.map { it.asFile.resolve("build") })
+    into(targetDir)
 
     doFirst {
-        val targetDir = outputs.files.singleFile
-        if (targetDir.exists()) {
-            targetDir.deleteRecursively()
+        val dir = targetDir.get()
+        if (dir.exists()) {
+            dir.deleteRecursively()
         }
-        targetDir.mkdirs()
+        dir.mkdirs()
     }
 }


val copyFlatpakResources = tasks.register<Copy>("copyFlatpakResources") {

val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")

from(resourcesDir) {
include("manifest.yml", "*.desktop", "*.xml")
}
into(flatpakDir.map { it.asFile.resolve("build") })

rename("manifest.yml", "$appId.yml")
}

tasks.register<Exec>("packageFlatpak") {
dependsOn(copyFlatpakResources)
group = "build"
description = "Build Flatpak for Linux desktop (binary-based)"

val buildDir = flatpakDir.map { it.asFile.resolve("build") }
val repoDir = flatpakDir.map { it.asFile.resolve("repo") }

workingDir(buildDir)
commandLine(
"flatpak-builder",
"--install-deps-from=flathub",
"--repo=${repoDir.get().absolutePath}",
"--force-clean",
"--disable-rofiles-fuse",
"build/${appId}",
"$appId.yml"
)
}

tasks.register<Exec>("exportFlatpak") {
dependsOn("packageFlatpak")
group = "build"
description = "Export Flatpak bundle (binary-based)"

val versionName = appVersionName

workingDir(flatpakDir)
commandLine("flatpak", "build-bundle", "repo", "github-store-${versionName}.flatpak", appId, "master")
}

tasks.register<Exec>("runFlatpak") {
dependsOn("packageFlatpak")
group = "run"
description = "Run the Flatpak locally (binary-based)"

val buildDir = flatpakDir.map { it.asFile.resolve("build") }

workingDir(buildDir)
commandLine("flatpak-builder", "--run", "build/${appId}", "${appId}.yml", "GitHub-Store")
}

// Source-based tasks for Flathub submission
val copyFlatpakSourceResources = tasks.register<Copy>("copyFlatpakSourceResources") {
val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")

from(resourcesDir) {
include("zed.rainxch.githubstore.yml", "*.desktop", "*.xml", "app_icon.png")
}
into(flatpakSourceDir.map { it.asFile.resolve("build") })

doFirst {
val targetDir = outputs.files.singleFile
if (targetDir.exists()) {
targetDir.deleteRecursively()
}
targetDir.mkdirs()
}
}
Comment on lines +343 to +358
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix directory cleanup to target the correct path.

The same issue as in copyFlatpakBinary: the doFirst block uses outputs.files.singleFile which may not reliably reference the intended target directory.

🔧 Proposed fix
 val copyFlatpakSourceResources = tasks.register<Copy>("copyFlatpakSourceResources") {
     val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")
 
     from(resourcesDir) {
         include("zed.rainxch.githubstore.yml", "*.desktop", "*.xml", "app_icon.png")
     }
     into(flatpakSourceDir.map { it.asFile.resolve("build") })
 
     doFirst {
-        val targetDir = outputs.files.singleFile
+        val targetDir = flatpakSourceDir.get().asFile.resolve("build")
         if (targetDir.exists()) {
             targetDir.deleteRecursively()
         }
         targetDir.mkdirs()
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val copyFlatpakSourceResources = tasks.register<Copy>("copyFlatpakSourceResources") {
val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")
from(resourcesDir) {
include("zed.rainxch.githubstore.yml", "*.desktop", "*.xml", "app_icon.png")
}
into(flatpakSourceDir.map { it.asFile.resolve("build") })
doFirst {
val targetDir = outputs.files.singleFile
if (targetDir.exists()) {
targetDir.deleteRecursively()
}
targetDir.mkdirs()
}
}
val copyFlatpakSourceResources = tasks.register<Copy>("copyFlatpakSourceResources") {
val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")
from(resourcesDir) {
include("zed.rainxch.githubstore.yml", "*.desktop", "*.xml", "app_icon.png")
}
into(flatpakSourceDir.map { it.asFile.resolve("build") })
doFirst {
val targetDir = flatpakSourceDir.get().asFile.resolve("build")
if (targetDir.exists()) {
targetDir.deleteRecursively()
}
targetDir.mkdirs()
}
}


val copyGeneratedSources = tasks.register<Copy>("copyGeneratedSources") {
dependsOn(copyFlatpakSourceResources)

val sourcesFile = layout.projectDirectory.file("generated-sources.json")

from(sourcesFile)
into(flatpakSourceDir.map { it.asFile.resolve("build") })

onlyIf {
sourcesFile.asFile.exists()
}
}

tasks.register<Exec>("packageFlatpakSource") {
dependsOn(copyGeneratedSources)
group = "build"
description = "Build Flatpak for Linux desktop (source-based for submission)"

val buildDir = flatpakSourceDir.map { it.asFile.resolve("build") }
val repoDir = flatpakSourceDir.map { it.asFile.resolve("repo") }

workingDir(buildDir)
commandLine(
"flatpak-builder",
"--install-deps-from=flathub",
"--repo=${repoDir.get().absolutePath}",
"--force-clean",
"build/${appId}",
"$appId.yml"
)
}

tasks.register<Exec>("exportFlatpakSource") {
dependsOn("packageFlatpakSource")
group = "build"
description = "Export Flatpak bundle (source-based)"

val versionName = appVersionName

workingDir(flatpakSourceDir)
commandLine("flatpak", "build-bundle", "repo", "github-store-${versionName}-source.flatpak", appId, "master")
}

tasks.register<Exec>("runFlatpakSource") {
dependsOn("packageFlatpakSource")
group = "run"
description = "Run the Flatpak locally (source-based)"

val buildDir = flatpakSourceDir.map { it.asFile.resolve("build") }

workingDir(buildDir)
commandLine("flatpak-builder", "--run", "build/${appId}", "${appId}.yml", "GitHub-Store")
}
Comment on lines 342 to 412
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Source-based tasks reference the wrong manifest filename ($appId.yml doesn’t exist in that build dir).

copyFlatpakSourceResources copies zed.rainxch.githubstore.yml, but packageFlatpakSource/runFlatpakSource use $appId.yml. That should be consistent (either rename on copy, or invoke the copied filename).

Proposed fix (rename on copy to reuse $appId.yml)
 val copyFlatpakSourceResources = tasks.register<Copy>("copyFlatpakSourceResources") {
   val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")

   from(resourcesDir) {
     include("zed.rainxch.githubstore.yml", "*.desktop", "*.xml", "app_icon.png")
   }
   into(flatpakSourceDir.map { it.asFile.resolve("build") })
+
+  rename("zed.rainxch.githubstore.yml", "$appId.yml")

   doFirst {
     val targetDir = outputs.files.singleFile
     if (targetDir.exists()) {
       targetDir.deleteRecursively()
     }
     targetDir.mkdirs()
   }
 }
🤖 Prompt for AI Agents
In @composeApp/build.gradle.kts around lines 341 - 411, The Flatpak manifest
filename is inconsistent: copyFlatpakSourceResources copies
zed.rainxch.githubstore.yml but packageFlatpakSource and runFlatpakSource call
"$appId.yml"; update copyFlatpakSourceResources to rename the copied manifest to
"$appId.yml" (e.g., use from(resourcesDir) {
include("zed.rainxch.githubstore.yml"); rename("zed.rainxch.githubstore.yml",
"$appId.yml") } or equivalent) so packageFlatpakSource and runFlatpakSource
(which reference appId and "$appId.yml") find the manifest, or alternatively
change the commandLine invocations in packageFlatpakSource and runFlatpakSource
to use "zed.rainxch.githubstore.yml" consistently.

Binary file modified composeApp/logo/app_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions composeApp/src/jvmMain/resources/flatpak/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
app-id: zed.rainxch.githubstore
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk//25.08
command: GitHub-Store
finish-args:
- --share=network
- --share=ipc
- --socket=x11
- --socket=wayland
- --device=dri
- --filesystem=xdg-download
- --env=GDK_BACKEND=x11,wayland
modules:
- name: githubstore
buildsystem: simple
build-commands:
- mkdir -p /app/bin /app/lib
- install -Dm755 bin/GitHub-Store /app/bin/GitHub-Store
- cp -r lib/* /app/lib/
- mkdir -p /app/share/applications
- install -D zed.rainxch.githubstore.desktop /app/share/applications/
- mkdir -p /app/share/icons/hicolor/512x512/apps/
- install -D app_icon.png /app/share/icons/hicolor/512x512/apps/zed.rainxch.githubstore.png
- mkdir -p /app/share/metainfo/
- install -D zed.rainxch.githubstore.appdata.xml /app/share/metainfo/zed.rainxch.githubstore.appdata.xml
sources:
- type: dir
path: .
skip:
- zed.rainxch.githubstore.yml
- manifest.yml
Comment on lines +1 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

❓ Verification inconclusive

Flatpak manifest format sdk field syntax runtime-version


Short answer — in a Flatpak manifest (JSON or YAML) you set:

  • sdk: a string naming the development runtime (e.g. "org.freedesktop.Sdk", "org.gnome.Sdk", "org.kde.Sdk").
  • runtime-version: a string naming the runtime version to build against (e.g. "19.08", "3.26", "41", "6.8"); if omitted it defaults to "master".

Example (JSON):
{
"app-id": "org.example.App",
"runtime": "org.freedesktop.Platform",
"runtime-version": "21.08",
"sdk": "org.freedesktop.Sdk",
"command": "app"
}

These fields are top-level manifest keys used by flatpak-builder to choose the platform and SDK for build and packaging. [1][2]

Sources:
[1] Flatpak Builder command reference / manifest docs.
[2] Flatpak manifests guide (examples and explanation).


AppStream metainfo.xml vs appdata.xml naming convention


Short answer

  • Use .appdata.xml for desktop applications (type="desktop" or "desktop-application"); use .metainfo.xml for other component types (addons, fonts, codecs, firmware, etc.). The file basename should match the inside the and files go in /usr/share/metainfo (legacy /usr/share/appdata is supported only for compatibility). [1][2][3]

Details / rationale (brief)

  • AppStream's spec permits either suffix for desktop-application for legacy reasons, but conventions and packaging guidelines prefer .appdata.xml for applications and .metainfo.xml for everything else to avoid name collisions and to make intent clear. [1][2]
  • Validate files with appstream tools (appstreamcli / appstream-util) and install them in the package that provides the .desktop file for GUI apps. [1][3]

Sources
[1] AppStream (freedesktop) — Metadata / Desktop Applications.
[2] KDE TechBase — MetaInfo (explains .appdata.xml vs .metainfo.xml).
[3] Debian / Fedora packaging guidelines (installation location and package placement).


Script executed:

# Check if there are any other Flatpak manifests in the repo for reference
find . -name "*.yml" -o -name "*.yaml" | grep -i flatpak | head -20

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

./composeApp/src/jvmMain/resources/flatpak/manifest.yml
./composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.yml

Script executed:

# Look at the Gradle build config to understand the manifest renaming behavior
find . -name "build.gradle*" -o -name "*.gradle" | head -20

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

./build.gradle.kts
./composeApp/build.gradle.kts

Script executed:

# Check the build.gradle.kts to understand manifest naming/handling
cat -n composeApp/build.gradle.kts | head -100

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

     1	import org.jetbrains.compose.desktop.application.dsl.TargetFormat
     2	import org.jetbrains.kotlin.gradle.dsl.JvmTarget
     3	import java.util.Properties
     4	
     5	plugins {
     6	    alias(libs.plugins.kotlinMultiplatform)
     7	    alias(libs.plugins.androidApplication)
     8	    alias(libs.plugins.composeMultiplatform)
     9	    alias(libs.plugins.composeCompiler)
    10	    alias(libs.plugins.composeHotReload)
    11	    alias(libs.plugins.kotlinSerialization)
    12	    alias(libs.plugins.kotest)
    13	    alias(libs.plugins.ksp)
    14	    alias(libs.plugins.androidx.room)
    15	}
    16	
    17	val appVersionName = "1.5.1"
    18	val appVersionCode = 10
    19	
    20	val localProps = Properties().apply {
    21	    val file = rootProject.file("local.properties")
    22	    if (file.exists()) file.inputStream().use { this.load(it) }
    23	}
    24	val localGithubClientId =
    25	    (localProps.getProperty("GITHUB_CLIENT_ID") ?: "Ov23linTY28VFpFjFiI9").trim()
    26	
    27	// Generate BuildConfig for JVM (Configuration Cache Compatible)
    28	val generateJvmBuildConfig = tasks.register("generateJvmBuildConfig") {
    29	    val outputDir = layout.buildDirectory.dir("generated/buildconfig/jvm")
    30	    val clientId = localGithubClientId
    31	    val versionName = appVersionName
    32	
    33	    outputs.dir(outputDir)
    34	
    35	    doLast {
    36	        val file = outputDir.get().asFile.resolve("zed/rainxch/githubstore/BuildConfig.kt")
    37	        file.parentFile.mkdirs()
    38	        file.writeText(
    39	            """
    40	            package zed.rainxch.githubstore
    41	            
    42	            object BuildConfig {
    43	                const val GITHUB_CLIENT_ID = "$clientId"
    44	                const val VERSION_NAME = "$versionName"
    45	            }
    46	        """.trimIndent()
    47	        )
    48	    }
    49	}
    50	
    51	kotlin {
    52	    androidTarget {
    53	        compilerOptions {
    54	            jvmTarget.set(JvmTarget.JVM_21)
    55	        }
    56	    }
    57	
    58	    jvm()
    59	
    60	    sourceSets {
    61	        androidMain.dependencies {
    62	            implementation(compose.preview)
    63	            implementation(libs.androidx.activity.compose)
    64	            // Koin DI
    65	            implementation(libs.koin.android)
    66	            implementation(libs.koin.androidx.compose)
    67	            // Ktor client for Android
    68	            implementation(libs.ktor.client.core)
    69	            implementation(libs.ktor.client.okhttp)
    70	            implementation(libs.ktor.client.content.negotiation)
    71	            implementation(libs.ktor.serialization.kotlinx.json)
    72	            implementation(libs.kotlinx.serialization.json)
    73	            // Secure storage (direct coordinate to avoid catalog accessor mismatch)
    74	            implementation(libs.androidx.security.crypto)
    75	            implementation(libs.core.splashscreen)
    76	        }
    77	        commonMain.dependencies {
    78	            implementation(compose.runtime)
    79	            implementation(compose.foundation)
    80	            implementation(libs.material3)
    81	            implementation(compose.materialIconsExtended)
    82	            implementation(compose.ui)
    83	            implementation(compose.components.resources)
    84	            implementation(compose.components.uiToolingPreview)
    85	            implementation(libs.androidx.lifecycle.viewmodelCompose)
    86	            implementation(libs.androidx.lifecycle.runtimeCompose)
    87	
    88	            // Koin DI
    89	            implementation(libs.koin.core)
    90	            implementation(libs.koin.compose)
    91	            implementation(libs.koin.compose.viewmodel)
    92	
    93	            // HTTP and serialization
    94	            implementation(libs.ktor.client.core)
    95	            implementation(libs.ktor.client.content.negotiation)
    96	            implementation(libs.ktor.serialization.kotlinx.json)
    97	            implementation(libs.kotlinx.serialization.json)
    98	            implementation(libs.kotlinx.coroutines.core)
    99	
   100	            // Logging

Script executed:

# Also check the root build.gradle.kts
cat -n build.gradle.kts | head -100

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

     1	plugins {
     2	    alias(libs.plugins.androidApplication) apply false
     3	    alias(libs.plugins.androidLibrary) apply false
     4	    alias(libs.plugins.composeHotReload) apply false
     5	    alias(libs.plugins.composeMultiplatform) apply false
     6	    alias(libs.plugins.composeCompiler) apply false
     7	    alias(libs.plugins.kotlinMultiplatform) apply false
     8	}

Script executed:

# Let's look at the flatpak directory structure
find composeApp/src/jvmMain/resources/flatpak -type f

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

composeApp/src/jvmMain/resources/flatpak/app_icon.png
composeApp/src/jvmMain/resources/flatpak/manifest.yml
composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.appdata.xml
composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.desktop
composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.yml

Script executed:

# Check if there's any documentation or comments about the manifest renaming
grep -r "manifest\|appId" composeApp/src/jvmMain/resources/flatpak/ 2>/dev/null

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

composeApp/src/jvmMain/resources/flatpak/manifest.yml:          - manifest.yml

Script executed:

# Check the appdata.xml file to see what component type is declared
cat composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.appdata.xml

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
    <id>zed.rainxch.githubstore</id>
    <metadata_license>CC0-1.0</metadata_license>
    <project_license>Apache-2.0</project_license>
    <name>GitHub Store</name>
    <summary>A cross-platform app store for GitHub releases</summary>
    <description>
        <p>GitHub Store is a cross-platform "play store" for GitHub releases. It discovers repositories that ship real installable binaries and lets you install, track, and update them across platforms from one place.</p>
        <p>Key Features:</p>
        <ul>
            <li>Smart discovery with Trending, Recently Updated, and New sections</li>
            <li>Only shows repositories with installable assets (APK, EXE, DMG, AppImage, DEB, RPM, etc.)</li>
            <li>Platform-aware filtering - automatically detects and shows installers for your OS</li>
            <li>Always installs from the latest published release with changelog preview</li>
            <li>Rich app details with README rendering, statistics, and developer info</li>
            <li>GitHub OAuth login for higher API rate limits</li>
            <li>Material 3 design with dynamic color support and dark mode</li>
            <li>Cross-platform support for Android and Desktop (Windows, macOS, Linux)</li>
        </ul>
        <p>Built with Kotlin Multiplatform and Compose Multiplatform for a consistent experience across all platforms.</p>
    </description>
    <developer id="zed.rainxch">
        <name>rainxchzed</name>
    </developer>
    <url type="homepage">https://github.com/rainxchzed/Github-Store</url>
    <url type="bugtracker">https://github.com/rainxchzed/Github-Store/issues</url>
    <url type="vcs-browser">https://github.com/rainxchzed/Github-Store</url>
    <url type="contribute">https://github.com/rainxchzed/Github-Store/blob/main/CONTRIBUTING.md</url>
    <url type="donation">https://github.com/sponsors/rainxchzed</url>
    <launchable type="desktop-id">zed.rainxch.githubstore.desktop</launchable>
    <provides>
        <binary>GitHub-Store</binary>
    </provides>
    <categories>
        <category>Development</category>
        <category>Utility</category>
    </categories>
    <keywords>
        <keyword>github</keyword>
        <keyword>releases</keyword>
        <keyword>app store</keyword>
        <keyword>package manager</keyword>
        <keyword>installer</keyword>
    </keywords>
    <content_rating type="oars-1.1">
        <content_attribute id="social-info">moderate</content_attribute>
    </content_rating>
    <releases>
        <release version="1.5.1" date="2026-01-10">
            <description>
                <p>A quality-of-life update focused on smoother navigation, smarter syncing, and richer localization.</p>
                <p>Highlights:</p>
                <ul>
                    <li>New liquid bottom navigation bar for a more fluid and modern experience</li>
                    <li>Favorites and feedback features on the details screen</li>
                    <li>Smarter data migration and improved system sync for better state alignment</li>
                    <li>New language support: Korean, Bengali, and Italian</li>
                    <li>Improved translations and localized theme options</li>
                    <li>Home screen refactored for better maintainability</li>
                    <li>Enhanced search experience with polished input behavior</li>
                    <li>Authentication improvements for more reliable sign-in</li>
                    <li>Fixed Android update issues</li>
                </ul>
            </description>
            <url>https://github.com/rainxchzed/Github-Store/releases/tag/1.5.1</url>
        </release>
    </releases>
</component>

Script executed:

# Check the desktop file as well for context
cat composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.desktop

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

[Desktop Entry]
Version=1.0
Type=Application
Categories=Development;
Terminal=false
Exec=GitHub-Store %U
Name=GitHub Store
Comment=Discover and install apps from GitHub releases
Icon=zed.rainxch.githubstore
StartupWMClass=GitHub-Store

Script executed:

# Check the source-based manifest to understand the two-manifest approach
cat composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.yml

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

app-id: zed.rainxch.githubstore
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
  - org.freedesktop.Sdk.Extension.openjdk21
command: GitHub-Store
finish-args:
  # Network access for GitHub API
  - --share=network
  # Required for X11/Wayland GUI applications
  - --share=ipc
  # Display server access - supports both X11 and Wayland
  - --socket=x11
  - --socket=wayland
  # GPU acceleration
  - --device=dri
  # File system access for downloads
  - --filesystem=xdg-download
  # Ensures compatibility across different display configurations
  - --env=GDK_BACKEND=x11,wayland
modules:
  - name: githubstore
    buildsystem: simple
    build-options:
      append-path: /usr/lib/sdk/openjdk21/bin
      env:
        JAVA_HOME: /usr/lib/sdk/openjdk21
    sources:
      - type: git
        url: https://github.com/rainxchzed/Github-Store.git
        tag: 1.5.1
      # TODO: Paste the contents of generated-sources.json here as a YAML list
      # Generate it using: flatpak-builder-tools/gradle/flatpak-gradle-generator.py
      # Example format:
      # - type: file
      #   url: https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar
      #   sha256: abc123...
      #   dest: gradle-cache/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/2.1.0/
      #   dest-filename: kotlin-stdlib-2.1.0.jar
      - type: file
        path: zed.rainxch.githubstore.desktop
      - type: file
        path: app_icon.png
      - type: file
        path: zed.rainxch.githubstore.appdata.xml
    build-commands:
      - chmod +x gradlew
      - export GRADLE_USER_HOME=$PWD/.gradle
      - ./gradlew --offline --no-daemon packageAppImage
      - mkdir -p /app/bin /app/lib
      - cp -r composeApp/build/compose/binaries/main/app/GitHub-Store/bin/* /app/bin/
      - cp -r composeApp/build/compose/binaries/main/app/GitHub-Store/lib/* /app/lib/
      - install -D zed.rainxch.githubstore.desktop /app/share/applications/zed.rainxch.githubstore.desktop
      - install -D app_icon.png /app/share/icons/hicolor/512x512/apps/zed.rainxch.githubstore.png
      - install -Dm644 zed.rainxch.githubstore.appdata.xml /app/share/metainfo/zed.rainxch.githubstore.metainfo.xml

Script executed:

# Check if there's any Gradle task or configuration that renames manifest files
grep -r "manifest" composeApp/build.gradle.kts | head -20

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

        include("manifest.yml", "*.desktop", "*.xml")
    rename("manifest.yml", "$appId.yml")

Script executed:

# Search the entire codebase for any manifest renaming logic
rg "manifest\.(yml|yaml)" --type gradle --type kotlin -A 3 -B 3

Repository: rainxchzed/Github-Store


Repository: rainxchzed/Github-Store
Exit code: 0

stdout:

composeApp/build.gradle.kts-    val resourcesDir = layout.projectDirectory.dir("src/jvmMain/resources/flatpak")
composeApp/build.gradle.kts-
composeApp/build.gradle.kts-    from(resourcesDir) {
composeApp/build.gradle.kts:        include("manifest.yml", "*.desktop", "*.xml")
composeApp/build.gradle.kts-    }
composeApp/build.gradle.kts-    into(flatpakDir.map { it.asFile.resolve("build") })
composeApp/build.gradle.kts-
composeApp/build.gradle.kts:    rename("manifest.yml", "$appId.yml")
composeApp/build.gradle.kts-}
composeApp/build.gradle.kts-
composeApp/build.gradle.kts-tasks.register<Exec>("packageFlatpak") {

Remove the double-slash from the sdk field: org.freedesktop.Sdk//25.08org.freedesktop.Sdk.

Flatpak manifests use separate fields for sdk (the SDK name) and runtime-version (the version). The syntax org.freedesktop.Sdk//25.08 is invalid and will cause flatpak-builder to reject the manifest.

🤖 Prompt for AI Agents
In @composeApp/src/jvmMain/resources/flatpak/manifest.yml around lines 1 - 32,
The sdk field currently uses an invalid double-slash syntax
("org.freedesktop.Sdk//25.08"); edit the manifest to set sdk to
"org.freedesktop.Sdk" (remove the "//25.08") and keep the runtime-version field
as '25.08' so Flatpak recognizes the SDK and version separately; update the sdk
value in the manifest entry where sdk is defined.

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>zed.rainxch.githubstore</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>Apache-2.0</project_license>
<name>GitHub Store</name>
<summary>A cross-platform app store for GitHub releases</summary>
<description>
<p>GitHub Store is a cross-platform "play store" for GitHub releases. It discovers repositories that ship real installable binaries and lets you install, track, and update them across platforms from one place.</p>
<p>Key Features:</p>
<ul>
<li>Smart discovery with Trending, Recently Updated, and New sections</li>
<li>Only shows repositories with installable assets (APK, EXE, DMG, AppImage, DEB, RPM, etc.)</li>
<li>Platform-aware filtering - automatically detects and shows installers for your OS</li>
<li>Always installs from the latest published release with changelog preview</li>
<li>Rich app details with README rendering, statistics, and developer info</li>
<li>GitHub OAuth login for higher API rate limits</li>
<li>Material 3 design with dynamic color support and dark mode</li>
<li>Cross-platform support for Android and Desktop (Windows, macOS, Linux)</li>
</ul>
<p>Built with Kotlin Multiplatform and Compose Multiplatform for a consistent experience across all platforms.</p>
</description>
<developer id="zed.rainxch">
<name>rainxchzed</name>
</developer>
<url type="homepage">https://github.com/rainxchzed/Github-Store</url>
<url type="bugtracker">https://github.com/rainxchzed/Github-Store/issues</url>
<url type="vcs-browser">https://github.com/rainxchzed/Github-Store</url>
<url type="contribute">https://github.com/rainxchzed/Github-Store/blob/main/CONTRIBUTING.md</url>
<url type="donation">https://github.com/sponsors/rainxchzed</url>
<launchable type="desktop-id">zed.rainxch.githubstore.desktop</launchable>
<provides>
<binary>GitHub-Store</binary>
</provides>
<categories>
<category>Development</category>
<category>Utility</category>
</categories>
<keywords>
<keyword>github</keyword>
<keyword>releases</keyword>
<keyword>app store</keyword>
<keyword>package manager</keyword>
<keyword>installer</keyword>
</keywords>
<content_rating type="oars-1.1">
<content_attribute id="social-info">moderate</content_attribute>
</content_rating>
<releases>
<release version="1.5.1" date="2026-01-10">
<description>
<p>A quality-of-life update focused on smoother navigation, smarter syncing, and richer localization.</p>
<p>Highlights:</p>
<ul>
<li>New liquid bottom navigation bar for a more fluid and modern experience</li>
<li>Favorites and feedback features on the details screen</li>
<li>Smarter data migration and improved system sync for better state alignment</li>
<li>New language support: Korean, Bengali, and Italian</li>
<li>Improved translations and localized theme options</li>
<li>Home screen refactored for better maintainability</li>
<li>Enhanced search experience with polished input behavior</li>
<li>Authentication improvements for more reliable sign-in</li>
<li>Fixed Android update issues</li>
</ul>
</description>
<url>https://github.com/rainxchzed/Github-Store/releases/tag/1.5.1</url>
</release>
</releases>
</component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Categories=Development;
Terminal=false
Exec=GitHub-Store %U
Name=GitHub Store
Comment=Discover and install apps from GitHub releases
Icon=zed.rainxch.githubstore
StartupWMClass=GitHub-Store
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
app-id: zed.rainxch.githubstore
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.openjdk21
command: GitHub-Store
finish-args:
# Network access for GitHub API
- --share=network
# Required for X11/Wayland GUI applications
- --share=ipc
# Display server access - supports both X11 and Wayland
- --socket=x11
- --socket=wayland
# GPU acceleration
- --device=dri
# File system access for downloads
- --filesystem=xdg-download
# Ensures compatibility across different display configurations
- --env=GDK_BACKEND=x11,wayland
modules:
- name: githubstore
buildsystem: simple
build-options:
append-path: /usr/lib/sdk/openjdk21/bin
env:
JAVA_HOME: /usr/lib/sdk/openjdk21
sources:
- type: git
url: https://github.com/rainxchzed/Github-Store.git
tag: 1.5.1
# TODO: Paste the contents of generated-sources.json here as a YAML list
# Generate it using: flatpak-builder-tools/gradle/flatpak-gradle-generator.py
# Example format:
# - type: file
# url: https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar
# sha256: abc123...
# dest: gradle-cache/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/2.1.0/
# dest-filename: kotlin-stdlib-2.1.0.jar
- type: file
path: zed.rainxch.githubstore.desktop
- type: file
path: app_icon.png
- type: file
path: zed.rainxch.githubstore.appdata.xml
build-commands:
- chmod +x gradlew
- export GRADLE_USER_HOME=$PWD/.gradle
- ./gradlew --offline --no-daemon packageAppImage
- mkdir -p /app/bin /app/lib
- cp -r composeApp/build/compose/binaries/main/app/GitHub-Store/bin/* /app/bin/
- cp -r composeApp/build/compose/binaries/main/app/GitHub-Store/lib/* /app/lib/
- install -D zed.rainxch.githubstore.desktop /app/share/applications/zed.rainxch.githubstore.desktop
- install -D app_icon.png /app/share/icons/hicolor/512x512/apps/zed.rainxch.githubstore.png
- install -Dm644 zed.rainxch.githubstore.appdata.xml /app/share/metainfo/zed.rainxch.githubstore.metainfo.xml
Comment on lines +1 to +56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

org.freedesktop.Platform runtime version 25.08

💡 Result:

org.freedesktop.Platform 25.08 is the Freedesktop (Flatpak) runtime from the Freedesktop SDK 25.08 release (major release for 2025). It was published as part of Freedesktop SDK 25.08 (release announced Sept 3, 2025) and introduces several breaking/behavior changes (e.g., openh264/ffmpeg-full replaced by codecs-extra, removal/replacements of some drivers and packages). [1][2][3]

Quick actions:

  • Install runtime (example): flatpak install org.freedesktop.Platform//25.08. [1]
  • See full SDK NEWS/release notes for detailed changes and migration guidance. [1][3]

Sources:
[1] Flathub Discourse — “Freedesktop SDK 25.08.0 released!” (announcement).
[2] Flatpak docs — “Available Runtimes” (freedesktop runtime description).
[3] Freedesktop SDK — Release notes / NEWS for 25.08.


🌐 Web query:

Flathub org.freedesktop.Platform 25.08 support

💡 Result:

Short answer: Yes — the Freedesktop org.freedesktop.Platform 25.08 runtime is available on Flathub and is a supported/current Freedesktop runtime. Install with flatpak (example):

  • flatpak install flathub org.freedesktop.Platform//25.08
  • flatpak install flathub org.freedesktop.Sdk//25.08

Sources: Flathub runtime pages and release notes, and Flatpak runtime documentation. [1][2][3]

References

  • Flathub org.freedesktop.Platform / Sdk pages (release notes). [1]
  • Freedesktop SDK app page on Flathub. [2]
  • Flatpak “Available Runtimes” (release schedule / support policy). [3]

🌐 Web query:

Flatpak gradle offline build vendored dependencies

💡 Result:

Short answer: you must vendor all Maven/Gradle artifacts into your Flatpak manifest (or into a local repo included as a source) and make Gradle use only that local repo / its cache during the build. Flatpak builds disallow network access, so fetching from Maven Central at build time is not permitted — either generate Flatpak "sources" for each dependency or include a pre-built local Maven/Gradle cache and point your build to it. [1][2][3][4]

Recommended approaches (concise):

  • Use the flatpak-gradle-generator plugin to generate a Flatpak sources file (it harvests your Gradle dependencies and produces sources entries you can include in the manifest). Add the generated sources to the manifest so flatpak-builder downloads/copies them before build. [1]

  • Vendor a local Maven repository inside the manifest:

    • Produce a directory containing all required artifacts/POMs (a local Maven repo or a flatDir).
    • Add that directory as a module/source in the manifest (type=file/archive or path), and in build.gradle declare a repository using file:// or layout path to that directory (or maven { url uri("$projectDir/...") }). This makes Gradle resolve from the vendored repo offline. See Flatpak module-sources and Gradle local repo docs. [2][4]
  • Alternatively, pre-populate Gradle’s user cache (.gradle) as a source:

    • Build once externally to populate ~/.gradle/caches, tar that cache, add it as a source in the manifest, extract it to /run/build/.gradle (or $HOME/.gradle) in the build commands, and run Gradle with --offline. Note: plugins resolved via the plugins {} block may need explicit buildscript/classpath declarations so they resolve from the cache. Use Gradle’s --offline flag. [2][4]

Practical notes / gotchas:

  • Flatpak disallows network downloads during build; everything must be in the manifest/sources. [2][3]
  • The plugins { } DSL can still try to reach plugins.gradle.org; convert those plugin declarations to explicit buildscript classpath dependencies or vendor the plugin JARs so they resolve offline. [4]
  • Test by running gradle --offline in a clean build environment identical to the Flatpak build sandbox to ensure no remote access is required. [4]

Useful references:

  • flatpak-gradle-generator plugin (generates Flatpak sources from Gradle). [1]
  • Flatpak module sources / how sources are staged for builds. [2]
  • Flathub/Flatpak guidance: builds must be offline; either vendor deps or generate sources. [3]
  • Gradle docs on offline mode, caching, and local Maven repositories. [4]

If you want, tell me which build setup you have (single-module Kotlin/Java, Android, or multimodule) and I’ll give an exact manifest + Gradle repo snippet and a short workflow to produce the vendored sources.


Build will fail on Flathub: --offline requires the generated-sources.json TODO to be completed and embedded as vendored sources.

The manifest runs ./gradlew --offline ... but the generated-sources.json content (Maven URLs + sha256 hashes) has not yet been generated and added to sources:. Flatpak disallows network access during builds, so without vendored Maven/Gradle artifacts listed in the manifest, the offline flag will cause the build to fail in the Flathub sandbox.

Complete the TODO using flatpak-builder-tools/gradle/flatpak-gradle-generator.py to extract all Gradle dependencies, then paste the generated sources list into the manifest before submission.

🤖 Prompt for AI Agents
In @composeApp/src/jvmMain/resources/flatpak/zed.rainxch.githubstore.yml around
lines 1 - 56, Run flatpak-builder-tools/gradle/flatpak-gradle-generator.py
against your project to produce the generated-sources.json list of Maven/Gradle
artifacts, then paste that generated list into the manifest's sources: section
in place of the TODO so each dependency entry (with url, sha256, dest and
dest-filename) is vendored; keep the manifest's ./gradlew --offline build
command only after confirming all required entries from generated-sources.json
are present, or remove --offline if you cannot vendor everything.