@ondeinference / onde / commits / cb34259

Fix NDK version comparison and native lib task ordering

Review feedback from siGit on #11, all three points. The version comparison was a real bug, and it fails harder than the review suggested. Groovy's single-argument max transform compared the returned ArrayLists directly, and ArrayList is not Comparable, so it threw "Cannot compare java.util.ArrayList with value '[9, 0, 1]' and java.util.ArrayList with value '[26, 1, 10909125]'" rather than picking the wrong NDK. Any machine with two or more NDKs installed and no ANDROID_NDK_HOME set would have died in cargoBuildAndroid. The earlier builds passed only because that env var is set locally, so resolveNdkDir short-circuited before ever reaching this code. Replaced with an explicit two-argument comparator doing segment-wise integer comparison, checked against 9 vs 26, reversed input order, three real NDK versions, and a short segment list. preBuild only ordered cargo early in the build. What has to hold is that the .so files exist before AGP merges native libs, and those merge tasks are created late by the variant API, so depend on them from afterEvaluate instead of assuming preBuild covers it. The README said "all three ABIs" next to a table that used to list four, which read as a leftover from dropping x86. Name them instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: siGit Code <297239231+sigitc@users.noreply.github.com>

Seto Elkahfi committed Aug 17, 2026 at 21:06 UTC cb34259927a66dd58a84c246121614557d4b541e
2 files changed +31 -7
sdk/dart/README.md
+3 -2
@@ -279,8 +279,9 @@ rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-and
279 The NDK comes from whichever version Gradle already resolved, so no
280 `ANDROID_NDK_HOME` export is needed for Gradle-driven builds.
281
282 -By default all three ABIs are built, which is slow — the engine is a large
283 -release-profile crate. While iterating, build only the one your device needs:
282 +Unless you say otherwise, all three default ABIs are built: arm64-v8a,
283 +armeabi-v7a, and x86_64. Each is a full release build of a large crate, so this
284 +is slow. While iterating, build only the one your device needs:
285
286 ```bash
287 flutter run -d <device> --android-project-arg=onde.androidAbis=arm64-v8a
sdk/dart/android/build.gradle
+28 -5
@@ -73,10 +73,26 @@ def resolveNdkDir = {
73 if (installed) {
74 // Newest installed version wins. The Rust output is a standalone
75 // .so, so it need not match the NDK the Flutter engine was built
76 - // with — any recent one links fine.
77 - def newest = installed.toList().max { dir ->
76 + // with: any recent one links fine.
77 + //
78 + // Directory names are dotted versions like "26.1.10909125".
79 + // Compare them segment by segment as integers rather than leaning
80 + // on Groovy's implicit list ordering, so "9.x" cannot outrank
81 + // "26.x" and a missing trailing segment counts as zero.
82 + def versionOf = { File dir ->
83 dir.name.split('\\.').collect { it.isInteger() ? it.toInteger() : 0 }
84 }
85 + def newest = installed.toList().max { a, b ->
86 + def va = versionOf(a)
87 + def vb = versionOf(b)
88 + for (int i = 0; i < Math.max(va.size(), vb.size()); i++) {
89 + def cmp = (va[i] ?: 0) <=> (vb[i] ?: 0)
90 + if (cmp != 0) {
91 + return cmp
92 + }
93 + }
94 + return 0
95 + }
96 if (newest) {
97 return newest
98 }
@@ -117,8 +133,15 @@ tasks.register('cargoBuildAndroid', Exec) {
133 }
134 }
135
120 -tasks.configureEach { task ->
121 - if (task.name == 'preBuild') {
122 - task.dependsOn 'cargoBuildAndroid'
136 +// preBuild on its own only orders the cargo run early in the build. What
137 +// actually matters is that the .so files exist before AGP merges native libs,
138 +// and those merge tasks are created late by the variant API, so match them
139 +// after evaluation rather than assuming preBuild covers it.
140 +afterEvaluate {
141 + tasks.matching { it.name == 'preBuild' }.configureEach {
142 + dependsOn 'cargoBuildAndroid'
143 + }
144 + tasks.matching { it.name ==~ /merge.*(NativeLibs|JniLibFolders)/ }.configureEach {
145 + dependsOn 'cargoBuildAndroid'
146 }
147 }