diff --git a/core/tauri-build/src/lib.rs b/core/tauri-build/src/lib.rs index a7e7ed9a509..a31bf679110 100644 --- a/core/tauri-build/src/lib.rs +++ b/core/tauri-build/src/lib.rs @@ -470,7 +470,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { println!("cargo:rustc-env=TAURI_ANDROID_PACKAGE_NAME_PREFIX={android_package_prefix}"); if let Some(project_dir) = var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) { - mobile::generate_gradle_files(project_dir)?; + mobile::generate_gradle_files(project_dir, &config)?; } cfg_alias("dev", dev()); diff --git a/core/tauri-build/src/mobile.rs b/core/tauri-build/src/mobile.rs index c12ac1e6202..eec8288f204 100644 --- a/core/tauri-build/src/mobile.rs +++ b/core/tauri-build/src/mobile.rs @@ -5,10 +5,13 @@ use std::{fs::write, path::PathBuf}; use anyhow::{Context, Result}; +use semver::Version; +use tauri_utils::config::Config; -pub fn generate_gradle_files(project_dir: PathBuf) -> Result<()> { +pub fn generate_gradle_files(project_dir: PathBuf, config: &Config) -> Result<()> { let gradle_settings_path = project_dir.join("tauri.settings.gradle"); let app_build_gradle_path = project_dir.join("app").join("tauri.build.gradle.kts"); + let app_tauri_properties_path = project_dir.join("app").join("tauri.properties"); let mut gradle_settings = "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n".to_string(); @@ -16,6 +19,7 @@ pub fn generate_gradle_files(project_dir: PathBuf) -> Result<()> { val implementation by configurations dependencies {" .to_string(); + let mut app_tauri_properties = Vec::new(); for (env, value) in std::env::vars_os() { let env = env.to_string_lossy(); @@ -48,13 +52,40 @@ dependencies {" app_build_gradle.push_str("\n}"); + if let Some(version) = config.version.as_ref() { + app_tauri_properties.push(format!("tauri.android.versionName={}", version)); + if let Some(version_code) = config.bundle.android.version_code.as_ref() { + app_tauri_properties.push(format!("tauri.android.versionCode={}", version_code)); + } else if let Ok(version) = Version::parse(version) { + let version_code = version.major * 1000000 + version.minor * 1000 + version.patch; + app_tauri_properties.push(format!("tauri.android.versionCode={}", version_code)); + } + } + write(&gradle_settings_path, gradle_settings).context("failed to write tauri.settings.gradle")?; write(&app_build_gradle_path, app_build_gradle) .context("failed to write tauri.build.gradle.kts")?; + if !app_tauri_properties.is_empty() { + write( + &app_tauri_properties_path, + format!( + "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n{}", + app_tauri_properties.join("\n") + ), + ) + .context("failed to write tauri.properties")?; + } + println!("cargo:rerun-if-changed={}", gradle_settings_path.display()); println!("cargo:rerun-if-changed={}", app_build_gradle_path.display()); + if !app_tauri_properties.is_empty() { + println!( + "cargo:rerun-if-changed={}", + app_tauri_properties_path.display() + ); + } Ok(()) } diff --git a/core/tauri-config-schema/schema.json b/core/tauri-config-schema/schema.json index 7a8a234fc61..f4071d6c7c7 100644 --- a/core/tauri-config-schema/schema.json +++ b/core/tauri-config-schema/schema.json @@ -20,7 +20,7 @@ "pattern": "^[^/\\:*?\"<>|]+$" }, "version": { - "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.", + "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\nBy default version 1.0 is used on Android.", "type": [ "string", "null" @@ -2835,6 +2835,16 @@ "type": "integer", "format": "uint32", "minimum": 0.0 + }, + "versionCode": { + "description": "The version code of the application. It is limited to 2,100,000,000 as per Google Play Store requirements.\n\nBy default we use your configured version and perform the following math: versionCode = version.major * 1000000 + version.minor * 1000 + version.patch", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "maximum": 2100000000.0, + "minimum": 1.0 } }, "additionalProperties": false diff --git a/core/tauri-utils/src/config.rs b/core/tauri-utils/src/config.rs index c153f68e55e..8b5d93556d6 100644 --- a/core/tauri-utils/src/config.rs +++ b/core/tauri-utils/src/config.rs @@ -1765,12 +1765,22 @@ pub struct AndroidConfig { /// The Android system will prevent the user from installing the application if the system's API level is lower than the value specified. #[serde(alias = "min-sdk-version", default = "default_min_sdk_version")] pub min_sdk_version: u32, + + /// The version code of the application. + /// It is limited to 2,100,000,000 as per Google Play Store requirements. + /// + /// By default we use your configured version and perform the following math: + /// versionCode = version.major * 1000000 + version.minor * 1000 + version.patch + #[serde(alias = "version-code")] + #[cfg_attr(feature = "schema", validate(range(min = 1, max = 2_100_000_000)))] + pub version_code: Option, } impl Default for AndroidConfig { fn default() -> Self { Self { min_sdk_version: default_min_sdk_version(), + version_code: None, } } } @@ -2030,6 +2040,8 @@ pub struct Config { #[cfg_attr(feature = "schema", validate(regex(pattern = "^[^/\\:*?\"<>|]+$")))] pub product_name: Option, /// App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used. + /// + /// By default version 1.0 is used on Android. #[serde(deserialize_with = "version_deserializer", default)] pub version: Option, /// The application identifier in reverse domain name notation (e.g. `com.tauri.example`). diff --git a/tooling/cli/schema.json b/tooling/cli/schema.json index 7a8a234fc61..f4071d6c7c7 100644 --- a/tooling/cli/schema.json +++ b/tooling/cli/schema.json @@ -20,7 +20,7 @@ "pattern": "^[^/\\:*?\"<>|]+$" }, "version": { - "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.", + "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\nBy default version 1.0 is used on Android.", "type": [ "string", "null" @@ -2835,6 +2835,16 @@ "type": "integer", "format": "uint32", "minimum": 0.0 + }, + "versionCode": { + "description": "The version code of the application. It is limited to 2,100,000,000 as per Google Play Store requirements.\n\nBy default we use your configured version and perform the following math: versionCode = version.major * 1000000 + version.minor * 1000 + version.patch", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "maximum": 2100000000.0, + "minimum": 1.0 } }, "additionalProperties": false diff --git a/tooling/cli/templates/mobile/android/app/.gitignore b/tooling/cli/templates/mobile/android/app/.gitignore index 532fcd9e074..439b71f0e39 100644 --- a/tooling/cli/templates/mobile/android/app/.gitignore +++ b/tooling/cli/templates/mobile/android/app/.gitignore @@ -2,4 +2,5 @@ /src/main/jniLibs/**/*.so /src/main/assets/tauri.conf.json /tauri.build.gradle.kts -/proguard-tauri.pro \ No newline at end of file +/proguard-tauri.pro +/tauri.properties \ No newline at end of file diff --git a/tooling/cli/templates/mobile/android/app/build.gradle.kts b/tooling/cli/templates/mobile/android/app/build.gradle.kts index 126c6d560ff..3217765fdbd 100644 --- a/tooling/cli/templates/mobile/android/app/build.gradle.kts +++ b/tooling/cli/templates/mobile/android/app/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -6,6 +8,13 @@ plugins { id("{{this}}"){{/each}} } +val tauriProperties = Properties().apply { + val propFile = file("tauri.properties") + if (propFile.exists()) { + propFile.inputStream().use { load(it) } + } +} + android { compileSdk = 33 namespace = "{{reverse-domain app.identifier}}" @@ -14,8 +23,8 @@ android { applicationId = "{{reverse-domain app.identifier}}" minSdk = {{android.min-sdk-version}} targetSdk = 33 - versionCode = 1 - versionName = "1.0" + versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() + versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") } buildTypes { getByName("debug") {