use std::path::{Path, PathBuf};
pub fn check_java_gradle_versions() -> Option<()> {
let java_major_version = java_major_version()?;
let project_gradle_version = project_gradle_version()?;
let gradle_max_supported_java = gradle_max_supported_java(&project_gradle_version)?;
if java_major_version > gradle_max_supported_java {
log::warn!(
"Detected Java {java_major_version}, but Gradle {project_gradle_version} used by this project can only run on Java up to {gradle_max_supported_java}. \
Android builds will likely fail with a cryptic error. Install a JDK that Gradle {project_gradle_version} supports \
(Java {gradle_max_supported_java} or older) and point JAVA_HOME at it. \
See https://docs.gradle.org/current/userguide/compatibility.html"
);
}
Some(())
}
fn project_gradle_version() -> Option<String> {
let project_path = std::env::var_os("TAURI_ANDROID_PROJECT_PATH")?;
let properties = std::fs::read_to_string(
Path::new(&project_path).join("gradle/wrapper/gradle-wrapper.properties"),
)
.ok()?;
properties.lines().find_map(|line| {
let url = line.trim().strip_prefix("distributionUrl=")?;
let file = url.rsplit('/').next()?;
let version = file.strip_prefix("gradle-")?.split('-').next()?;
(!version.is_empty()).then(|| version.to_string())
})
}
fn gradle_max_supported_java(version: &str) -> Option<u32> {
let mut parts = version.split('.');
let major: u32 = parts.next()?.parse().ok()?;
let minor: u32 = parts.next().and_then(|m| m.parse().ok()).unwrap_or(0);
if major >= 10 {
return None;
}
Some(match (major, minor) {
v if v >= (9, 4) => 26,
v if v >= (9, 1) => 25,
v if v >= (8, 14) => 24,
v if v >= (8, 10) => 23,
v if v >= (8, 8) => 22,
v if v >= (8, 5) => 21,
v if v >= (8, 3) => 20,
v if v >= (7, 6) => 19,
v if v >= (7, 5) => 18,
v if v >= (7, 3) => 17,
_ => return None,
})
}
fn java_major_version() -> Option<u32> {
let release = std::fs::read_to_string(java_home_dir()?.join("release")).ok()?;
release
.lines()
.find_map(|line| line.strip_prefix("JAVA_VERSION="))
.and_then(parse_java_major)
}
fn java_home_dir() -> Option<PathBuf> {
if let Some(home) = std::env::var_os("JAVA_HOME") {
return Some(PathBuf::from(home));
}
let java = which::which("java").ok()?;
java.parent()?.parent().map(Path::to_path_buf)
}
fn parse_java_major(version_output: &str) -> Option<u32> {
let start = version_output.find('"')?;
let rest = &version_output[start + 1..];
let end = rest.find('"')?;
let mut parts = rest[..end].split(['.', '_', '-']);
let first = parts.next()?;
if first == "1" {
parts.next()?.parse().ok()
} else {
first.parse().ok()
}
}
#[cfg(test)]
mod tests {
use super::{gradle_max_supported_java, parse_java_major};
#[test]
fn parses_java_major_version() {
assert_eq!(
parse_java_major("openjdk version \"21.0.1\" 2023-10-17"),
Some(21)
);
assert_eq!(
parse_java_major("openjdk version \"26\" 2026-03-17"),
Some(26)
);
assert_eq!(
parse_java_major("java version \"17.0.9\" 2023-10-17 LTS"),
Some(17)
);
assert_eq!(parse_java_major("java version \"1.8.0_292\""), Some(8));
assert_eq!(parse_java_major("\"21.0.1\""), Some(21));
assert_eq!(parse_java_major("no version here"), None);
}
#[test]
fn maps_gradle_to_max_java() {
assert_eq!(gradle_max_supported_java("9.6.1"), Some(26));
assert_eq!(gradle_max_supported_java("9.4.0"), Some(26));
assert_eq!(gradle_max_supported_java("9.3"), Some(25));
assert_eq!(gradle_max_supported_java("9.1.0"), Some(25));
assert_eq!(gradle_max_supported_java("9.0"), Some(24));
assert_eq!(gradle_max_supported_java("8.14"), Some(24));
assert_eq!(gradle_max_supported_java("8.5"), Some(21));
assert_eq!(gradle_max_supported_java("7.3"), Some(17));
assert_eq!(gradle_max_supported_java("7.2"), None);
assert_eq!(gradle_max_supported_java("10.0"), None);
assert_eq!(gradle_max_supported_java("not-a-version"), None);
}
}