Skip to content

Commit 7ba67b4

Browse files
authored
refactor!: use localhost for development on Android devices and emulators or iOS simulators (#10437)
* feat(cli): use localhost on mobile! * change cargo-mobile2 * use public network address on iOS device :( * add change file * actually breaking * pin cargo-mobile2 * rename env var
1 parent a5bfbaa commit 7ba67b4

File tree

13 files changed

+236
-339
lines changed

13 files changed

+236
-339
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"tauri-cli": patch:breaking
3+
"@tauri-apps/cli": patch:breaking
4+
---
5+
6+
`ios dev` and `android dev` now uses localhost for the development server unless running on an iOS device,
7+
which still requires connecting to the public network address. To conditionally check this on your frontend
8+
framework's configuration you can check for the existence of the `TAURI_DEV_HOST`
9+
environment variable instead of checking if the target is iOS or Android (previous recommendation).

examples/api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
},
1212
"dependencies": {
1313
"@tauri-apps/api": "../../tooling/api/dist",
14-
"@zerodevx/svelte-json-view": "1.0.9"
14+
"@zerodevx/svelte-json-view": "1.0.9",
15+
"internal-ip": "^7.0.0"
1516
},
1617
"devDependencies": {
1718
"@iconify-json/codicon": "^1.1.49",
1819
"@iconify-json/ph": "^1.1.13",
1920
"@sveltejs/vite-plugin-svelte": "^3.1.1",
2021
"@unocss/extractor-svelte": "^0.61.0",
21-
"internal-ip": "^8.0.0",
2222
"svelte": "^4.2.18",
2323
"unocss": "^0.61.0",
2424
"vite": "^5.3.2"

examples/api/vite.config.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Unocss from 'unocss/vite'
77
import { svelte } from '@sveltejs/vite-plugin-svelte'
88
import { internalIpV4Sync } from 'internal-ip'
99

10-
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM)
10+
const host = process.env.TAURI_DEV_HOST
1111

1212
// https://vitejs.dev/config/
1313
export default defineConfig({
@@ -27,13 +27,13 @@ export default defineConfig({
2727
clearScreen: false,
2828
// tauri expects a fixed port, fail if that port is not available
2929
server: {
30-
host: mobile ? '0.0.0.0' : false,
30+
host: host ? '0.0.0.0' : false,
3131
port: 1420,
3232
strictPort: true,
33-
hmr: mobile
33+
hmr: host
3434
? {
3535
protocol: 'ws',
36-
host: mobile ? internalIpV4Sync() : 'localhost',
36+
host: internalIpV4Sync(),
3737
port: 1430
3838
}
3939
: undefined,

examples/api/yarn.lock

Lines changed: 45 additions & 153 deletions
Large diffs are not rendered by default.

tooling/cli/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ name = "cargo-tauri"
3939
path = "src/main.rs"
4040

4141
[dependencies]
42-
cargo-mobile2 = { version = "0.12.1", default-features = false }
42+
cargo-mobile2 = { version = "0.13", default-features = false }
4343
jsonrpsee = { version = "0.22", features = [ "server" ] }
4444
jsonrpsee-core = "0.22"
4545
jsonrpsee-client-transport = { version = "0.22", features = [ "ws" ] }

tooling/cli/src/dev.rs

Lines changed: 7 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tauri_utils::platform::Target;
2121

2222
use std::{
2323
env::set_current_dir,
24-
net::{IpAddr, Ipv4Addr},
24+
net::Ipv4Addr,
2525
process::{exit, Command, Stdio},
2626
sync::{
2727
atomic::{AtomicBool, Ordering},
@@ -75,9 +75,6 @@ pub struct Options {
7575
/// Disable the file watcher.
7676
#[clap(long)]
7777
pub no_watch: bool,
78-
/// Force prompting for an IP to use to connect to the dev server on mobile.
79-
#[clap(long)]
80-
pub force_ip_prompt: bool,
8178

8279
/// Disable the built-in dev server for static files.
8380
#[clap(long)]
@@ -109,7 +106,7 @@ fn command_internal(mut options: Options) -> Result<()> {
109106
options.target.clone(),
110107
)?;
111108

112-
setup(&interface, &mut options, config, false)?;
109+
setup(&interface, &mut options, config)?;
113110

114111
let exit_on_panic = options.exit_on_panic;
115112
let no_watch = options.no_watch;
@@ -118,67 +115,10 @@ fn command_internal(mut options: Options) -> Result<()> {
118115
})
119116
}
120117

121-
pub fn local_ip_address(force: bool) -> &'static IpAddr {
122-
static LOCAL_IP: OnceLock<IpAddr> = OnceLock::new();
123-
LOCAL_IP.get_or_init(|| {
124-
let prompt_for_ip = || {
125-
let addresses: Vec<IpAddr> = local_ip_address::list_afinet_netifas()
126-
.expect("failed to list networks")
127-
.into_iter()
128-
.map(|(_, ipaddr)| ipaddr)
129-
.filter(|ipaddr| match ipaddr {
130-
IpAddr::V4(i) => i != &Ipv4Addr::LOCALHOST,
131-
_ => false,
132-
})
133-
.collect();
134-
match addresses.len() {
135-
0 => panic!("No external IP detected."),
136-
1 => {
137-
let ipaddr = addresses.first().unwrap();
138-
*ipaddr
139-
}
140-
_ => {
141-
let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default())
142-
.with_prompt(
143-
"Failed to detect external IP, What IP should we use to access your development server?",
144-
)
145-
.items(&addresses)
146-
.default(0)
147-
.interact()
148-
.expect("failed to select external IP");
149-
*addresses.get(selected).unwrap()
150-
}
151-
}
152-
};
153-
154-
let ip = if force {
155-
prompt_for_ip()
156-
} else {
157-
local_ip_address::local_ip().unwrap_or_else(|_| prompt_for_ip())
158-
};
159-
log::info!("Using {ip} to access the development server.");
160-
ip
161-
})
162-
}
163-
164-
pub fn setup(
165-
interface: &AppInterface,
166-
options: &mut Options,
167-
config: ConfigHandle,
168-
mobile: bool,
169-
) -> Result<()> {
118+
pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHandle) -> Result<()> {
170119
let tauri_path = tauri_dir();
171120
set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?;
172121

173-
let mut dev_url = config
174-
.lock()
175-
.unwrap()
176-
.as_ref()
177-
.unwrap()
178-
.build
179-
.dev_url
180-
.clone();
181-
182122
if let Some(before_dev) = config
183123
.lock()
184124
.unwrap()
@@ -196,25 +136,7 @@ pub fn setup(
196136
}
197137
};
198138
let cwd = script_cwd.unwrap_or_else(|| app_dir().clone());
199-
if let Some(mut before_dev) = script {
200-
if before_dev.contains("$HOST") {
201-
if mobile {
202-
let local_ip_address = local_ip_address(options.force_ip_prompt).to_string();
203-
before_dev = before_dev.replace("$HOST", &local_ip_address);
204-
if let Some(url) = &mut dev_url {
205-
url.set_host(Some(&local_ip_address))?;
206-
}
207-
} else {
208-
before_dev = before_dev.replace(
209-
"$HOST",
210-
if let Some(url) = &dev_url {
211-
url.host_str().unwrap_or("127.0.0.1")
212-
} else {
213-
"127.0.0.1"
214-
},
215-
);
216-
}
217-
}
139+
if let Some(before_dev) = script {
218140
log::info!(action = "Running"; "BeforeDevCommand (`{}`)", before_dev);
219141
let mut env = command_env(true);
220142
env.extend(interface.env());
@@ -326,12 +248,9 @@ pub fn setup(
326248
if let Some(FrontendDist::Directory(path)) = &frontend_dist {
327249
if path.exists() {
328250
let path = path.canonicalize()?;
329-
let ip = if mobile {
330-
*local_ip_address(options.force_ip_prompt)
331-
} else {
332-
Ipv4Addr::new(127, 0, 0, 1).into()
333-
};
334-
let server_url = builtin_dev_server::start(path, ip, options.port)?;
251+
252+
let server_url =
253+
builtin_dev_server::start(path, Ipv4Addr::new(127, 0, 0, 1).into(), options.port)?;
335254
let server_url = format!("http://{server_url}");
336255
dev_url = Some(server_url.parse().unwrap());
337256

tooling/cli/src/mobile/android/dev.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use super::{
66
configure_cargo, delete_codegen_vars, device_prompt, ensure_init, env, get_app, get_config,
7-
inject_assets, open_and_wait, setup_dev_config, MobileTarget,
7+
inject_assets, open_and_wait, MobileTarget,
88
};
99
use crate::{
1010
dev::Options as DevOptions,
@@ -22,6 +22,7 @@ use clap::{ArgAction, Parser};
2222
use anyhow::Context;
2323
use cargo_mobile2::{
2424
android::{
25+
adb,
2526
config::{Config as AndroidConfig, Metadata as AndroidMetadata},
2627
device::Device,
2728
env::Env,
@@ -63,9 +64,6 @@ pub struct Options {
6364
pub open: bool,
6465
/// Runs on the given device name
6566
pub device: Option<String>,
66-
/// Force prompting for an IP to use to connect to the dev server on mobile.
67-
#[clap(long)]
68-
pub force_ip_prompt: bool,
6967
/// Disable the built-in dev server for static files.
7068
#[clap(long)]
7169
pub no_dev_server: bool,
@@ -87,7 +85,6 @@ impl From<Options> for DevOptions {
8785
no_dev_server_wait: options.no_dev_server_wait,
8886
no_dev_server: options.no_dev_server,
8987
port: options.port,
90-
force_ip_prompt: options.force_ip_prompt,
9188
release_mode: options.release_mode,
9289
}
9390
}
@@ -166,7 +163,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
166163
#[allow(clippy::too_many_arguments)]
167164
fn run_dev(
168165
mut interface: AppInterface,
169-
mut options: Options,
166+
options: Options,
170167
mut dev_options: DevOptions,
171168
tauri_config: ConfigHandle,
172169
device: Option<Device>,
@@ -176,13 +173,7 @@ fn run_dev(
176173
metadata: &AndroidMetadata,
177174
noise_level: NoiseLevel,
178175
) -> Result<()> {
179-
setup_dev_config(
180-
MobileTarget::Android,
181-
&mut options.config,
182-
options.force_ip_prompt,
183-
)?;
184-
185-
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone(), true)?;
176+
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?;
186177

187178
let interface_options = InterfaceOptions {
188179
debug: !dev_options.release_mode,
@@ -216,6 +207,19 @@ fn run_dev(
216207
},
217208
)?;
218209

210+
let dev_url = tauri_config
211+
.lock()
212+
.unwrap()
213+
.as_ref()
214+
.unwrap()
215+
.build
216+
.dev_url
217+
.clone();
218+
if let Some(port) = dev_url.and_then(|url| url.port_or_known_default()) {
219+
let forward = format!("tcp:{port}");
220+
adb::adb(&env, ["reverse", &forward, &forward]).run()?;
221+
}
222+
219223
let open = options.open;
220224
let exit_on_panic = options.exit_on_panic;
221225
let no_watch = options.no_watch;

tooling/cli/src/mobile/android/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use sublime_fuzzy::best_match;
2929
use super::{
3030
ensure_init, get_app,
3131
init::{command as init_command, configure_cargo},
32-
log_finished, read_options, setup_dev_config, CliOptions, OptionsHandle, Target as MobileTarget,
32+
log_finished, read_options, CliOptions, OptionsHandle, Target as MobileTarget,
3333
MIN_DEVICE_MATCH_SCORE,
3434
};
3535
use crate::{helpers::config::Config as TauriConfig, Result};

0 commit comments

Comments
 (0)