Explorar o código

feat(android): aware of version info from tauri config (#9856)

* feat(android): versionName and versionCode support

* formatted code and updated schema

* fix config, cleanup generation

* update docs

* mention default version for android

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Mariotaku hai 1 ano
pai
achega
fd2d7cf8b3

+ 1 - 1
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());

+ 32 - 1
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(())
 }

+ 11 - 1
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"
@@ -2844,6 +2844,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

+ 12 - 0
core/tauri-utils/src/config.rs

@@ -1780,12 +1780,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<u32>,
 }
 
 impl Default for AndroidConfig {
   fn default() -> Self {
     Self {
       min_sdk_version: default_min_sdk_version(),
+      version_code: None,
     }
   }
 }
@@ -2045,6 +2055,8 @@ pub struct Config {
   #[cfg_attr(feature = "schema", validate(regex(pattern = "^[^/\\:*?\"<>|]+$")))]
   pub product_name: Option<String>,
   /// 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<String>,
   /// The application identifier in reverse domain name notation (e.g. `com.tauri.example`).

+ 11 - 1
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"
@@ -2844,6 +2844,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

+ 2 - 1
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
+/proguard-tauri.pro
+/tauri.properties

+ 11 - 2
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") {