Skip to content

Commit 6f06150

Browse files
authored
feat(cli): add android dev and ios dev commands (#4982)
1 parent f445f37 commit 6f06150

File tree

47 files changed

+1629
-691
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1629
-691
lines changed

.changes/cli-mobile-dev.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"cli.rs": minor
3+
"cli.js": minor
4+
---
5+
6+
Added `android dev` and `ios dev` commands.

.changes/codegen-mobile-devurl.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-codegen": patch
3+
---
4+
5+
Change `devPath` URL to use the local IP address on iOS and Android.

.changes/dev-proxy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": major
3+
---
4+
5+
**Breaking change:** Use the custom protocol as a proxy to the development server on all platforms except Linux.

core/tauri-codegen/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ semver = "1"
2929
ico = "0.1"
3030
png = "0.17"
3131
json-patch = "0.2"
32+
local-ip-address = "0.4"
33+
url = "2"
3234

3335
[target."cfg(target_os = \"macos\")".dependencies]
3436
plist = "1"

core/tauri-codegen/src/context.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ enum Target {
122122
pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
123123
let ContextData {
124124
dev,
125-
config,
125+
mut config,
126126
config_parent,
127127
root,
128128
} = data;
@@ -155,6 +155,23 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
155155
panic!("unknown codegen target");
156156
};
157157

158+
if dev && (target == Target::Ios || target == Target::Android) {
159+
if let AppUrl::Url(WindowUrl::External(url)) = &mut config.build.dev_path {
160+
let localhost = match url.host() {
161+
Some(url::Host::Domain(d)) => d == "localhost",
162+
Some(url::Host::Ipv4(i)) => {
163+
i == std::net::Ipv4Addr::LOCALHOST || i == std::net::Ipv4Addr::UNSPECIFIED
164+
}
165+
_ => false,
166+
};
167+
if localhost {
168+
if let Ok(ip) = local_ip_address::local_ip() {
169+
url.set_host(Some(&ip.to_string())).unwrap();
170+
}
171+
}
172+
}
173+
}
174+
158175
let mut options = AssetOptions::new(config.tauri.pattern.clone())
159176
.freeze_prototype(config.tauri.security.freeze_prototype)
160177
.dangerous_disable_asset_csp_modification(

core/tauri-codegen/src/embedded_assets.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ impl ToTokens for EmbeddedAssets {
431431

432432
// we expect phf related items to be in path when generating the path code
433433
tokens.append_all(quote! {{
434+
#[allow(unused_imports)]
434435
use ::tauri::utils::assets::{CspHash, EmbeddedAssets, phf, phf::phf_map};
435436
EmbeddedAssets::new(phf_map! { #assets }, &[#global_hashes], phf_map! { #html_hashes })
436437
}});

core/tauri-utils/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2364,7 +2364,7 @@ fn default_dialog() -> bool {
23642364
#[serde(rename_all = "camelCase", deny_unknown_fields)]
23652365
pub struct IosConfig {
23662366
/// The development team. This value is required for iOS development because code signing is enforced.
2367-
/// The `APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.
2367+
/// The `TAURI_APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.
23682368
#[serde(alias = "development-team")]
23692369
pub development_team: Option<String>,
23702370
}

core/tauri/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ base64 = { version = "0.13", optional = true }
7575
clap = { version = "3", optional = true }
7676
reqwest = { version = "0.11", features = [ "json", "stream" ], optional = true }
7777
bytes = { version = "1", features = [ "serde" ], optional = true }
78-
attohttpc = { version = "0.20", features = [ "compress", "json", "form" ], optional = true }
78+
attohttpc = { version = "0.20", features = [ "compress", "json", "form" ] }
7979
open = { version = "3.0", optional = true }
8080
shared_child = { version = "1.0", optional = true }
8181
os_pipe = { version = "1.0", optional = true }
@@ -146,7 +146,7 @@ updater = [
146146
"dialog-ask",
147147
"fs-extract-api"
148148
]
149-
http-api = [ "attohttpc" ]
149+
http-api = [ ]
150150
http-multipart = [ "attohttpc/multipart-form", "reqwest/multipart" ]
151151
shell-open-api = [ "open", "regex", "tauri-macros/shell-scope" ]
152152
fs-extract-api = [ "zip" ]

core/tauri/src/manager.rs

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,6 @@ fn set_csp<R: Runtime>(
142142
Csp::DirectiveMap(csp).to_string()
143143
}
144144

145-
#[cfg(target_os = "linux")]
146-
fn set_html_csp(html: &str, csp: &str) -> String {
147-
html.replacen(tauri_utils::html::CSP_TOKEN, csp, 1)
148-
}
149-
150145
// inspired by https://github.com/rust-lang/rust/blob/1be5c8f90912c446ecbdc405cbc4a89f9acd20fd/library/alloc/src/str.rs#L260-L297
151146
fn replace_with_callback<F: FnMut() -> String>(
152147
original: &str,
@@ -374,7 +369,13 @@ impl<R: Runtime> WindowManager<R> {
374369
/// Get the origin as it will be seen in the webview.
375370
fn get_browser_origin(&self) -> String {
376371
match self.base_path() {
377-
AppUrl::Url(WindowUrl::External(url)) => url.origin().ascii_serialization(),
372+
AppUrl::Url(WindowUrl::External(url)) => {
373+
if cfg!(dev) && !cfg!(target_os = "linux") {
374+
format_real_schema("tauri")
375+
} else {
376+
url.origin().ascii_serialization()
377+
}
378+
}
378379
_ => format_real_schema("tauri"),
379380
}
380381
}
@@ -820,8 +821,12 @@ impl<R: Runtime> WindowManager<R> {
820821
>,
821822
) -> Box<dyn Fn(&HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>> + Send + Sync>
822823
{
824+
#[cfg(dev)]
825+
let url = self.get_url().into_owned();
826+
#[cfg(not(dev))]
823827
let manager = self.clone();
824828
let window_origin = window_origin.to_string();
829+
825830
Box::new(move |request| {
826831
let path = request
827832
.uri()
@@ -834,32 +839,47 @@ impl<R: Runtime> WindowManager<R> {
834839
// the `strip_prefix` only returns None when a request is made to `https://tauri.$P` on Windows
835840
// where `$P` is not `localhost/*`
836841
.unwrap_or_else(|| "".to_string());
837-
let asset = manager.get_asset(path)?;
838-
let mut builder = HttpResponseBuilder::new()
839-
.header("Access-Control-Allow-Origin", &window_origin)
840-
.mimetype(&asset.mime_type);
841-
if let Some(csp) = &asset.csp_header {
842-
builder = builder.header("Content-Security-Policy", csp);
843-
}
844-
let mut response = builder.body(asset.bytes)?;
845-
if let Some(handler) = &web_resource_request_handler {
846-
handler(request, &mut response);
847842

848-
// if it's an HTML file, we need to set the CSP meta tag on Linux
849-
#[cfg(target_os = "linux")]
850-
if let Some(response_csp) = response.headers().get("Content-Security-Policy") {
851-
let response_csp = String::from_utf8_lossy(response_csp.as_bytes());
852-
let body = set_html_csp(&String::from_utf8_lossy(response.body()), &response_csp);
853-
*response.body_mut() = body.as_bytes().to_vec();
854-
}
855-
} else {
856-
#[cfg(target_os = "linux")]
857-
{
858-
if let Some(csp) = &asset.csp_header {
859-
let body = set_html_csp(&String::from_utf8_lossy(response.body()), csp);
860-
*response.body_mut() = body.as_bytes().to_vec();
843+
let mut builder =
844+
HttpResponseBuilder::new().header("Access-Control-Allow-Origin", &window_origin);
845+
846+
#[cfg(dev)]
847+
let mut response = {
848+
let mut url = url.clone();
849+
url.set_path(&path);
850+
match attohttpc::get(url.as_str()).send() {
851+
Ok(r) => {
852+
for (name, value) in r.headers() {
853+
builder = builder.header(name, value);
854+
}
855+
builder.status(r.status()).body(r.bytes()?)?
856+
}
857+
Err(e) => {
858+
debug_eprintln!("Failed to request {}: {}", url.path(), e);
859+
return Err(Box::new(e));
861860
}
862861
}
862+
};
863+
864+
#[cfg(not(dev))]
865+
let mut response = {
866+
let asset = manager.get_asset(path)?;
867+
builder = builder.mimetype(&asset.mime_type);
868+
if let Some(csp) = &asset.csp_header {
869+
builder = builder.header("Content-Security-Policy", csp);
870+
}
871+
builder.body(asset.bytes)?
872+
};
873+
if let Some(handler) = &web_resource_request_handler {
874+
handler(request, &mut response);
875+
}
876+
// if it's an HTML file, we need to set the CSP meta tag on Linux
877+
#[cfg(all(not(dev), target_os = "linux"))]
878+
if let Some(response_csp) = response.headers().get("Content-Security-Policy") {
879+
let response_csp = String::from_utf8_lossy(response_csp.as_bytes());
880+
let html = String::from_utf8_lossy(response.body());
881+
let body = html.replacen(tauri_utils::html::CSP_TOKEN, &response_csp, 1);
882+
*response.body_mut() = body.as_bytes().to_vec();
863883
}
864884
Ok(response)
865885
})
@@ -1061,7 +1081,10 @@ impl<R: Runtime> WindowManager<R> {
10611081
#[allow(unused_mut)] // mut url only for the data-url parsing
10621082
let (is_local, mut url) = match &pending.webview_attributes.url {
10631083
WindowUrl::App(path) => {
1084+
#[cfg(target_os = "linux")]
10641085
let url = self.get_url();
1086+
#[cfg(not(target_os = "linux"))]
1087+
let url: Cow<'_, Url> = Cow::Owned(Url::parse("tauri://localhost").unwrap());
10651088
(
10661089
true,
10671090
// ignore "index.html" just to simplify the url
@@ -1078,7 +1101,13 @@ impl<R: Runtime> WindowManager<R> {
10781101
}
10791102
WindowUrl::External(url) => {
10801103
let config_url = self.get_url();
1081-
(config_url.make_relative(url).is_some(), url.clone())
1104+
let is_local = config_url.make_relative(url).is_some();
1105+
let mut url = url.clone();
1106+
if is_local && !cfg!(target_os = "linux") {
1107+
url.set_scheme("tauri").unwrap();
1108+
url.set_host(Some("localhost")).unwrap();
1109+
}
1110+
(is_local, url)
10821111
}
10831112
_ => unimplemented!(),
10841113
};

0 commit comments

Comments
 (0)