Преглед изворни кода

refactor(android): fix race conditions processing Android plugin project as dependency (#6968)

Lucas Fernandes Nogueira пре 2 година
родитељ
комит
59db76af4c

+ 1 - 47
core/tauri-build/src/lib.rs

@@ -15,9 +15,7 @@ use tauri_utils::{
 };
 
 use std::{
-  collections::HashMap,
   env::var_os,
-  fs::{read_to_string, write},
   path::{Path, PathBuf},
 };
 
@@ -270,51 +268,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
   println!("cargo:rustc-env=TAURI_ANDROID_PACKAGE_PREFIX={android_package_prefix}");
 
   if let Some(project_dir) = var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) {
-    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 mut gradle_settings =
-      "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n".to_string();
-    let mut app_build_gradle = "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-val implementation by configurations
-dependencies {"
-      .to_string();
-
-    let plugins_json_path = project_dir.join(".tauri").join("plugins.json");
-    let mut plugins: HashMap<String, mobile::PluginMetadata> = if plugins_json_path.exists() {
-      let s = read_to_string(&plugins_json_path)?;
-      println!("cargo:rerun-if-changed={}", plugins_json_path.display());
-      serde_json::from_str(&s)?
-    } else {
-      Default::default()
-    };
-
-    plugins.insert(
-      "tauri-android".into(),
-      mobile::PluginMetadata {
-        path: var_os("DEP_TAURI_ANDROID_LIBRARY_PATH").map(PathBuf::from).expect("missing `DEP_TAURI_ANDROID_LIBRARY_PATH` environment variable; did you add `tauri` as a dependency to this crate?"),
-      },
-    );
-
-    for (plugin_name, plugin) in plugins {
-      gradle_settings.push_str(&format!("include ':{plugin_name}'"));
-      gradle_settings.push('\n');
-      gradle_settings.push_str(&format!(
-        "project(':{plugin_name}').projectDir = new File({:?})",
-        tauri_utils::display_path(plugin.path)
-      ));
-      gradle_settings.push('\n');
-
-      app_build_gradle.push('\n');
-      app_build_gradle.push_str(&format!(r#"  implementation(project(":{plugin_name}"))"#));
-    }
-    app_build_gradle.push_str("\n}");
-
-    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")?;
+    mobile::generate_gradle_files(project_dir)?;
   }
 
   cfg_alias("dev", !has_feature("custom-protocol"));

+ 56 - 48
core/tauri-build/src/mobile.rs

@@ -3,19 +3,15 @@
 // SPDX-License-Identifier: MIT
 
 use std::{
-  collections::HashMap,
   env::{var, var_os},
-  fs::{copy, create_dir, create_dir_all, read_to_string, remove_dir_all, File},
-  io::Write,
+  fs::{copy, create_dir, create_dir_all, remove_dir_all, write},
   path::{Path, PathBuf},
-  thread::sleep,
-  time::{Duration, SystemTime},
 };
 
 use anyhow::{Context, Result};
 use serde::{Deserialize, Serialize};
 
-#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
+#[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
 pub(crate) struct PluginMetadata {
   pub path: PathBuf,
 }
@@ -69,48 +65,7 @@ impl PluginBuilder {
           )
           .context("failed to copy tauri-api to the plugin project")?;
 
-          if let Some(project_dir) = var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) {
-            let pkg_name = var("CARGO_PKG_NAME").unwrap();
-            println!("cargo:rerun-if-env-changed=TAURI_ANDROID_PROJECT_PATH");
-
-            let plugins_json_path = project_dir.join(".tauri").join("plugins.json");
-            let mut plugins: HashMap<String, PluginMetadata> = if plugins_json_path.exists() {
-              let s = read_to_string(&plugins_json_path)?;
-              serde_json::from_str(&s)?
-            } else {
-              Default::default()
-            };
-
-            let metadata = PluginMetadata { path: source };
-            let already_set = plugins
-              .get(&pkg_name)
-              .map(|m| m == &metadata)
-              .unwrap_or(false);
-            if !already_set {
-              plugins.insert(pkg_name, metadata);
-              let mut file = File::create(&plugins_json_path)?;
-              file.write_all(serde_json::to_string(&plugins)?.as_bytes())?;
-              file.flush()?;
-
-              // wait for the file to be written before moving to the app build script
-              let now = SystemTime::now()
-                .checked_sub(Duration::from_millis(10))
-                .unwrap();
-              let mut attempts = 0;
-              while !plugins_json_path
-                .metadata()
-                .map(|m| m.modified().unwrap() >= now)
-                .unwrap_or(false)
-              {
-                attempts += 1;
-                if attempts == 10 {
-                  anyhow::bail!("Could not determine whether the plugins.json file has been modified or not, please rerun the build.");
-                }
-                sleep(Duration::from_millis(100));
-              }
-            }
-            println!("cargo:rerun-if-changed={}", plugins_json_path.display());
-          }
+          println!("cargo:android_library_path={}", source.display());
         }
       }
       #[cfg(target_os = "macos")]
@@ -190,3 +145,56 @@ fn copy_folder(source: &Path, target: &Path, ignore_paths: &[&str]) -> Result<()
 
   Ok(())
 }
+
+pub(crate) fn generate_gradle_files(project_dir: PathBuf) -> 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 mut gradle_settings =
+    "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n".to_string();
+  let mut app_build_gradle = "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+val implementation by configurations
+dependencies {"
+    .to_string();
+
+  for (env, value) in std::env::vars_os() {
+    let env = env.to_string_lossy();
+    if env.starts_with("DEP_") && env.ends_with("_ANDROID_LIBRARY_PATH") {
+      let name_len = env.len() - "DEP_".len() - "_ANDROID_LIBRARY_PATH".len();
+      let mut plugin_name = env
+        .chars()
+        .skip("DEP_".len())
+        .take(name_len)
+        .collect::<String>()
+        .to_lowercase()
+        .replace('_', "-");
+      if plugin_name == "tauri" {
+        plugin_name = "tauri-android".into();
+      }
+      let plugin_path = PathBuf::from(value);
+
+      gradle_settings.push_str(&format!("include ':{plugin_name}'"));
+      gradle_settings.push('\n');
+      gradle_settings.push_str(&format!(
+        "project(':{plugin_name}').projectDir = new File({:?})",
+        tauri_utils::display_path(plugin_path)
+      ));
+      gradle_settings.push('\n');
+
+      app_build_gradle.push('\n');
+      app_build_gradle.push_str(&format!(r#"  implementation(project(":{plugin_name}"))"#));
+    }
+  }
+
+  app_build_gradle.push_str("\n}");
+
+  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")?;
+
+  println!("cargo:rerun-if-changed={}", gradle_settings_path.display());
+  println!("cargo:rerun-if-changed={}", app_build_gradle_path.display());
+
+  Ok(())
+}

+ 1 - 0
core/tauri/build.rs

@@ -116,6 +116,7 @@ fn main() {
       )
       .expect("failed to write proguard-tauri.pro");
     }
+
     let lib_path =
       PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("mobile/android");
     println!("cargo:android_library_path={}", lib_path.display());

+ 1 - 0
examples/api/src-tauri/tauri-plugin-sample/Cargo.toml

@@ -2,6 +2,7 @@
 name = "tauri-plugin-sample"
 version = "0.1.0"
 edition = "2021"
+links = "tauri-plugin-sample"
 
 [dependencies]
 tauri = { path = "../../../../core/tauri" }

+ 8 - 7
tooling/cli/src/mobile/android/build.rs

@@ -81,6 +81,12 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
       set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", "");
       set_var("WRY_RUSTWEBVIEW_CLASS_INIT", "");
 
+      let profile = if options.debug {
+        Profile::Debug
+      } else {
+        Profile::Release
+      };
+
       ensure_init(config.project_dir(), MobileTarget::Android)?;
 
       let mut env = env()?;
@@ -101,7 +107,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
       )?;
 
       let open = options.open;
-      run_build(options, config, &mut env, noise_level)?;
+      run_build(options, profile, config, &mut env, noise_level)?;
 
       if open {
         open_and_wait(config, &env);
@@ -115,16 +121,11 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
 
 fn run_build(
   mut options: Options,
+  profile: Profile,
   config: &AndroidConfig,
   env: &mut Env,
   noise_level: NoiseLevel,
 ) -> Result<()> {
-  let profile = if options.debug {
-    Profile::Debug
-  } else {
-    Profile::Release
-  };
-
   if !(options.apk || options.aab) {
     // if the user didn't specify the format to build, we'll do both
     options.apk = true;

+ 2 - 7
tooling/cli/src/mobile/mod.rs

@@ -24,7 +24,7 @@ use std::{
   env::{set_var, temp_dir},
   ffi::OsString,
   fmt::Write,
-  fs::{create_dir_all, read_to_string, remove_file, write},
+  fs::{read_to_string, write},
   net::SocketAddr,
   path::PathBuf,
   process::{exit, ExitStatus},
@@ -315,13 +315,8 @@ fn ensure_init(project_dir: PathBuf, target: Target) -> Result<()> {
       project_dir.display(),
       target.command_name(),
     )
-  } else {
-    if target == Target::Android {
-      create_dir_all(project_dir.join(".tauri"))?;
-      let _ = remove_file(project_dir.join(".tauri").join("plugins.json"));
-    }
-    Ok(())
   }
+  Ok(())
 }
 
 fn log_finished(outputs: Vec<PathBuf>, kind: &str) {

+ 1 - 1
tooling/cli/templates/mobile/android/buildSrc/src/main/kotlin/BuildTask.kt

@@ -15,7 +15,7 @@ open class BuildTask : DefaultTask() {
     var release: Boolean? = null
 
     @TaskAction
-    fun build() {
+    fun assemble() {
         val executable = """{{tauri-binary}}""";
         try {
             runTauriCli(executable)

+ 1 - 0
tooling/cli/templates/plugin/Cargo.crate-manifest

@@ -6,6 +6,7 @@ description = ""
 edition = "2021"
 rust-version = "1.65"
 exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"]
+links = "tauri-plugin-{{ plugin_name }}"
 
 [dependencies]
 tauri = {{  tauri_dep }}