瀏覽代碼

feat(core): inject src-tauri/Info.plist file on dev and merge on bundle, closes #1570 #2338 (#2444)

Lucas Fernandes Nogueira 4 年之前
父節點
當前提交
537ab1b6d5

+ 5 - 0
.changes/bundler-merge-info-plist.md

@@ -0,0 +1,5 @@
+---
+"tauri-bundler": patch
+---
+
+Merge Tauri-generated Info.plist with the contents of `src-tauri/Info.plist` if it exists.

+ 6 - 0
.changes/embed-plist.md

@@ -0,0 +1,6 @@
+---
+"tauri-codegen": patch
+"tauri": patch
+---
+
+Embed Info.plist file contents on binary on dev.

+ 20 - 0
core/tauri-codegen/src/context.rs

@@ -144,6 +144,25 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
     quote!(None)
   };
 
+  #[cfg(target_os = "macos")]
+  let info_plist = {
+    if dev {
+      let info_plist_path = config_parent.join("Info.plist");
+      if info_plist_path.exists() {
+        let info_plist_path = info_plist_path.display().to_string();
+        quote!({
+          tauri::embed_plist::embed_info_plist!(#info_plist_path);
+        })
+      } else {
+        quote!(())
+      }
+    } else {
+      quote!(())
+    }
+  };
+  #[cfg(not(target_os = "macos"))]
+  let info_plist = quote!(());
+
   // double braces are purposeful to force the code into a block expression
   Ok(quote!(#root::Context::new(
     #config,
@@ -151,6 +170,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
     #default_window_icon,
     #system_tray_icon,
     #package_info,
+    #info_plist,
   )))
 }
 

+ 3 - 0
core/tauri/Cargo.toml

@@ -76,6 +76,9 @@ futures-lite = "1.12"
 gtk = { version = "0.14", features = [ "v3_20" ] }
 glib = "0.14"
 
+[target."cfg(target_os = \"macos\")".dependencies]
+embed_plist = "1.2"
+
 [build-dependencies]
 cfg_aliases = "0.1.1"
 

+ 18 - 2
core/tauri/src/lib.rs

@@ -19,6 +19,9 @@
 #![warn(missing_docs, rust_2018_idioms)]
 #![cfg_attr(doc_cfg, feature(doc_cfg))]
 
+#[cfg(target_os = "macos")]
+#[doc(hidden)]
+pub use embed_plist;
 /// The Tauri error enum.
 pub use error::Error;
 pub use tauri_macros::{command, generate_handler};
@@ -60,7 +63,7 @@ use crate::{
   runtime::window::PendingWindow,
 };
 use serde::Serialize;
-use std::{collections::HashMap, sync::Arc};
+use std::{collections::HashMap, fmt, sync::Arc};
 
 // Export types likely to be used by the application.
 pub use runtime::menu::CustomMenuItem;
@@ -146,13 +149,24 @@ macro_rules! tauri_build_context {
 /// # Stability
 /// This is the output of the `tauri::generate_context!` macro, and is not considered part of the stable API.
 /// Unless you know what you are doing and are prepared for this type to have breaking changes, do not create it yourself.
-#[derive(Debug)]
 pub struct Context<A: Assets> {
   pub(crate) config: Config,
   pub(crate) assets: Arc<A>,
   pub(crate) default_window_icon: Option<Vec<u8>>,
   pub(crate) system_tray_icon: Option<Icon>,
   pub(crate) package_info: crate::api::PackageInfo,
+  pub(crate) _info_plist: (),
+}
+
+impl<A: Assets> fmt::Debug for Context<A> {
+  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    f.debug_struct("Context")
+      .field("config", &self.config)
+      .field("default_window_icon", &self.default_window_icon)
+      .field("system_tray_icon", &self.system_tray_icon)
+      .field("package_info", &self.package_info)
+      .finish()
+  }
 }
 
 impl<A: Assets> Context<A> {
@@ -224,6 +238,7 @@ impl<A: Assets> Context<A> {
     default_window_icon: Option<Vec<u8>>,
     system_tray_icon: Option<Icon>,
     package_info: crate::api::PackageInfo,
+    info_plist: (),
   ) -> Self {
     Self {
       config,
@@ -231,6 +246,7 @@ impl<A: Assets> Context<A> {
       default_window_icon,
       system_tray_icon,
       package_info,
+      _info_plist: info_plist,
     }
   }
 }

+ 10 - 0
examples/api/src-tauri/Info.plist

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSCameraUsageDescription</key>
+	<string>Request camera access for WebRTC</string>
+	<key>NSMicrophoneUsageDescription</key>
+	<string>Request microphone access for WebRTC</string>
+</dict>
+</plist>

+ 24 - 1
tooling/bundler/src/bundle/macos/app.rs

@@ -181,7 +181,9 @@ fn create_info_plist(
   settings: &Settings,
 ) -> crate::Result<()> {
   let build_number = chrono::Utc::now().format("%Y%m%d.%H%M%S");
-  let file = &mut common::create_file(&bundle_dir.join("Info.plist"))?;
+
+  let bundle_plist_path = bundle_dir.join("Info.plist");
+  let file = &mut common::create_file(&bundle_plist_path)?;
   let use_bootstrapper = settings.macos().use_bootstrapper.unwrap_or_default();
   write!(
     file,
@@ -296,6 +298,27 @@ fn create_info_plist(
 
   write!(file, "</dict>\n</plist>\n")?;
   file.flush()?;
+
+  if let Some(user_plist_path) = &settings.macos().info_plist_path {
+    let mut cmd = Command::new("/usr/libexec/PlistBuddy");
+    cmd.args(&[
+      "-c".into(),
+      format!("Merge {}", user_plist_path.display()),
+      bundle_plist_path.display().to_string(),
+    ]);
+
+    common::execute_with_verbosity(&mut cmd, settings).map_err(|_| {
+      crate::Error::ShellScriptError(format!(
+        "error running /usr/libexec/PlistBuddy{}",
+        if settings.is_verbose() {
+          ""
+        } else {
+          ", try running with --verbose to see command output"
+        }
+      ))
+    })?;
+  }
+
   Ok(())
 }
 

+ 2 - 0
tooling/bundler/src/bundle/settings.rs

@@ -170,6 +170,8 @@ pub struct MacOsSettings {
   pub signing_identity: Option<String>,
   /// Path to the entitlements.plist file.
   pub entitlements: Option<String>,
+  /// Path to the Info.plist file for the bundle.
+  pub info_plist_path: Option<PathBuf>,
 }
 
 /// Settings specific to the WiX implementation.

+ 8 - 0
tooling/cli.rs/src/interface/rust.rs

@@ -436,6 +436,14 @@ fn tauri_config_to_bundle_settings(
       exception_domain: config.macos.exception_domain,
       signing_identity,
       entitlements: config.macos.entitlements,
+      info_plist_path: {
+        let path = tauri_dir().join("Info.plist");
+        if path.exists() {
+          Some(path)
+        } else {
+          None
+        }
+      },
     },
     windows: WindowsSettings {
       timestamp_url: config.windows.timestamp_url,