diff --git a/android/app/build.gradle b/android/app/build.gradle index eb2f631..a83001d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -5,6 +5,7 @@ plugins { def repoRoot = rootProject.projectDir.parentFile def meshchatSourceDir = new File(repoRoot, "meshchatx") +def repositoryBundledWheelsDir = new File(meshchatSourceDir, "public/repository-server-bundled/bundled") def chaquopyBuildPython = System.getenv("CHAQUOPY_BUILD_PYTHON") def pythonTempDir = new File(buildDir, "python-tmp") def vendorWheelDir = new File(rootProject.projectDir, "vendor") @@ -23,12 +24,35 @@ def invalidAndroidAbis = selectedAndroidAbis.findAll { !allAndroidAbis.contains( if (!invalidAndroidAbis.isEmpty()) { throw new org.gradle.api.GradleException("Unsupported ABIs: ${invalidAndroidAbis}. Supported: ${allAndroidAbis}") } -def enableAbiSplits = selectedAndroidAbis.size() > 1 + +def meshchatxAbiPackaging = ( + project.findProperty("meshchatxAbiPackaging") + ?: System.getenv("MESHCHATX_ABI_PACKAGING") + ?: "universal" +).toString().trim().toLowerCase() +if (meshchatxAbiPackaging != "universal" && meshchatxAbiPackaging != "split") { + throw new org.gradle.api.GradleException( + "meshchatxAbiPackaging must be 'universal' or 'split' (got '${meshchatxAbiPackaging}'). " + + "Use -PmeshchatxAbiPackaging=... or MESHCHATX_ABI_PACKAGING." + ) +} +def enableAbiSplits = meshchatxAbiPackaging == "split" && selectedAndroidAbis.size() > 1 android { namespace 'com.meshchatx' compileSdk 34 + flavorDimensions "pythonBundle" + productFlavors { + slim { + dimension "pythonBundle" + isDefault true + } + full { + dimension "pythonBundle" + } + } + defaultConfig { applicationId "com.meshchatx" minSdk 24 @@ -73,30 +97,64 @@ android { } } -tasks.register("syncMeshchatPython", Sync) { - if (!meshchatSourceDir.exists()) { - throw new org.gradle.api.GradleException("Missing meshchatx source directory at ${meshchatSourceDir}") +tasks.register("fetchRepositoryBundledWheels", Exec) { + workingDir = repoRoot + def pyExe = (System.getenv("MESHCHATX_FETCH_PYTHON") ?: "python3") + commandLine(pyExe, "scripts/build/fetch_repository_wheels.py") + ignoreExitValue = false + onlyIf { + if (System.getenv("MESHCHATX_SKIP_REPOSITORY_WHEELS_FETCH") == "1") { + return false + } + if (!repositoryBundledWheelsDir.isDirectory()) { + return true + } + def names = repositoryBundledWheelsDir.list() + return names == null || !names.any { it.endsWith(".whl") } } - doFirst { - // Remove legacy vendored packages so pip-installed dependencies are used. - delete( - file("$projectDir/src/main/python/LXST"), - file("$projectDir/src/main/python/LXMF"), - file("$projectDir/src/main/python/RNS") - ) - } - from(meshchatSourceDir) - includeEmptyDirs = false - into(file("$projectDir/src/main/python/meshchatx")) } -tasks.named("preBuild") { - dependsOn(tasks.named("syncMeshchatPython")) +def registerMeshchatPythonSync = { String bundle -> + def cap = bundle.capitalize() + tasks.register("syncMeshchatPython${cap}", Sync) { + if (bundle == "full") { + dependsOn("fetchRepositoryBundledWheels") + } + if (!meshchatSourceDir.exists()) { + throw new org.gradle.api.GradleException("Missing meshchatx source directory at ${meshchatSourceDir}") + } + doFirst { + delete( + file("$projectDir/src/main/python/meshchatx"), + file("$projectDir/src/main/python/LXST"), + file("$projectDir/src/main/python/LXMF"), + file("$projectDir/src/main/python/RNS") + ) + } + from(meshchatSourceDir) { + if (bundle == "slim") { + exclude("src/frontend/**") + exclude("public/reticulum-docs-bundled/**") + exclude("public/rnode-flasher/**") + exclude("public/repository-server-bundled/**") + } + } + includeEmptyDirs = false + from(new File(repoRoot, "CHANGELOG.md")) + into(file("$projectDir/src/${bundle}/python/meshchatx")) + } } +registerMeshchatPythonSync("slim") +registerMeshchatPythonSync("full") + tasks.configureEach { task -> if (task.name.toLowerCase().contains("merge") && task.name.toLowerCase().contains("pythonsources")) { - task.dependsOn(tasks.named("syncMeshchatPython")) + if (task.name.contains("Slim")) { + task.dependsOn(tasks.named("syncMeshchatPythonSlim")) + } else if (task.name.contains("Full")) { + task.dependsOn(tasks.named("syncMeshchatPythonFull")) + } } } @@ -128,6 +186,7 @@ chaquopy { throw new org.gradle.api.GradleException("Missing vendor wheel directory at ${vendorWheelDir}") } options "--find-links", vendorWheelDir.absolutePath + install "packaging>=23" install "aiohttp==3.13.3" install "rns>=1.1.5" install "lxmf>=0.9.4" @@ -163,4 +222,3 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' } -