7
mavenCentral()
8
}
9
dependencies {
10
- classpath 'com.android.tools.build:gradle:7.3.0'
10
+ classpath 'com.android.tools.build:gradle:8.7.3'
11
}
12
}
13
20
21
apply plugin: 'com.android.library'
22
23
+// ── ABIs to cross-compile ────────────────────────────────────────────────────
24
+// Override from the consuming app to shorten local iteration, e.g.
25
+// flutter run -d <device> --android-project-arg=onde.androidAbis=arm64-v8a
26
+def ondeAndroidAbis = (project.findProperty('onde.androidAbis') ?: 'arm64-v8a,armeabi-v7a,x86_64')
27
+ .split(',')
28
+ .collect { it.trim() }
29
+ .findAll { !it.isEmpty() }
30
+
31
+// Lowest API level the Rust code is linked against. Must stay <= the consuming
32
+// app's minSdk, and matches defaultConfig.minSdkVersion below.
33
+def ondeAndroidApiLevel = 21
34
+
35
android {
24
- compileSdkVersion 33
36
+ compileSdkVersion 35
37
+ namespace 'com.ondeinference.onde_inference'
38
39
defaultConfig {
27
- minSdkVersion 21
40
+ minSdkVersion ondeAndroidApiLevel
41
+ }
42
29
- externalNativeBuild {
30
- cmake {
31
- cppFlags '-std=c++17'
32
- arguments '-DANDROID_STL=c++_shared'
33
- }
43
+ compileOptions {
44
+ sourceCompatibility JavaVersion.VERSION_17
45
+ targetCompatibility JavaVersion.VERSION_17
46
+ }
47
+
48
+ // cargo-ndk drops libonde_inference_dart.so into <abi>/ subdirectories here.
49
+ // AGP packages anything under a jniLibs source dir, which an IMPORTED CMake
50
+ // library would *not* have been.
51
+ sourceSets {
52
+ main {
53
+ jniLibs.srcDirs += ["${layout.buildDirectory.get().asFile}/rustJniLibs"]
54
}
55
}
56
+}
57
+
58
+// ── NDK location ─────────────────────────────────────────────────────────────
59
+// `android.ndkDirectory` is deliberately not used: this is a library module
60
+// with no ndkVersion of its own, so AGP resolves its own default version and
61
+// throws "NDK is not installed" even when the app module has just installed a
62
+// perfectly good NDK. Resolve it ourselves instead.
63
+def resolveNdkDir = {
64
+ def fromEnv = System.getenv('ANDROID_NDK_HOME') ?: System.getenv('ANDROID_NDK_ROOT')
65
+ if (fromEnv && new File(fromEnv).isDirectory()) {
66
+ return new File(fromEnv)
67
+ }
68
37
- externalNativeBuild {
38
- cmake {
39
- path 'CMakeLists.txt'
40
- version '3.18.1'
69
+ def sdkRoot = System.getenv('ANDROID_HOME') ?: System.getenv('ANDROID_SDK_ROOT')
70
+ if (sdkRoot) {
71
+ def ndkRoot = new File(sdkRoot, 'ndk')
72
+ def installed = ndkRoot.isDirectory() ? ndkRoot.listFiles({ it.isDirectory() } as FileFilter) : null
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 ->
78
+ dir.name.split('\\.').collect { it.isInteger() ? it.toInteger() : 0 }
79
+ }
80
+ if (newest) {
81
+ return newest
82
+ }
83
}
84
}
85
44
- namespace 'com.ondeinference.onde_inference'
86
+ throw new GradleException(
87
+ 'Could not locate an Android NDK. Install one via Android Studio\'s SDK ' +
88
+ 'Manager, or set ANDROID_NDK_HOME to an NDK directory.')
89
+}
90
+
91
+// ── Rust cross-compilation ───────────────────────────────────────────────────
92
+// Always built with --release: a debug-profile inference engine is too slow to
93
+// be worth running, so there is no point wiring this per build type.
94
+tasks.register('cargoBuildAndroid', Exec) {
95
+ description = "Cross-compiles the onde_inference_dart crate for ${ondeAndroidAbis.join(', ')}"
96
+ workingDir file('../rust')
97
+
98
+ def outDir = file("${layout.buildDirectory.get().asFile}/rustJniLibs")
99
+
100
+ // Gradle launched from Android Studio does not necessarily inherit the
101
+ // shell PATH, so fall back to the standard rustup install location.
102
+ def cargoBin = 'cargo'
103
+ def rustupCargo = new File("${System.getProperty('user.home')}/.cargo/bin/cargo")
104
+ if (rustupCargo.exists()) {
105
+ cargoBin = rustupCargo.absolutePath
106
+ }
107
+
108
+ def cargoArgs = [cargoBin, 'ndk']
109
+ ondeAndroidAbis.each { cargoArgs += ['-t', it] }
110
+ cargoArgs += ['-P', ondeAndroidApiLevel.toString(), '-o', outDir.absolutePath, 'build', '--release']
111
+ commandLine cargoArgs
112
+
113
+ doFirst {
114
+ outDir.mkdirs()
115
+ // cargo-ndk locates the toolchain via ANDROID_NDK_HOME.
116
+ environment 'ANDROID_NDK_HOME', resolveNdkDir().absolutePath
117
+ }
118
+}
119
+
120
+tasks.configureEach { task ->
121
+ if (task.name == 'preBuild') {
122
+ task.dependsOn 'cargoBuildAndroid'
123
+ }
124
}