From 9c133f8bd91acdb83bb69f73cd805fa7dbe67669 Mon Sep 17 00:00:00 2001 From: matthieu-db Date: Mon, 23 Jun 2025 20:30:39 +0200 Subject: [PATCH 01/22] Update mavsdk-server to 3.6.0 (#208) * Update mavsdk-server * Fix 3.0.0 update oversights Closes #203 * Update README for mavsdk-server 3.1.0 * Update proto for mavsdk 3.6.0 --------- Co-authored-by: Matthieu <170411151+matthieu-db@users.noreply.github.com> --- README.md | 2 +- mavsdk_server/build.gradle | 8 ++--- mavsdk_server/src/main/cpp/native-lib.cpp | 9 +++--- .../io/mavsdk/mavsdkserver/MavsdkServer.java | 32 ++++++++++++------- sdk/proto | 2 +- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d188a30..2a3d3cf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ For Android, `mavsdk_server` is distributed as an Android library (`aar`): dependencies { ... implementation 'io.mavsdk:mavsdk:3.0.0' - implementation 'io.mavsdk:mavsdk-server:3.0.0' + implementation 'io.mavsdk:mavsdk-server:3.1.0' ... } ``` diff --git a/mavsdk_server/build.gradle b/mavsdk_server/build.gradle index 3c8437d..175e178 100644 --- a/mavsdk_server/build.gradle +++ b/mavsdk_server/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.10.0' + classpath 'com.android.tools.build:gradle:8.10.1' } } @@ -19,7 +19,7 @@ allprojects { mavenCentral() } - def mavsdk_server_release = "v3.5.0" + def mavsdk_server_release = "v3.6.0" tasks.register('extractMavsdkServer', Copy) { mkdir project.buildDir.getAbsolutePath() + "/tmp" @@ -124,7 +124,7 @@ android { archivesBaseName = 'mavsdk-server' group = 'io.mavsdk' versionCode 3 - version '3.0.0' + version '3.1.0' ndk { abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' @@ -150,6 +150,6 @@ android { } } - ndkVersion "25.1.8937393" + ndkVersion "28.0.13004108" namespace 'io.mavsdk.mavsdkserver' } diff --git a/mavsdk_server/src/main/cpp/native-lib.cpp b/mavsdk_server/src/main/cpp/native-lib.cpp index f5e89d0..2812582 100644 --- a/mavsdk_server/src/main/cpp/native-lib.cpp +++ b/mavsdk_server/src/main/cpp/native-lib.cpp @@ -18,7 +18,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_io_mavsdk_mavsdkserver_MavsdkServer_runNative(JNIEnv* env, jobject thiz, jlong mavsdkServerHandle, jstring system_address, jint mavsdk_server_port) { - const char* native_connection_url = env->GetStringUTFChars(system_address, 0); + const char* native_connection_url = env->GetStringUTFChars(system_address, nullptr); auto mavsdk_server = reinterpret_cast(mavsdkServerHandle); LOGD("Running mavsdk_server with connection url: %s", native_connection_url); @@ -36,14 +36,15 @@ extern "C" JNIEXPORT jboolean JNICALL Java_io_mavsdk_mavsdkserver_MavsdkServer_runNativeWithMavIds(JNIEnv* env, jobject thiz, jlong mavsdkServerHandle, jstring system_address, jint mavsdk_server_port, jint system_id, jint component_id) { - const char* native_connection_url = env->GetStringUTFChars(system_address, 0); + const char* native_connection_url = env->GetStringUTFChars(system_address, nullptr); auto mavsdk_server = reinterpret_cast(mavsdkServerHandle); LOGD("Running mavsdk_server with connection url: %s", native_connection_url); - if (!mavsdk_server_run_with_mavlink_ids(mavsdk_server, native_connection_url, mavsdk_server_port, system_id, component_id)) { + auto result = mavsdk_server_run_with_mavlink_ids(mavsdk_server, native_connection_url, mavsdk_server_port, system_id, component_id); + if (result != 0) { + LOGD("Failed to start mavsdk_server: %d", result); return false; } - auto server_port = mavsdk_server_get_port(mavsdk_server); LOGD("mavsdk_server is now running, listening on port %d", server_port); return true; diff --git a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java index bc74f33..5ab6004 100644 --- a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java +++ b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java @@ -9,7 +9,7 @@ public class MavsdkServer { private long mavsdkServerHandle; /** - * Run MavsdkServer with MAVLink defaulting to udp://:14540. + * Run MavsdkServer with MAVLink defaulting to udpin://:14540. * *

MavsdkServer will start a gRPC server listening on an * arbitrary port, to which a `System` should connect.

@@ -18,7 +18,7 @@ public class MavsdkServer { * A return value of 0 means that the server failed to start. */ public int run() { - return run("udp://:14540"); + return run("udpin://:14540"); } /** @@ -29,9 +29,12 @@ public int run() { * * @param systemAddress The address on which the remote MAVLink system is expected. * Valid formats are: - * For TCP : tcp://[server_host][:server_port]. - * For UDP : udp://[bind_host][:bind_port]. - * For Serial : serial:///path/to/serial/dev[:baudrate]. + * UDP in (server): udpin://our_ip:port + * UDP out (client): udpout://remote_ip:port + * TCP in (server): tcpin://our_ip:port + * TCP out (client): tcpout://remote_ip:port + * Serial: serial://dev_node:baudrate + * Serial with flow control: serial_flowcontrol://dev_node:baudrate * @return The port on which MavsdkServer listens for a `System` to connect. * A return value of 0 means that the server failed to start. */ @@ -46,9 +49,12 @@ public int run(String systemAddress) { * * @param systemAddress The address on which the remote MAVLink system is expected. * Valid formats are: - * For TCP : tcp://[server_host][:server_port] - * For UDP : udp://[bind_host][:bind_port] - * For Serial : serial:///path/to/serial/dev[:baudrate] + * UDP in (server): udpin://our_ip:port + * UDP out (client): udpout://remote_ip:port + * TCP in (server): tcpin://our_ip:port + * TCP out (client): tcpout://remote_ip:port + * Serial: serial://dev_node:baudrate + * Serial with flow control: serial_flowcontrol://dev_node:baudrate * @param mavsdkServerPort The port on which the server should listen for a `System`. * @return The port on which MavsdkServer listens for a `System` to connect. * A return value of 0 means that the server failed to start. @@ -69,10 +75,12 @@ public int run(String systemAddress, int mavsdkServerPort) { *

MavsdkServer will listen for a `System` to connect on `mavsdkServerPort`.

* * @param systemAddress The address on which the remote MAVLink system is expected. - * Valid formats are: - * For TCP : tcp://[server_host][:server_port] - * For UDP : udp://[bind_host][:bind_port] - * For Serial : serial:///path/to/serial/dev[:baudrate] + * UDP in (server): udpin://our_ip:port + * UDP out (client): udpout://remote_ip:port + * TCP in (server): tcpin://our_ip:port + * TCP out (client): tcpout://remote_ip:port + * Serial: serial://dev_node:baudrate + * Serial with flow control: serial_flowcontrol://dev_node:baudrate * @param mavsdkServerPort The port on which the server should listen for a `System`. * @param systemId The MAVLink sysid that MAVSDK should use. * @param componentId The MAVLink compid that MAVSDK should use. diff --git a/sdk/proto b/sdk/proto index e053eca..20aa335 160000 --- a/sdk/proto +++ b/sdk/proto @@ -1 +1 @@ -Subproject commit e053ecabc5b825bb9c831f3f31ab24ff727ce1e6 +Subproject commit 20aa335ef85b50d844ffb3d3a53420c6fbcc289b From 273c62a96bc1b4449d13b0a3b2713f354ef297b7 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 10 Jul 2025 13:47:36 +0200 Subject: [PATCH 02/22] Update to Gradle Kotlin DSL and use jreleaser --- .gitignore | 1 + mavsdk_server/build.gradle | 155 ------------ mavsdk_server/build.gradle.kts | 226 ++++++++++++++++++ mavsdk_server/gradle/libs.versions.toml | 9 + mavsdk_server/settings.gradle | 1 - mavsdk_server/settings.gradle.kts | 18 ++ sdk/build.gradle | 179 -------------- sdk/build.gradle.kts | 184 ++++++++++++++ sdk/gradle/libs.versions.toml | 9 + sdk/mavsdk/settings.gradle | 1 - .../src/test/java/io/mavsdk/MavsdkTest.java | 34 --- sdk/proto | 2 +- sdk/settings.gradle | 1 - sdk/settings.gradle.kts | 19 ++ .../main/java/io/mavsdk/MavsdkEventQueue.java | 0 .../main/java/io/mavsdk/MavsdkException.java | 0 .../src/main/java/io/mavsdk/Plugin.java | 0 .../src/main/java/io/mavsdk/System.java | 0 .../java/io/mavsdk/internal/LazyPlugin.java | 0 .../java/io/mavsdk/internal/Provider.java | 0 20 files changed, 467 insertions(+), 372 deletions(-) delete mode 100644 mavsdk_server/build.gradle create mode 100644 mavsdk_server/build.gradle.kts create mode 100644 mavsdk_server/gradle/libs.versions.toml delete mode 100644 mavsdk_server/settings.gradle create mode 100644 mavsdk_server/settings.gradle.kts delete mode 100644 sdk/build.gradle create mode 100644 sdk/build.gradle.kts create mode 100644 sdk/gradle/libs.versions.toml delete mode 100644 sdk/mavsdk/settings.gradle delete mode 100644 sdk/mavsdk/src/test/java/io/mavsdk/MavsdkTest.java delete mode 100644 sdk/settings.gradle create mode 100644 sdk/settings.gradle.kts rename sdk/{mavsdk => }/src/main/java/io/mavsdk/MavsdkEventQueue.java (100%) rename sdk/{mavsdk => }/src/main/java/io/mavsdk/MavsdkException.java (100%) rename sdk/{mavsdk => }/src/main/java/io/mavsdk/Plugin.java (100%) rename sdk/{mavsdk => }/src/main/java/io/mavsdk/System.java (100%) rename sdk/{mavsdk => }/src/main/java/io/mavsdk/internal/LazyPlugin.java (100%) rename sdk/{mavsdk => }/src/main/java/io/mavsdk/internal/Provider.java (100%) diff --git a/.gitignore b/.gitignore index 536d876..38197f9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build local.properties gradle.properties +keystore.properties .cxx venv diff --git a/mavsdk_server/build.gradle b/mavsdk_server/build.gradle deleted file mode 100644 index 175e178..0000000 --- a/mavsdk_server/build.gradle +++ /dev/null @@ -1,155 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.10.1' - } -} - -allprojects { - apply plugin: 'com.android.library' - apply plugin: 'maven-publish' - apply plugin: 'signing' - - repositories { - google() - mavenCentral() - } - - def mavsdk_server_release = "v3.6.0" - - tasks.register('extractMavsdkServer', Copy) { - mkdir project.buildDir.getAbsolutePath() + "/tmp" - - def extractForArch = { arch -> - def archiveName = "mavsdk_server_android-" + arch + "_" + mavsdk_server_release + ".tar" - def archiveFile = new File(project.buildDir.getAbsolutePath() + "/tmp/" + archiveName) - def archiveUrl = "https://github.com/mavlink/MAVSDK/releases/download/" + mavsdk_server_release + "/mavsdk_server_android-" + arch + ".tar" - def destDir = project.projectDir.getAbsolutePath() + "/src/main/prebuiltLibs" - - if (!archiveFile.exists()) { - project.logger.lifecycle("Downloading " + archiveFile.getName() + " into " + archiveFile.getAbsolutePath() + "...") - new URL(archiveUrl).withInputStream { i -> archiveFile.withOutputStream { it << i } } - } else { - project.logger.lifecycle("Archive already exists! Skipping download!") - } - - project.logger.lifecycle("Extracting into " + destDir) - copy { - from tarTree(archiveFile) - eachFile({ file -> if (file.getName().endsWith(".so")) file.setMode(0755) }) - into(destDir) - } - } - - extractForArch("arm64") - extractForArch("arm") - extractForArch("x86") - extractForArch("x86_64") - } - build.dependsOn extractMavsdkServer - - if (project.hasProperty('ossrhUsername') - && project.hasProperty('ossrhPassword')) { - afterEvaluate { - publishing { - publications { - release(MavenPublication) { - from components.release - - pom { - name = 'MAVSDK-Server' - packaging = 'aar' - description = 'MAVSDK server for Android.' - url = 'https://github.com/mavlink/MAVSDK-Java' - - scm { - connection = 'scm:git:https://github.com/mavlink/MAVSDK-Java' - developerConnection = 'scm:git:https://github.com/mavlink/MAVSDK-Java' - url = 'https://github.com/mavlink/MAVSDK-Java' - } - - licenses { - license { - name = 'BSD 3-Clause "New"' - url = 'https://opensource.org/licenses/BSD-3-Clause' - } - } - - developers { - developer { - id = 'jonasvautherin' - name = 'Jonas Vautherin' - email = 'dev@jonas.vautherin.ch' - } - } - } - } - } - repositories { - maven { - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - - credentials { - username = ossrhUsername - password = ossrhPassword - } - } - } - } - - signing { - useGpgCmd() - sign publishing.publications.release - } - } - } -} - -android { - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - defaultConfig { - minSdkVersion 21 - targetSdkVersion 35 - compileSdk 35 - - archivesBaseName = 'mavsdk-server' - group = 'io.mavsdk' - versionCode 3 - version '3.1.0' - - ndk { - abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' - } - - externalNativeBuild { - cmake { - arguments "-DANDROID_STL=c++_shared" - } - } - } - - externalNativeBuild { - cmake { - path "src/main/cpp/CMakeLists.txt" - } - } - - publishing { - singleVariant('release') { - withSourcesJar() - withJavadocJar() - } - } - - ndkVersion "28.0.13004108" - namespace 'io.mavsdk.mavsdkserver' -} diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts new file mode 100644 index 0000000..78098b9 --- /dev/null +++ b/mavsdk_server/build.gradle.kts @@ -0,0 +1,226 @@ +import java.util.Properties +import java.io.FileInputStream +import java.io.IOException +import java.net.URI + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.jreleaser) + `maven-publish` +} + +// Load file "keystore.properties" where we keep our keys +val keystorePropertiesFile = rootProject.file("keystore.properties") +val keystoreProperties = Properties() + +try { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} catch (ignored: IOException) { + if (project.hasProperty("centralUsername")) keystoreProperties["centralUsername"] = property("centralUsername") + if (project.hasProperty("centralPassword")) keystoreProperties["centralPassword"] = property("centralPassword") + if (project.hasProperty("gpgPass")) keystoreProperties["gpgPass"] = property("gpgPass") +} + +allprojects { + val mavsdk_server_release = "v3.6.0" + + tasks { + register("extractMavsdkServer") { + val tmpDir = File(layout.buildDirectory.get().asFile, "tmp") + tmpDir.mkdirs() + + fun extractForArch(arch: String) { + val archiveName = "mavsdk_server_android-${arch}_${mavsdk_server_release}.tar" + val archiveFile = File(tmpDir, archiveName) + val archiveUrl = "https://github.com/mavlink/MAVSDK/releases/download/${mavsdk_server_release}/mavsdk_server_android-$arch.tar" + val destDir = "${project.projectDir.getAbsolutePath()}/src/main/prebuiltLibs" + + inputs.file(archiveFile) + outputs.dir(destDir) + + if (!archiveFile.exists()) { + project.logger.warn("Downloading ${archiveFile.getName()} into ${archiveFile.getAbsolutePath()}...") + URI(archiveUrl).toURL().openStream().use { input -> + archiveFile.outputStream().use { output -> + input.copyTo(output) + } + } + } else { + project.logger.warn("Archive already exists! Skipping download.") + } + + project.logger.warn("Extracting $archiveFile into $destDir") + + from(tarTree(archiveFile)) { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + eachFile { + if (path.endsWith(".so")) { + filePermissions { + group.execute = true + user.execute = true + other.execute = true + } + } + } + into(destDir) + project.logger.warn("Should be extracted for arch $arch") + } + + extractForArch("arm64") + extractForArch("arm") + extractForArch("x86") + extractForArch("x86_64") + } + } + + tasks.named("preBuild") { + dependsOn("extractMavsdkServer") + } +} + +android { + namespace = "io.mavsdk.mavsdkserver" + compileSdk = 35 + + defaultConfig { + minSdk = 21 + + group = "io.mavsdk" + version = "3.6.0-SNAPSHOT" + + + ndk { + abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64") + } + + externalNativeBuild { + cmake { + arguments.add("-DANDROID_STL=c++_shared") + } + } + } + + externalNativeBuild { + cmake { + path = File("src/main/cpp/CMakeLists.txt") + } + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + + publishing { + singleVariant("release") { + withSourcesJar() + withJavadocJar() + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + ndkVersion = "28.0.13004108" +} + + +if (keystoreProperties.containsKey("centralUsername") && keystoreProperties.containsKey("centralPassword")) { + afterEvaluate { + publishing { + publications { + create("release") { + from(components["release"]) + + pom { + name = "MAVSDK-Server" + packaging = "aar" + description = "MAVSDK server for Android." + url = "https://github.com/mavlink/MAVSDK-Java" + + scm { + connection = "scm:git:https://github.com/mavlink/MAVSDK-Java" + developerConnection = "scm:git:https://github.com/mavlink/MAVSDK-Java" + url = "https://github.com/mavlink/MAVSDK-Java" + } + + licenses { + license { + name = "BSD 3-Clause" + url = "https://opensource.org/licenses/BSD-3-Clause" + } + } + + developers { + developer { + id = "jonasvautherin" + name = "Jonas Vautherin" + email = "dev@jonas.vautherin.ch" + } + developer { + id = "julianoes" + name = "Julian Oes" + email = "julian@oes.ch" + } + } + } + } + } + + repositories { + maven { + url = uri(layout.buildDirectory.dir("target/staging-deploy")) + } + } + } + } + + jreleaser { + signing { + setActive("ALWAYS") + armored.set(true) + setMode("COMMAND") + keystoreProperties["gpgPass"]?.let { + passphrase.set(it as String) + } + } + deploy { + release { + github { + skipRelease = true + skipTag = true + } + } + maven { + mavenCentral { + create("sonatype") { + verifyPom = false + setActive("RELEASE") + username = keystoreProperties["centralUsername"] as String + password = keystoreProperties["centralPassword"] as String + url = "https://central.sonatype.com/api/v1/publisher" + stagingRepository("build/target/staging-deploy") + } + } + nexus2 { + create("snapshot-deploy") { + verifyPom = false + setActive("SNAPSHOT") + snapshotUrl.set("https://central.sonatype.com/repository/maven-snapshots") + url = "https://central.sonatype.com/repository/maven-snapshots" + applyMavenCentralRules = true + snapshotSupported = true + username = keystoreProperties["centralUsername"] as String + password = keystoreProperties["centralPassword"] as String + stagingRepository("build/target/staging-deploy") + } + } + } + } + } +} + diff --git a/mavsdk_server/gradle/libs.versions.toml b/mavsdk_server/gradle/libs.versions.toml new file mode 100644 index 0000000..e7e110c --- /dev/null +++ b/mavsdk_server/gradle/libs.versions.toml @@ -0,0 +1,9 @@ +[versions] +android-gradle-plugin = "8.6.1" +jreleaser-plugin = "1.19.0" + +[libraries] + +[plugins] +android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +jreleaser = { id = "org.jreleaser", version.ref = "jreleaser-plugin" } diff --git a/mavsdk_server/settings.gradle b/mavsdk_server/settings.gradle deleted file mode 100644 index 004a467..0000000 --- a/mavsdk_server/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'mavsdk-server' diff --git a/mavsdk_server/settings.gradle.kts b/mavsdk_server/settings.gradle.kts new file mode 100644 index 0000000..a2d2957 --- /dev/null +++ b/mavsdk_server/settings.gradle.kts @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "mavsdk-server" + diff --git a/sdk/build.gradle b/sdk/build.gradle deleted file mode 100644 index 5411a6c..0000000 --- a/sdk/build.gradle +++ /dev/null @@ -1,179 +0,0 @@ -buildscript { - repositories { - jcenter() - mavenCentral() - } - - dependencies { - classpath "com.google.protobuf:protobuf-gradle-plugin:0.9.4" - } -} - -subprojects { - apply plugin: 'com.google.protobuf' - apply plugin: 'idea' - apply plugin: 'java-library' - apply plugin: 'maven-publish' - apply plugin: 'signing' - - group = 'io.mavsdk' - archivesBaseName = 'mavsdk' - version = '3.0.0' - - repositories { - jcenter() - mavenCentral() - } - - configurations { - checkstyleClasspath - } - - dependencies { - checkstyleClasspath 'com.puppycrawl.tools:checkstyle:8.17' - } - - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - - def grpcVersion = '1.61.1' - - protobuf { - protoc { - artifact = 'com.google.protobuf:protoc:3.25.2' - } - - plugins { - grpc { - artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" - } - } - - generateProtoTasks { - all()*.each { task -> - task.builtins { - java { - option "lite" - } - } - - task.plugins { - grpc { - option 'lite' - } - - mavsdk { - option 'file_ext=java' - option "template_path=$project.rootDir/templates/" - } - } - } - } - } - - sourceSets { - main { - proto { - srcDir "$project.rootDir/proto/protos/" - } - - java { - srcDir 'build/generated/source/proto/main/javalite' - srcDir 'build/generated/source/proto/main/grpc' - srcDir 'build/generated/source/proto/main/mavsdk' - } - } - } - - tasks.withType(Jar).all { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - - java { - withJavadocJar() - withSourcesJar() - } - - if (project.hasProperty('ossrhUsername') - && project.hasProperty('ossrhPassword')) { - - afterEvaluate { - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - - pom { - name = 'MAVSDK-Java' - packaging = 'jar' - description = 'MAVSDK client for Java.' - url = 'https://github.com/mavlink/MAVSDK-Java' - - scm { - connection = 'scm:git:https://github.com/mavlink/MAVSDK-Java' - developerConnection = 'scm:git:https://github.com/mavlink/MAVSDK-Java' - url = 'https://github.com/mavlink/MAVSDK-Java' - } - - licenses { - license { - name = 'BSD 3-Clause "New"' - url = 'https://opensource.org/licenses/BSD-3-Clause' - } - } - - developers { - developer { - id = 'jonasvautherin' - name = 'Jonas Vautherin' - email = 'dev@jonas.vautherin.ch' - } - } - } - } - } - repositories { - maven { - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - - credentials { - username = ossrhUsername - password = ossrhPassword - } - } - } - } - - signing { - useGpgCmd() - sign publishing.publications.mavenJava - } - } - } - - idea { - module { - inheritOutputDirs = false - outputDir = compileJava.destinationDir - testOutputDir = compileTestJava.destinationDir - } - } - - dependencies { - // The protobuf configuration which was set earlier would generate well-known - // protos which would create conflicts with other libraries that use them as well - compileOnly "io.grpc:grpc-protobuf:${grpcVersion}" - - implementation "io.grpc:grpc-okhttp:${grpcVersion}" - implementation "io.grpc:grpc-protobuf-lite:${grpcVersion}" - implementation "io.grpc:grpc-stub:${grpcVersion}" - implementation 'org.slf4j:slf4j-api:2.0.12' - api 'io.reactivex.rxjava2:rxjava:2.2.21' - - compileOnly "javax.annotation:javax.annotation-api:1.3.2" - - testImplementation "io.grpc:grpc-testing:${grpcVersion}" - testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.13.0' - } -} diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts new file mode 100644 index 0000000..b728de1 --- /dev/null +++ b/sdk/build.gradle.kts @@ -0,0 +1,184 @@ +import java.util.Properties +import java.io.FileInputStream +import java.io.IOException + +plugins { + alias(libs.plugins.jreleaser) + alias(libs.plugins.protobuf) + `java-library` + `maven-publish` +} + +// Load file "keystore.properties" where we keep our keys +val keystorePropertiesFile = rootProject.file("keystore.properties") +val keystoreProperties = Properties() + +try { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} catch (ignored: IOException) { + if (project.hasProperty("centralUsername")) keystoreProperties["centralUsername"] = property("centralUsername") + if (project.hasProperty("centralPassword")) keystoreProperties["centralPassword"] = property("centralPassword") + if (project.hasProperty("gpgPass")) keystoreProperties["gpgPass"] = property("gpgPass") +} + +group = "io.mavsdk" +version = "3.6.0-SNAPSHOT" + +val grpcVersion = "1.61.1" + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.25.2" + } + + plugins { + create("grpc") { + artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" + } + } + + generateProtoTasks { + all().forEach { task -> + task.builtins { + getByName("java") { + option("lite") + } + } + task.plugins { + create("grpc") { + option("lite") + } + + create("mavsdk") { + option("file_ext=java") + option("template_path=templates/") + } + } + } + } +} + +tasks.withType().configureEach { + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + + withJavadocJar() + withSourcesJar() +} + +if (keystoreProperties.containsKey("centralUsername") && keystoreProperties.containsKey("centralPassword")) { + afterEvaluate { + publishing { + publications { + create("java") { + from(components["java"]) + + pom { + name = "MAVSDK-Java" + packaging = "jar" + description = "MAVSDK client for Java." + url = "https://github.com/mavlink/MAVSDK-Java" + + scm { + connection = "scm:git:https://github.com/mavlink/MAVSDK-Java" + developerConnection = "scm:git:https://github.com/mavlink/MAVSDK-Java" + url = "https://github.com/mavlink/MAVSDK-Java" + } + + licenses { + license { + name = "BSD 3-Clause" + url = "https://opensource.org/licenses/BSD-3-Clause" + } + } + + developers { + developer { + id = "jonasvautherin" + name = "Jonas Vautherin" + email = "dev@jonas.vautherin.ch" + } + } + } + } + } + + repositories { + maven { + url = uri(layout.buildDirectory.dir("target/staging-deploy")) + } + } + } + } + + jreleaser { + signing { + setActive("ALWAYS") + armored.set(true) + setMode("COMMAND") + keystoreProperties["gpgPass"]?.let { + passphrase.set(it as String) + } + + command { + keyName.set("72D6223E657BDA72EDEA45F021A81CC9B3DDE00B") + } + } + deploy { + release { + github { + skipRelease = true + skipTag = true + } + } + maven { + mavenCentral { + create("sonatype") { + verifyPom = false + setActive("RELEASE") + username = keystoreProperties["centralUsername"] as String + password = keystoreProperties["centralPassword"] as String + url = "https://central.sonatype.com/api/v1/publisher" + stagingRepository("build/target/staging-deploy") + } + } + nexus2 { + create("snapshot-deploy") { + verifyPom = false + setActive("SNAPSHOT") + snapshotUrl.set("https://central.sonatype.com/repository/maven-snapshots") + url = "https://central.sonatype.com/repository/maven-snapshots" + applyMavenCentralRules = true + snapshotSupported = true + username = keystoreProperties["centralUsername"] as String + password = keystoreProperties["centralPassword"] as String + stagingRepository("build/target/staging-deploy") + } + } + } + } + } +} + +dependencies { + protobuf(files("proto/protos/")) + + compileOnly("io.grpc:grpc-protobuf:${grpcVersion}") + + implementation("io.grpc:grpc-okhttp:${grpcVersion}") + implementation("io.grpc:grpc-protobuf-lite:${grpcVersion}") + implementation("io.grpc:grpc-stub:${grpcVersion}") + implementation("org.slf4j:slf4j-api:2.0.12") + api("io.reactivex.rxjava2:rxjava:2.2.21") + + compileOnly("javax.annotation:javax.annotation-api:1.3.2") + + testImplementation("io.grpc:grpc-testing:${grpcVersion}") + testImplementation("junit:junit:4.12") + testImplementation("org.mockito:mockito-core:2.13.0") +} diff --git a/sdk/gradle/libs.versions.toml b/sdk/gradle/libs.versions.toml new file mode 100644 index 0000000..ab410b5 --- /dev/null +++ b/sdk/gradle/libs.versions.toml @@ -0,0 +1,9 @@ +[versions] +jreleaser-plugin = "1.19.0" +protobuf-gradle-plugin = "0.9.4" + +[libraries] + +[plugins] +jreleaser = { id = "org.jreleaser", version.ref = "jreleaser-plugin" } +protobuf = { id = "com.google.protobuf", version.ref = "protobuf-gradle-plugin" } diff --git a/sdk/mavsdk/settings.gradle b/sdk/mavsdk/settings.gradle deleted file mode 100644 index 5ef60bf..0000000 --- a/sdk/mavsdk/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'mavsdk' diff --git a/sdk/mavsdk/src/test/java/io/mavsdk/MavsdkTest.java b/sdk/mavsdk/src/test/java/io/mavsdk/MavsdkTest.java deleted file mode 100644 index 9084829..0000000 --- a/sdk/mavsdk/src/test/java/io/mavsdk/MavsdkTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.mavsdk; - -import java.util.concurrent.TimeUnit; -import org.junit.Test; - -public class MavsdkTest { - - @Test - public void testStream() throws InterruptedException { - System system = new System(); - system.getTelemetry().getPosition() - .doOnNext(next -> java.lang.System.out.println(next)) - .test() - .await(5, TimeUnit.SECONDS); - } - - @Test - public void testCall() throws InterruptedException { - System system = new System(); - system.getAction().arm() - .andThen(system.getAction().takeoff()) - .delay(5, TimeUnit.SECONDS) - .andThen(system.getAction().land()) - .test() - .await(); - } - - @Test - public void testRequest() throws InterruptedException { - System system = new System(); - system.getAction().getTakeoffAltitude() - .doOnSuccess(result -> java.lang.System.out.println(result)).test().await(); - } -} diff --git a/sdk/proto b/sdk/proto index 20aa335..e053eca 160000 --- a/sdk/proto +++ b/sdk/proto @@ -1 +1 @@ -Subproject commit 20aa335ef85b50d844ffb3d3a53420c6fbcc289b +Subproject commit e053ecabc5b825bb9c831f3f31ab24ff727ce1e6 diff --git a/sdk/settings.gradle b/sdk/settings.gradle deleted file mode 100644 index f47d1fa..0000000 --- a/sdk/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include 'mavsdk' diff --git a/sdk/settings.gradle.kts b/sdk/settings.gradle.kts new file mode 100644 index 0000000..7ec28bd --- /dev/null +++ b/sdk/settings.gradle.kts @@ -0,0 +1,19 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + + +rootProject.name = "mavsdk" + diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/MavsdkEventQueue.java b/sdk/src/main/java/io/mavsdk/MavsdkEventQueue.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/MavsdkEventQueue.java rename to sdk/src/main/java/io/mavsdk/MavsdkEventQueue.java diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/MavsdkException.java b/sdk/src/main/java/io/mavsdk/MavsdkException.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/MavsdkException.java rename to sdk/src/main/java/io/mavsdk/MavsdkException.java diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/Plugin.java b/sdk/src/main/java/io/mavsdk/Plugin.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/Plugin.java rename to sdk/src/main/java/io/mavsdk/Plugin.java diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/System.java b/sdk/src/main/java/io/mavsdk/System.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/System.java rename to sdk/src/main/java/io/mavsdk/System.java diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/internal/LazyPlugin.java b/sdk/src/main/java/io/mavsdk/internal/LazyPlugin.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/internal/LazyPlugin.java rename to sdk/src/main/java/io/mavsdk/internal/LazyPlugin.java diff --git a/sdk/mavsdk/src/main/java/io/mavsdk/internal/Provider.java b/sdk/src/main/java/io/mavsdk/internal/Provider.java similarity index 100% rename from sdk/mavsdk/src/main/java/io/mavsdk/internal/Provider.java rename to sdk/src/main/java/io/mavsdk/internal/Provider.java From 5331a32d56cd0b9571cab3c5dd9510386ab1d6a0 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 10 Jul 2025 22:28:24 +0200 Subject: [PATCH 03/22] Bump to 3.6.0 --- README.md | 6 +++--- mavsdk_server/build.gradle.kts | 2 +- sdk/README.md | 2 +- sdk/build.gradle.kts | 2 +- sdk/proto | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2a3d3cf..95f0bb4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ MAVSDK-Java is distributed through MavenCentral, meaning that it can be imported ``` dependencies { ... - implementation 'io.mavsdk:mavsdk:3.0.0' + implementation 'io.mavsdk:mavsdk:3.6.0' ... } ``` @@ -29,8 +29,8 @@ For Android, `mavsdk_server` is distributed as an Android library (`aar`): ``` dependencies { ... - implementation 'io.mavsdk:mavsdk:3.0.0' - implementation 'io.mavsdk:mavsdk-server:3.1.0' + implementation 'io.mavsdk:mavsdk:3.6.0' + implementation 'io.mavsdk:mavsdk-server:3.6.0' ... } ``` diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 78098b9..fdad314 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -87,7 +87,7 @@ android { minSdk = 21 group = "io.mavsdk" - version = "3.6.0-SNAPSHOT" + version = "3.6.0" ndk { diff --git a/sdk/README.md b/sdk/README.md index 5d33b57..f468cbe 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -8,7 +8,7 @@ Because it is deployed on Maven Central, adding MAVSDK-Java to your project is a ```groovy dependencies { - implementation 'io.mavsdk:mavsdk:2.1.0' + implementation 'io.mavsdk:mavsdk:3.6.0' } ``` diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index b728de1..c3fe141 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -22,7 +22,7 @@ try { } group = "io.mavsdk" -version = "3.6.0-SNAPSHOT" +version = "3.6.0" val grpcVersion = "1.61.1" diff --git a/sdk/proto b/sdk/proto index e053eca..20aa335 160000 --- a/sdk/proto +++ b/sdk/proto @@ -1 +1 @@ -Subproject commit e053ecabc5b825bb9c831f3f31ab24ff727ce1e6 +Subproject commit 20aa335ef85b50d844ffb3d3a53420c6fbcc289b From e04a72b25caa4c14db0f6a97f8b4470096c7ee1a Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 10 Jul 2025 22:58:49 +0200 Subject: [PATCH 04/22] Use proper CI gpg key --- mavsdk_server/build.gradle.kts | 4 ++++ sdk/build.gradle.kts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index fdad314..70ff74e 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -187,6 +187,10 @@ if (keystoreProperties.containsKey("centralUsername") && keystoreProperties.cont keystoreProperties["gpgPass"]?.let { passphrase.set(it as String) } + + command { + keyName.set("CF3FF35732A465F680A89BC25B01A8023597C84B") + } } deploy { release { diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index c3fe141..92e6c15 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -126,7 +126,7 @@ if (keystoreProperties.containsKey("centralUsername") && keystoreProperties.cont } command { - keyName.set("72D6223E657BDA72EDEA45F021A81CC9B3DDE00B") + keyName.set("CF3FF35732A465F680A89BC25B01A8023597C84B") } } deploy { From 9da3b972cc5dd08c25a9b7ee9f6c5acf944c2c70 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 10 Jul 2025 23:45:25 +0200 Subject: [PATCH 05/22] Add CI to deploy artifacts to Maven Central --- .github/workflows/main.yml | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..2113cd9 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,51 @@ +name: MAVSDK-Java + +on: + push: + branches: + - 'main' + pull_request: + branches: + - '**' + release: + types: [created] + +jobs: + main: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Prepare tokens keystore + run: | + echo "${{ secrets.TOKENS_KEYSTORE }}" > /tmp/keystore.properties.b64 + base64 -d -i /tmp/keystore.properties.b64 > /tmp/keystore.properties + cp /tmp/keystore.properties sdk + cp /tmp/keystore.properties mavsdk_server + - name: Prepare GPG key + run: echo "${{ secrets.SIGNING_PGP_KEY }}" | gpg --batch --import + - name: Build and prepare mavsdk + working-directory: ./sdk + run: | + set -o pipefail + python3 -m venv venv + source ./venv/bin/activate + pip install protoc-gen-mavsdk + ./gradlew build + ./gradlew publish + - name: Build and prepare mavsdk-server + working-directory: ./mavsdk_server + run: | + set -o pipefail + ./gradlew build + ./gradlew publish + - name: Deploy mavsdk + if: github.event_name == 'release' && github.event.action == 'created' + working-directory: ./sdk + run: ./gradlew jreleaserDeploy + - name: Deploy mavsdk-server + if: github.event_name == 'release' && github.event.action == 'created' + working-directory: ./mavsdk_server + run: ./gradlew jreleaserDeploy + From 3262a1938773e5577aa17c6fd6c62a172a1cad4c Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Fri, 11 Jul 2025 00:24:09 +0200 Subject: [PATCH 06/22] Update README --- README.md | 77 +++++++++++++++++-------------------------------------- 1 file changed, 23 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 95f0bb4..ef204fb 100644 --- a/README.md +++ b/README.md @@ -71,62 +71,31 @@ The plugins are constructed and initialized lazily upon their first call through 5. One-shot calls like `takeoff` and `land` are not added to the `mavsdk-event-queue` when the user subscribes to them. This is done to avoid their piling up while the `mavsdk_server` discovers a system. Instead, the `onError` callback will be triggered after a 100ms delay indicating that no system was available for the command. -## Contributing - -### Coding style - -Java/Android coding style is ensured using CheckStyle with the Google style. - -#### Command line - -A `checkstyle` task is defined in the root `build.gradle` of each project and can be run as follows: - - $ ./gradlew checkstyle - -The `build` task depends on `checkstyle`, meaning that `$ ./gradlew build` runs the checks as well. - -#### IntelliJ / Android-Studio - -There exist a plugin for CheckStyle in JetBrains' IDEs. - -##### Setup - -1. Install the plugin called "CheckStyle-IDEA" in IntelliJ / Android-Studio. -2. Import the checkstyle configuration as a code style scheme in _Settings > Editor > Code Style > Java > Manage... > - Import..._ by selecting "CheckStyle configuration" and then browsing to `config/checkstyle/checkstyle.xml`. -3. In _Settings > Other Settings > Checkstyle_, change the "Scan Scope" to "Only Java sources (including tests)". -4. Still in _Settings > Other Settings > Checkstyle_, add a new configuration file and browse to - `config/checkstyle/checkstyle.xml`. - -##### Usage - -In IntelliJ / Android-Studio's bottom task bar, you should see a "CheckStyle" tab. It will allow you to select your configuration -with the "Rules" dropdown-list, and to run the analysis on your code. - -Note that by default, the IDE will not run checkstyle when building the project (whereas `$ ./gradlew build` always does it). - -#### Troubleshooting - -In IntelliJ / Android-Studio, the IDE might force the order of the imports in a way that is not following the checkstyle rules. For some reason, this is not set when importing `checkstyle.xml` as a code style scheme. However, it can be manually updated in _Settings > Code Style > Java > Import Layout_. - ### Releasing -Both [sdk](./sdk) and [mavsdk_server](./mavsdk_server) are released with Maven. Publishing can be done through a gradle task: - -```gradle -./gradlew uploadArchives -``` - -This task requires a few secrets in `gradle.properties`: - -``` -signing.keyId= -signing.password= -signing.secretKeyRingFile= - -ossrhUsername= -ossrhPassword= -``` +1. Update the proto submodule (./sdk/proto) to match the version of + `mavsdk_server` you want to use. The proto submodule should point to the same + commit hash as the proto submodule in + [MAVSDK-C++](https://github.com/mavlink/mavsdk) (make sure you check the hash + associated with the right release tag!). +1. Update the version in both modules: + [./sdk/build.gradle.kts](./sdk/build.gradle.kts) and + [./mavsdk_server/build.gradle.kts](./mavsdk_server/build.gradle.kts). The new version + should be the version of `mavsdk_server` followed by an optional build + number, e.g. `3.6.0` or `3.6.0-2`. This means that the proto definitions + should match with the `v3.6.0` tag of + [MAVSDK-C++](https://github.com/mavlink/mavsdk). We support snapshots, e.g. + `3.6.0-SNAPSHOT` will publish a temporary snapshot to Maven Central (this is + convenient for testing before the final release). +1. In [./mavsdk_server/build.gradle.kts](./mavsdk_server/build.gradle.kts), + change `mavsdk_server_release` to point to the version of `mavsdk_server` you + want to use. This should correspond to the proto submodule and to the version + numbers set in the previous step (e.g. if you set 3.6.0-2, the proto + submodule should point to the same hash as MAVSDK-C++ v3.6.0, and + `mavsdk_server_release` should be set to "v3.6.0"). +1. Update the README to point to the new version. +1. Tag a release. The CI will publish the artifacts to Maven Central + automatically. ### Debugging without pushing to maven From 0c35e901cf60d856d8ded01fb2668e13a7a40674 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Sun, 13 Jul 2025 17:59:18 +0200 Subject: [PATCH 07/22] ci: more automation --- .github/workflows/main.yml | 69 +++++++++++--- mavsdk_server/build.gradle.kts | 19 +++- sdk/build.gradle.kts | 10 ++- tools/version_validator.py | 159 +++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 14 deletions(-) create mode 100644 tools/version_validator.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2113cd9..838aca5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,4 @@ name: MAVSDK-Java - on: push: branches: @@ -9,14 +8,40 @@ on: - '**' release: types: [created] - jobs: - main: + build: + if: github.event_name != 'release' runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: submodules: recursive + - name: Build and prepare mavsdk + working-directory: ./sdk + run: | + set -o pipefail + python3 -m venv venv + source ./venv/bin/activate + pip install protoc-gen-mavsdk + ./gradlew build + - name: Build and prepare mavsdk-server + working-directory: ./mavsdk_server + run: ./gradlew build + + release: + if: github.event_name == 'release' && github.event.action == 'created' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Validate version + id: version + run: | + set -o pipefail + tag_name="${{ github.ref_name }}" + python ./tools/version_validator.py "$tag_name" + echo "tag_name=$tag_name" >> $GITHUB_OUTPUT - name: Prepare tokens keystore run: | echo "${{ secrets.TOKENS_KEYSTORE }}" > /tmp/keystore.properties.b64 @@ -25,6 +50,30 @@ jobs: cp /tmp/keystore.properties mavsdk_server - name: Prepare GPG key run: echo "${{ secrets.SIGNING_PGP_KEY }}" | gpg --batch --import + - name: Extract version and sync proto submodule + run: | + set -o pipefail + tag_name="${{ steps.version.outputs.tag_name }}" + + # Extract version number + extracted_version=$(python ./tools/version_validator.py -e "$tag_name") + + # Clone MAVSDK repo with minimal depth to get proto submodule hash + git clone --depth 1 --branch "${extracted_version}" https://github.com/mavlink/mavsdk.git /tmp/mavsdk + + # Get the proto submodule commit hash from the MAVSDK repo + cd /tmp/mavsdk + proto_commit_hash=$(git ls-tree HEAD proto | awk '{print $3}') + + # Update our local proto submodule to match + cd $GITHUB_WORKSPACE/sdk/proto + git fetch origin + git checkout $proto_commit_hash + + # Cleanup + rm -rf /tmp/mavsdk + + echo "Updated proto submodule to commit: $proto_commit_hash for MAVSDK version: $extracted_version" - name: Build and prepare mavsdk working-directory: ./sdk run: | @@ -32,20 +81,18 @@ jobs: python3 -m venv venv source ./venv/bin/activate pip install protoc-gen-mavsdk - ./gradlew build - ./gradlew publish + ./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }} + ./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }} - name: Build and prepare mavsdk-server working-directory: ./mavsdk_server run: | set -o pipefail - ./gradlew build - ./gradlew publish + ./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }} + ./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }} - name: Deploy mavsdk - if: github.event_name == 'release' && github.event.action == 'created' working-directory: ./sdk - run: ./gradlew jreleaserDeploy + run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }} - name: Deploy mavsdk-server - if: github.event_name == 'release' && github.event.action == 'created' working-directory: ./mavsdk_server - run: ./gradlew jreleaserDeploy + run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }} diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 70ff74e..1c25d86 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -22,7 +22,17 @@ try { } allprojects { - val mavsdk_server_release = "v3.6.0" + // We fetch the mavsdk_server binary that corresponds to the mavsdk-java + // version. Say we set this package to be 3.6.0-2-SNAPSHOT, it means that it + // corresponds to mavsdk_server 3.6.0. + val mavsdk_server_release = if (!project.hasProperty("VERSION")) { + "v3.6.0" + } else { + val versionString = project.property("VERSION").toString() + val regex = Regex("v?(\\d+\\.\\d+\\.\\d+)") + val version = regex.find(versionString)?.groupValues?.get(1) + "v$version" + } tasks { register("extractMavsdkServer") { @@ -87,8 +97,13 @@ android { minSdk = 21 group = "io.mavsdk" - version = "3.6.0" + // The version must be of the form "X.Y.Z-b[-SNAPSHOT]", where "X.Y.Z" + // is the MAVSDK-C++ version, "b" is the build number of this + // MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT. + version = + if (project.hasProperty("VERSION")) project.property("VERSION").toString() + else "3.6.0-SNAPSHOT" ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64") diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index 92e6c15..0a2dc3a 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -22,7 +22,15 @@ try { } group = "io.mavsdk" -version = "3.6.0" + +// The version must be of the form "X.Y.Z-b[-SNAPSHOT]", where "X.Y.Z" +// is the MAVSDK-C++ version, "b" is the build number of this +// MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT. +// For instance, if the version is 3.6.0-2, it should be built with the same +// version of the proto files as MAVSDK-C++ v3.6.0. +version = + if (project.hasProperty("VERSION")) project.property("VERSION").toString() + else "3.6.0-SNAPSHOT" val grpcVersion = "1.61.1" diff --git a/tools/version_validator.py b/tools/version_validator.py new file mode 100644 index 0000000..79ac27f --- /dev/null +++ b/tools/version_validator.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Version Number Validator + +This script validates version numbers and extracts major.minor.patch format. + +Version format rules: +- Can start with 'v' (optional): v2.3.1 or 2.3.1 +- Must have major.minor.patch: 1.2.3 (minimum required) +- May have build number: 1.2.3-1 or 1.2.3-2 +- May end with -SNAPSHOT: 3.4.5-1-SNAPSHOT or 3.4.5-SNAPSHOT + +Usage: + python version_validator.py + python version_validator.py --extract +""" + +import re +import sys +import argparse + +def extract_major_minor_patch(version_string): + """ + Extract major.minor.patch from a valid version string in vX.Y.Z format. + + Args: + version_string (str): The version string to extract from + + Returns: + str: The extracted version in vX.Y.Z format, or None if invalid + """ + # Define the regex pattern for valid version strings + pattern = r'^v?(\d+)\.(\d+)\.(\d+)(?:-(\d+))?(?:-SNAPSHOT)?$' + match = re.match(pattern, version_string) + + if match: + major, minor, patch = match.groups()[:3] + return f"v{major}.{minor}.{patch}" + + return None + +def validate_version(version_string): + """ + Validate a version string according to the specified rules. + + Args: + version_string (str): The version string to validate + + Returns: + bool: True if valid, False otherwise + """ + return extract_major_minor_patch(version_string) is not None + +def main(): + parser = argparse.ArgumentParser( + description="Validate version number and extract major.minor.patch format", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python version_validator.py v2.3.1 # Validate version + python version_validator.py 1.2.3-1 # Validate version with build + python version_validator.py --extract v2.3.1-SNAPSHOT # Extract v2.3.1 + python version_validator.py -e 3.4.5-2-SNAPSHOT # Extract v3.4.5 + +Valid version formats: + v1.2.3, 1.2.3, v1.2.3-1, 1.2.3-1, v1.2.3-SNAPSHOT, 1.2.3-1-SNAPSHOT + """ + ) + + parser.add_argument( + 'version', + help='Version string to validate/extract' + ) + parser.add_argument( + '-e', '--extract', + action='store_true', + help='Extract major.minor.patch in vX.Y.Z format' + ) + + args = parser.parse_args() + + if args.extract: + # Extract mode + result = extract_major_minor_patch(args.version) + if result: + print(result) + sys.exit(0) + else: + print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr) + sys.exit(1) + else: + # Validation mode + if validate_version(args.version): + print(f"'{args.version}' is a valid version string") + sys.exit(0) + else: + print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + # If no arguments provided, run some test cases + if len(sys.argv) == 1: + print("Running test cases...") + + test_cases = [ + # Valid cases + ("v2.3.1", True), + ("2.3.1", True), + ("1.2.3-1", True), + ("v1.2.3-1", True), + ("3.4.5-SNAPSHOT", True), + ("v3.4.5-SNAPSHOT", True), + ("1.2.3-1-SNAPSHOT", True), + ("v1.2.3-1-SNAPSHOT", True), + ("10.20.30", True), + ("v0.0.1", True), + + # Invalid cases + ("1.2", False), + ("v1.2", False), + ("1.2.3.4", False), + ("v1.2.3.4", False), + ("1.2.3-", False), + ("1.2.3-SNAPSHOT-1", False), + ("1.2.3-a", False), + ("v1.2.3-a", False), + ("av1.2.3", False), + ("a1.2.3", False), + (" v1.2.3", False), + ("V1.2.3-a", False), + ("1.2.x", False), + ("", False), + ("v", False), + ("1.2.3-1-SNAPSHOT-extra", False), + ] + + print("\nValidation Tests:") + for version, expected in test_cases: + result = validate_version(version) + status = "✓" if result == expected else "✗" + print(f"{status} {version:<25} -> {result} (expected {expected})") + + print("\nExtraction Tests:") + extraction_tests = [ + ("v2.3.1", "v2.3.1"), + ("2.3.1", "v2.3.1"), + ("1.2.3-1", "v1.2.3"), + ("v1.2.3-1-SNAPSHOT", "v1.2.3"), + ("3.4.5-SNAPSHOT", "v3.4.5"), + ("invalid", None), + ] + + for version, expected in extraction_tests: + result = extract_major_minor_patch(version) + status = "✓" if result == expected else "✗" + print(f"{status} {version:<25} -> {result} (expected {expected})") + else: + main() From 7904073cbc8ea7712294e54afdcecdc6f8e2ed6e Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Sun, 13 Jul 2025 18:46:41 +0200 Subject: [PATCH 08/22] Update README --- README.md | 40 ++++++++++++++-------------------------- sdk/README.md | 2 +- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ef204fb..29a2f9f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ MAVSDK-Java is distributed through MavenCentral, meaning that it can be imported ``` dependencies { ... - implementation 'io.mavsdk:mavsdk:3.6.0' + implementation 'io.mavsdk:mavsdk:' ... } ``` @@ -29,8 +29,8 @@ For Android, `mavsdk_server` is distributed as an Android library (`aar`): ``` dependencies { ... - implementation 'io.mavsdk:mavsdk:3.6.0' - implementation 'io.mavsdk:mavsdk-server:3.6.0' + implementation 'io.mavsdk:mavsdk:' + implementation 'io.mavsdk:mavsdk-server:' ... } ``` @@ -73,29 +73,17 @@ The plugins are constructed and initialized lazily upon their first call through ### Releasing -1. Update the proto submodule (./sdk/proto) to match the version of - `mavsdk_server` you want to use. The proto submodule should point to the same - commit hash as the proto submodule in - [MAVSDK-C++](https://github.com/mavlink/mavsdk) (make sure you check the hash - associated with the right release tag!). -1. Update the version in both modules: - [./sdk/build.gradle.kts](./sdk/build.gradle.kts) and - [./mavsdk_server/build.gradle.kts](./mavsdk_server/build.gradle.kts). The new version - should be the version of `mavsdk_server` followed by an optional build - number, e.g. `3.6.0` or `3.6.0-2`. This means that the proto definitions - should match with the `v3.6.0` tag of - [MAVSDK-C++](https://github.com/mavlink/mavsdk). We support snapshots, e.g. - `3.6.0-SNAPSHOT` will publish a temporary snapshot to Maven Central (this is - convenient for testing before the final release). -1. In [./mavsdk_server/build.gradle.kts](./mavsdk_server/build.gradle.kts), - change `mavsdk_server_release` to point to the version of `mavsdk_server` you - want to use. This should correspond to the proto submodule and to the version - numbers set in the previous step (e.g. if you set 3.6.0-2, the proto - submodule should point to the same hash as MAVSDK-C++ v3.6.0, and - `mavsdk_server_release` should be set to "v3.6.0"). -1. Update the README to point to the new version. -1. Tag a release. The CI will publish the artifacts to Maven Central - automatically. +When a GitHub release is created, the CI runs the release pipeline, which: + +1. Extracts the package version from the release tag. The release tag is expected + to be in the form "X.Y.Z-b[-SNAPSHOT]", where "X.Y.Z" correspond to the + matching version of MAVSDK-C++ and "b" is for build numbers of MAVSDK-Java. + For instance, 3.6.0, 3.6.0-2, 3.6.0-SNAPSHOT or 3.6.0-2-SNAPSHOT. +1. Updates the ./sdk/proto submodule to point to the same commit as the + corresponding proto submodule in MAVSDK-C++ (for version X.Y.Z of + MAVSDK-C++). +1. Build mavsdk and mavsdk_server and deploy them, either as SNAPSHOTs or as + definitive releases. ### Debugging without pushing to maven diff --git a/sdk/README.md b/sdk/README.md index f468cbe..9523847 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -8,7 +8,7 @@ Because it is deployed on Maven Central, adding MAVSDK-Java to your project is a ```groovy dependencies { - implementation 'io.mavsdk:mavsdk:3.6.0' + implementation 'io.mavsdk:mavsdk:' } ``` From f127435fb948d978c7bbca40a86502c64dab3f67 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Sun, 13 Jul 2025 23:02:39 +0200 Subject: [PATCH 09/22] Add SNAPSHOTs to README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 29a2f9f..db51562 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,24 @@ dependencies { } ``` +It is possible to fetch SNAPSHOTs by adding the repository to your Gradle config, as per the [sonatype documentation](https://central.sonatype.org/publish/publish-portal-snapshots/#consuming-via-gradle): + +``` +repositories { + maven { + name = 'Central Portal Snapshots' + url = 'https://central.sonatype.com/repository/maven-snapshots/' + + // Only search this repository for the specific dependency + content { + includeModule("io.mavsdk", "mavsdk") + includeModule("io.mavsdk", "mavsdk-server") + } + } + mavenCentral() +} +``` + ### ProGuard ProGuard users may need to add the following rule: From a999abc62972affd99c05cfae67a79f9314baa0a Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Tue, 8 Jul 2025 12:02:01 +1200 Subject: [PATCH 10/22] mavsdk_server: add temp directory setter --- mavsdk_server/src/main/cpp/native-lib.cpp | 15 +++++++++++++++ .../java/io/mavsdk/mavsdkserver/MavsdkServer.java | 2 ++ 2 files changed, 17 insertions(+) diff --git a/mavsdk_server/src/main/cpp/native-lib.cpp b/mavsdk_server/src/main/cpp/native-lib.cpp index 2812582..6608382 100644 --- a/mavsdk_server/src/main/cpp/native-lib.cpp +++ b/mavsdk_server/src/main/cpp/native-lib.cpp @@ -6,6 +6,8 @@ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"MAVSDK-Server",__VA_ARGS__) +extern "C" char* mavsdk_temp_path; + extern "C" { JNIEXPORT jlong JNICALL @@ -77,4 +79,17 @@ extern "C" auto mavsdk_server = reinterpret_cast(mavsdkServerHandle); mavsdk_server_destroy(mavsdk_server); } + + JNIEXPORT void JNICALL + Java_io_mavsdk_mavsdkserver_MavsdkServer_setTempDirectory(JNIEnv *env, jobject thiz, jstring temp_dir) + { + + const char* temp_c_str = env->GetStringUTFChars(temp_dir, 0); + + static char our_copy[256]; + strncpy(our_copy, temp_c_str, sizeof(our_copy)); + mavsdk_temp_path = our_copy; + + env->ReleaseStringUTFChars(temp_dir, temp_c_str); + } }; diff --git a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java index 5ab6004..2aa482a 100644 --- a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java +++ b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java @@ -125,4 +125,6 @@ public void destroy() { } private native void destroy(long mavsdkServerHandle); + + private native void setTempDirDirectory(String dir); } From 2f2ccf59014aec606a9821bbba7d8410a1f449d7 Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Wed, 9 Jul 2025 13:58:27 +1200 Subject: [PATCH 11/22] Apply suggestion from @JonasVautherin Co-authored-by: Jonas Vautherin --- mavsdk_server/src/main/cpp/native-lib.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mavsdk_server/src/main/cpp/native-lib.cpp b/mavsdk_server/src/main/cpp/native-lib.cpp index 6608382..de81273 100644 --- a/mavsdk_server/src/main/cpp/native-lib.cpp +++ b/mavsdk_server/src/main/cpp/native-lib.cpp @@ -83,7 +83,6 @@ extern "C" JNIEXPORT void JNICALL Java_io_mavsdk_mavsdkserver_MavsdkServer_setTempDirectory(JNIEnv *env, jobject thiz, jstring temp_dir) { - const char* temp_c_str = env->GetStringUTFChars(temp_dir, 0); static char our_copy[256]; From 34d61737c9cebe666870677f7e6383b974691597 Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Wed, 9 Jul 2025 13:58:34 +1200 Subject: [PATCH 12/22] Apply suggestion from @julianoes --- .../src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java index 2aa482a..c959f66 100644 --- a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java +++ b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java @@ -126,5 +126,5 @@ public void destroy() { private native void destroy(long mavsdkServerHandle); - private native void setTempDirDirectory(String dir); + private native void setTempDirectory(String dir); } From 624ca1c26f267d825fcfff16698c66e4730e2409 Mon Sep 17 00:00:00 2001 From: Julian Oes Date: Thu, 10 Jul 2025 06:03:19 +1200 Subject: [PATCH 13/22] Make setTempDirectory public --- .../src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java index c959f66..e6a6e0d 100644 --- a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java +++ b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java @@ -126,5 +126,5 @@ public void destroy() { private native void destroy(long mavsdkServerHandle); - private native void setTempDirectory(String dir); + public native void setTempDirectory(String dir); } From d62eb57f667b3972d558134a44affe0fd73f6f47 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Wed, 16 Jul 2025 01:34:56 +0200 Subject: [PATCH 14/22] Bump to 3.7.1 --- mavsdk_server/build.gradle.kts | 4 ++-- sdk/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 1c25d86..5072ecd 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -26,7 +26,7 @@ allprojects { // version. Say we set this package to be 3.6.0-2-SNAPSHOT, it means that it // corresponds to mavsdk_server 3.6.0. val mavsdk_server_release = if (!project.hasProperty("VERSION")) { - "v3.6.0" + "v3.7.1" } else { val versionString = project.property("VERSION").toString() val regex = Regex("v?(\\d+\\.\\d+\\.\\d+)") @@ -103,7 +103,7 @@ android { // MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT. version = if (project.hasProperty("VERSION")) project.property("VERSION").toString() - else "3.6.0-SNAPSHOT" + else "3.7.1-SNAPSHOT" ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64") diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index 0a2dc3a..c66416e 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -30,7 +30,7 @@ group = "io.mavsdk" // version of the proto files as MAVSDK-C++ v3.6.0. version = if (project.hasProperty("VERSION")) project.property("VERSION").toString() - else "3.6.0-SNAPSHOT" + else "3.7.1-SNAPSHOT" val grpcVersion = "1.61.1" From 28b769f045c3878bfe107fdd83087a6104d8f2b5 Mon Sep 17 00:00:00 2001 From: earocorn Date: Wed, 30 Jul 2025 17:27:33 -0500 Subject: [PATCH 15/22] Add mavlink direct plugin and update proto commit --- sdk/proto | 2 +- sdk/src/main/java/io/mavsdk/System.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sdk/proto b/sdk/proto index 20aa335..61b1b1a 160000 --- a/sdk/proto +++ b/sdk/proto @@ -1 +1 @@ -Subproject commit 20aa335ef85b50d844ffb3d3a53420c6fbcc289b +Subproject commit 61b1b1a197966faed181f8c7c5f2fa57d832cf1f diff --git a/sdk/src/main/java/io/mavsdk/System.java b/sdk/src/main/java/io/mavsdk/System.java index 3372f1d..413f046 100644 --- a/sdk/src/main/java/io/mavsdk/System.java +++ b/sdk/src/main/java/io/mavsdk/System.java @@ -14,6 +14,7 @@ import io.mavsdk.internal.LazyPlugin; import io.mavsdk.log_files.LogFiles; import io.mavsdk.manual_control.ManualControl; +import io.mavsdk.mavlink_direct.MavlinkDirect; import io.mavsdk.mission.Mission; import io.mavsdk.mission_raw.MissionRaw; import io.mavsdk.mission_raw_server.MissionRawServer; @@ -57,6 +58,7 @@ public class System { private final LazyPlugin telemetryServer; private final LazyPlugin transponder; private final LazyPlugin tune; + private final LazyPlugin mavlinkDirect; /** * Create a System object. The plugins are initialized lazily, when the corresponding @@ -102,6 +104,7 @@ public System(@NonNull String host, int port) { telemetryServer = LazyPlugin.from(() -> new TelemetryServer(host, port)); transponder = LazyPlugin.from(() -> new Transponder(host, port)); tune = LazyPlugin.from(() -> new Tune(host, port)); + mavlinkDirect = LazyPlugin.from(() -> new MavlinkDirect(host, port)); } @NonNull @@ -235,6 +238,9 @@ public Tune getTune() { return tune.get(); } + @NonNull + public MavlinkDirect getMavlinkDirect() { return mavlinkDirect.get(); } + /** * Dispose of all the plugins. */ @@ -265,5 +271,6 @@ public void dispose() { telemetryServer.dispose(); transponder.dispose(); tune.dispose(); + mavlinkDirect.dispose(); } } From b999f3dfbe3b6910f0b40b2f37b64aa3b440008a Mon Sep 17 00:00:00 2001 From: earocorn Date: Wed, 30 Jul 2025 17:32:12 -0500 Subject: [PATCH 16/22] Align mavlink direct alphabetically --- sdk/src/main/java/io/mavsdk/System.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sdk/src/main/java/io/mavsdk/System.java b/sdk/src/main/java/io/mavsdk/System.java index 413f046..116c0e4 100644 --- a/sdk/src/main/java/io/mavsdk/System.java +++ b/sdk/src/main/java/io/mavsdk/System.java @@ -45,6 +45,7 @@ public class System { private final LazyPlugin info; private final LazyPlugin logFiles; private final LazyPlugin manualControl; + private final LazyPlugin mavlinkDirect; private final LazyPlugin mission; private final LazyPlugin missionRaw; private final LazyPlugin missionRawServer; @@ -58,7 +59,6 @@ public class System { private final LazyPlugin telemetryServer; private final LazyPlugin transponder; private final LazyPlugin tune; - private final LazyPlugin mavlinkDirect; /** * Create a System object. The plugins are initialized lazily, when the corresponding @@ -91,6 +91,7 @@ public System(@NonNull String host, int port) { info = LazyPlugin.from(() -> new Info(host, port)); logFiles = LazyPlugin.from(() -> new LogFiles(host, port)); manualControl = LazyPlugin.from(() -> new ManualControl(host, port)); + mavlinkDirect = LazyPlugin.from(() -> new MavlinkDirect(host, port)); mission = LazyPlugin.from(() -> new Mission(host, port)); missionRaw = LazyPlugin.from(() -> new MissionRaw(host, port)); missionRawServer = LazyPlugin.from(() -> new MissionRawServer(host, port)); @@ -104,7 +105,6 @@ public System(@NonNull String host, int port) { telemetryServer = LazyPlugin.from(() -> new TelemetryServer(host, port)); transponder = LazyPlugin.from(() -> new Transponder(host, port)); tune = LazyPlugin.from(() -> new Tune(host, port)); - mavlinkDirect = LazyPlugin.from(() -> new MavlinkDirect(host, port)); } @NonNull @@ -172,6 +172,11 @@ public ManualControl getManualControl() { return manualControl.get(); } + @NonNull + public MavlinkDirect getMavlinkDirect() { + return mavlinkDirect.get(); + } + @NonNull public Mission getMission() { return mission.get(); @@ -238,9 +243,6 @@ public Tune getTune() { return tune.get(); } - @NonNull - public MavlinkDirect getMavlinkDirect() { return mavlinkDirect.get(); } - /** * Dispose of all the plugins. */ @@ -258,6 +260,7 @@ public void dispose() { info.dispose(); logFiles.dispose(); manualControl.dispose(); + mavlinkDirect.dispose(); mission.dispose(); missionRaw.dispose(); missionRawServer.dispose(); @@ -271,6 +274,5 @@ public void dispose() { telemetryServer.dispose(); transponder.dispose(); tune.dispose(); - mavlinkDirect.dispose(); } } From b6a795075a135f9a07f1c2e74408e734dcc16dd4 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Wed, 20 Aug 2025 11:29:42 +0200 Subject: [PATCH 17/22] Bump minSdk to 24 and ndk to r28b --- mavsdk_server/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 5072ecd..94b8185 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -94,7 +94,7 @@ android { compileSdk = 35 defaultConfig { - minSdk = 21 + minSdk = 24 group = "io.mavsdk" @@ -140,7 +140,7 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - ndkVersion = "28.0.13004108" + ndkVersion = "28.1.13356709" } From 0482053491e414b531461488b4bb6d99ea67b90f Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Wed, 20 Aug 2025 14:45:22 +0200 Subject: [PATCH 18/22] Do not use c++_shared --- mavsdk_server/build.gradle.kts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 94b8185..66d0479 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -108,12 +108,6 @@ android { ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64") } - - externalNativeBuild { - cmake { - arguments.add("-DANDROID_STL=c++_shared") - } - } } externalNativeBuild { From 8765639407e3e6faecd248edb9bd54b8c8e16dee Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 21 Aug 2025 00:19:35 +0200 Subject: [PATCH 19/22] Set a default temporary folder for MavsdkServer --- .../java/io/mavsdk/mavsdkserver/MavsdkServer.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java index e6a6e0d..9a391f0 100644 --- a/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java +++ b/mavsdk_server/src/main/java/io/mavsdk/mavsdkserver/MavsdkServer.java @@ -1,11 +1,22 @@ package io.mavsdk.mavsdkserver; +import android.content.Context; + public class MavsdkServer { static { java.lang.System.loadLibrary("native_lib"); } + public MavsdkServer(Context context) { + String cacheDir = context.getCacheDir().getAbsolutePath(); + setTempDirectory(cacheDir); + } + + public MavsdkServer(String tempDirectory) { + setTempDirectory(tempDirectory); + } + private long mavsdkServerHandle; /** From 10ecda840406ea0c3168c0ef0c776815722bfb4c Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 21 Aug 2025 00:33:51 +0200 Subject: [PATCH 20/22] Update default version to 3.10.0 --- mavsdk_server/build.gradle.kts | 4 ++-- sdk/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mavsdk_server/build.gradle.kts b/mavsdk_server/build.gradle.kts index 66d0479..ca824b2 100644 --- a/mavsdk_server/build.gradle.kts +++ b/mavsdk_server/build.gradle.kts @@ -26,7 +26,7 @@ allprojects { // version. Say we set this package to be 3.6.0-2-SNAPSHOT, it means that it // corresponds to mavsdk_server 3.6.0. val mavsdk_server_release = if (!project.hasProperty("VERSION")) { - "v3.7.1" + "v3.10.0" } else { val versionString = project.property("VERSION").toString() val regex = Regex("v?(\\d+\\.\\d+\\.\\d+)") @@ -103,7 +103,7 @@ android { // MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT. version = if (project.hasProperty("VERSION")) project.property("VERSION").toString() - else "3.7.1-SNAPSHOT" + else "3.10.0-SNAPSHOT" ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64") diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index c66416e..7216c89 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -30,7 +30,7 @@ group = "io.mavsdk" // version of the proto files as MAVSDK-C++ v3.6.0. version = if (project.hasProperty("VERSION")) project.property("VERSION").toString() - else "3.7.1-SNAPSHOT" + else "3.10.0-SNAPSHOT" val grpcVersion = "1.61.1" From 8200d3c95a6b6984542326cd72d97ccd1b481038 Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 21 Aug 2025 00:34:29 +0200 Subject: [PATCH 21/22] Add SNAPSHOTs section to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index db51562..3aafa3a 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ dependencies { } ``` +### SNAPSHOTs + It is possible to fetch SNAPSHOTs by adding the repository to your Gradle config, as per the [sonatype documentation](https://central.sonatype.org/publish/publish-portal-snapshots/#consuming-via-gradle): ``` From eaa61bbc429235e73d568e6e2c2e8d796b2bd55e Mon Sep 17 00:00:00 2001 From: Jonas Vautherin Date: Thu, 21 Aug 2025 13:17:50 +0200 Subject: [PATCH 22/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3aafa3a..2c5fe00 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ ProGuard users may need to add the following rule: 2. For Android, run the `mavsdk_server` as follows: ```java -MavsdkServer server = new MavsdkServer(); +MavsdkServer server = new MavsdkServer(context); MavsdkEventQueue.executor().execute(() -> server.run(SYSTEM_ADDRESS, MAVSDK_SERVER_PORT)); ```