tauri_plugin/build/
mobile.rs1use std::{
8 fs::{copy, create_dir, create_dir_all, remove_dir_all},
9 path::{Path, PathBuf},
10};
11
12use anyhow::{Context, Result};
13
14use super::{build_var, cfg_alias};
15
16#[cfg(target_os = "macos")]
39pub fn update_entitlements<F: FnOnce(&mut plist::Dictionary)>(f: F) -> Result<()> {
40 if let (Some(project_path), Ok(app_name)) = (
41 std::env::var_os("TAURI_IOS_PROJECT_PATH").map(PathBuf::from),
42 std::env::var("TAURI_IOS_APP_NAME"),
43 ) {
44 update_plist_file(
45 project_path
46 .join(format!("{app_name}_iOS"))
47 .join(format!("{app_name}_iOS.entitlements")),
48 f,
49 )?;
50 }
51
52 Ok(())
53}
54
55#[cfg(target_os = "macos")]
82pub fn update_info_plist<F: FnOnce(&mut plist::Dictionary)>(f: F) -> Result<()> {
83 if let (Some(project_path), Ok(app_name)) = (
84 std::env::var_os("TAURI_IOS_PROJECT_PATH").map(PathBuf::from),
85 std::env::var("TAURI_IOS_APP_NAME"),
86 ) {
87 update_plist_file(
88 project_path
89 .join(format!("{app_name}_iOS"))
90 .join("Info.plist"),
91 f,
92 )?;
93 }
94
95 Ok(())
96}
97
98pub fn update_android_manifest(block_identifier: &str, parent: &str, insert: String) -> Result<()> {
100 tauri_utils::build::update_android_manifest(block_identifier, parent, insert)
101}
102
103pub(crate) fn setup(
104 android_path: Option<PathBuf>,
105 #[allow(unused_variables)] ios_path: Option<PathBuf>,
106) -> Result<()> {
107 let target_os = build_var("CARGO_CFG_TARGET_OS")?;
108 let mobile = target_os == "android" || target_os == "ios";
109 cfg_alias("mobile", mobile);
110 cfg_alias("desktop", !mobile);
111
112 if std::env::var_os("DOCS_RS").is_some() {
115 return Ok(());
116 }
117
118 match target_os.as_str() {
119 "android" => {
120 if let Some(path) = android_path {
121 let manifest_dir = build_var("CARGO_MANIFEST_DIR").map(PathBuf::from)?;
122 let source = manifest_dir.join(path);
123
124 let tauri_library_path = std::env::var("DEP_TAURI_ANDROID_LIBRARY_PATH")
125 .expect("missing `DEP_TAURI_ANDROID_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin.");
126 println!("cargo:rerun-if-env-changed=DEP_TAURI_ANDROID_LIBRARY_PATH");
127
128 create_dir_all(source.join(".tauri")).context("failed to create .tauri directory")?;
129 copy_folder(
130 Path::new(&tauri_library_path),
131 &source.join(".tauri").join("tauri-api"),
132 &[],
133 )
134 .context("failed to copy tauri-api to the plugin project")?;
135
136 println!("cargo:android_library_path={}", source.display());
137 }
138 }
139 #[cfg(target_os = "macos")]
140 "ios" => {
141 if let Some(path) = ios_path {
142 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
143 .map(PathBuf::from)
144 .unwrap();
145 let tauri_library_path = std::env::var("DEP_TAURI_IOS_LIBRARY_PATH")
146 .expect("missing `DEP_TAURI_IOS_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin.");
147
148 let tauri_dep_path = path.parent().unwrap().join(".tauri");
149 create_dir_all(&tauri_dep_path).context("failed to create .tauri directory")?;
150 copy_folder(
151 Path::new(&tauri_library_path),
152 &tauri_dep_path.join("tauri-api"),
153 &[".build", "Package.resolved", "Tests"],
154 )
155 .context("failed to copy tauri-api to the plugin project")?;
156 tauri_utils::build::link_apple_library(
157 &std::env::var("CARGO_PKG_NAME").unwrap(),
158 manifest_dir.join(path),
159 );
160 }
161 }
162 _ => (),
163 }
164
165 Ok(())
166}
167
168fn copy_folder(source: &Path, target: &Path, ignore_paths: &[&str]) -> Result<()> {
169 let _ = remove_dir_all(target);
170
171 for entry in walkdir::WalkDir::new(source) {
172 let entry = entry?;
173 let rel_path = entry.path().strip_prefix(source)?;
174 let rel_path_str = rel_path.to_string_lossy();
175 if ignore_paths
176 .iter()
177 .any(|path| rel_path_str.starts_with(path))
178 {
179 continue;
180 }
181 let dest_path = target.join(rel_path);
182
183 if entry.file_type().is_dir() {
184 create_dir(&dest_path)
185 .with_context(|| format!("failed to create directory {}", dest_path.display()))?;
186 } else {
187 copy(entry.path(), &dest_path).with_context(|| {
188 format!(
189 "failed to copy {} to {}",
190 entry.path().display(),
191 dest_path.display()
192 )
193 })?;
194 println!("cargo:rerun-if-changed={}", entry.path().display());
195 }
196 }
197
198 Ok(())
199}
200
201#[cfg(target_os = "macos")]
202fn update_plist_file<P: AsRef<Path>, F: FnOnce(&mut plist::Dictionary)>(
203 path: P,
204 f: F,
205) -> Result<()> {
206 use std::io::Cursor;
207
208 let path = path.as_ref();
209 if path.exists() {
210 let plist_str = std::fs::read_to_string(path)?;
211 let mut plist = plist::Value::from_reader(Cursor::new(&plist_str))?;
212 if let Some(dict) = plist.as_dictionary_mut() {
213 f(dict);
214 let mut plist_buf = Vec::new();
215 let writer = Cursor::new(&mut plist_buf);
216 plist::to_writer_xml(writer, &plist)?;
217 let new_plist_str = String::from_utf8(plist_buf)?;
218 if new_plist_str != plist_str {
219 std::fs::write(path, new_plist_str)?;
220 }
221 }
222 }
223
224 Ok(())
225}
226
227#[cfg(test)]
228mod tests {
229 #[test]
230 fn update_android_manifest() {
231 use tauri_utils::build::update_android_manifest;
232
233 let _result = update_android_manifest("test", "activity", "<test></test>".to_string());
236 }
237}