浏览代码

feat(cli): allow using iOS device tun address for dev server (#10456)

- Changes the IP prompt to also show IPV6 address ending with ::2 (usually device's address)
- Adds --host option on ios dev to force the host
- Also makes it work with our own dev server impl (builtin)
Lucas Fernandes Nogueira 1 年之前
父节点
当前提交
786f188923

+ 1 - 2
examples/api/package.json

@@ -11,8 +11,7 @@
   },
   "dependencies": {
     "@tauri-apps/api": "../../tooling/api/dist",
-    "@zerodevx/svelte-json-view": "1.0.9",
-    "internal-ip": "^7.0.0"
+    "@zerodevx/svelte-json-view": "1.0.9"
   },
   "devDependencies": {
     "@iconify-json/codicon": "^1.1.49",

+ 2 - 3
examples/api/vite.config.js

@@ -5,7 +5,6 @@
 import { defineConfig } from 'vite'
 import Unocss from 'unocss/vite'
 import { svelte } from '@sveltejs/vite-plugin-svelte'
-import { internalIpV4Sync } from 'internal-ip'
 
 const host = process.env.TAURI_DEV_HOST
 
@@ -27,13 +26,13 @@ export default defineConfig({
   clearScreen: false,
   // tauri expects a fixed port, fail if that port is not available
   server: {
-    host: host ? '0.0.0.0' : false,
+    host: host || false,
     port: 1420,
     strictPort: true,
     hmr: host
       ? {
           protocol: 'ws',
-          host: internalIpV4Sync(),
+          host: host,
           port: 1430
         }
       : undefined,

+ 1 - 54
examples/api/yarn.lock

@@ -1015,13 +1015,6 @@ deepmerge@^4.3.1:
   resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
   integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
 
-default-gateway@^6.0.3:
-  version "6.0.3"
-  resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
-  integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
-  dependencies:
-    execa "^5.0.0"
-
 defu@^6.1.4:
   version "6.1.4"
   resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479"
@@ -1098,7 +1091,7 @@ estree-walker@^3.0.0, estree-walker@^3.0.3:
   dependencies:
     "@types/estree" "^1.0.0"
 
-execa@^5.0.0, execa@^5.1.1:
+execa@^5.1.1:
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
   integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
@@ -1190,26 +1183,6 @@ human-signals@^2.1.0:
   resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
   integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
 
-internal-ip@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-7.0.0.tgz#5b1c6a9d7e188aa73a1b69717daf50c8d8ed774f"
-  integrity sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw==
-  dependencies:
-    default-gateway "^6.0.3"
-    ipaddr.js "^2.0.1"
-    is-ip "^3.1.0"
-    p-event "^4.2.0"
-
-ip-regex@^4.0.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
-  integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
-
-ipaddr.js@^2.0.1:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8"
-  integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==
-
 is-binary-path@~2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
@@ -1229,13 +1202,6 @@ is-glob@^4.0.1, is-glob@~4.0.1:
   dependencies:
     is-extglob "^2.1.1"
 
-is-ip@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8"
-  integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==
-  dependencies:
-    ip-regex "^4.0.0"
-
 is-number@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
@@ -1413,18 +1379,6 @@ onetime@^5.1.2:
   dependencies:
     mimic-fn "^2.1.0"
 
-p-event@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
-  integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
-  dependencies:
-    p-timeout "^3.1.0"
-
-p-finally@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
-  integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
-
 p-limit@^3.0.2:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
@@ -1439,13 +1393,6 @@ p-locate@^5.0.0:
   dependencies:
     p-limit "^3.0.2"
 
-p-timeout@^3.1.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
-  integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
-  dependencies:
-    p-finally "^1.0.0"
-
 path-exists@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"

+ 9 - 3
tooling/cli/src/dev.rs

@@ -21,7 +21,7 @@ use tauri_utils::platform::Target;
 
 use std::{
   env::set_current_dir,
-  net::Ipv4Addr,
+  net::{IpAddr, Ipv4Addr},
   process::{exit, Command, Stdio},
   sync::{
     atomic::{AtomicBool, Ordering},
@@ -82,6 +82,9 @@ pub struct Options {
   /// Specify port for the built-in dev server for static files. Defaults to 1430.
   #[clap(long, env = "TAURI_CLI_PORT")]
   pub port: Option<u16>,
+
+  #[clap(skip)]
+  pub host: Option<IpAddr>,
 }
 
 pub fn command(options: Options) -> Result<()> {
@@ -249,8 +252,11 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
       if path.exists() {
         let path = path.canonicalize()?;
 
-        let server_url =
-          builtin_dev_server::start(path, Ipv4Addr::new(127, 0, 0, 1).into(), options.port)?;
+        let ip = options
+          .host
+          .unwrap_or_else(|| Ipv4Addr::new(127, 0, 0, 1).into());
+
+        let server_url = builtin_dev_server::start(path, ip, options.port)?;
         let server_url = format!("http://{server_url}");
         dev_url = Some(server_url.parse().unwrap());
 

+ 1 - 0
tooling/cli/src/mobile/android/dev.rs

@@ -86,6 +86,7 @@ impl From<Options> for DevOptions {
       no_dev_server: options.no_dev_server,
       port: options.port,
       release_mode: options.release_mode,
+      host: None,
     }
   }
 }

+ 53 - 20
tooling/cli/src/mobile/ios/dev.rs

@@ -32,7 +32,7 @@ use cargo_mobile2::{
 
 use std::{
   env::set_current_dir,
-  net::{IpAddr, Ipv4Addr},
+  net::{IpAddr, Ipv4Addr, SocketAddr},
   sync::OnceLock,
 };
 
@@ -76,6 +76,7 @@ pub struct Options {
   #[clap(long)]
   pub force_ip_prompt: bool,
   /// Use the public network address for the development server.
+  /// If an actual address it provided, it is used instead of prompting to pick one.
   ///
   /// This option is particularly useful along the `--open` flag when you intend on running on a physical device.
   ///
@@ -87,7 +88,7 @@ pub struct Options {
   /// environment variable so you can check this on your framework's configuration to expose the development server
   /// on the public network address.
   #[clap(long)]
-  pub host: bool,
+  pub host: Option<Option<IpAddr>>,
   /// Disable the built-in dev server for static files.
   #[clap(long)]
   pub no_dev_server: bool,
@@ -110,6 +111,7 @@ impl From<Options> for DevOptions {
       no_dev_server: options.no_dev_server,
       no_dev_server_wait: options.no_dev_server_wait,
       port: options.port,
+      host: None,
     }
   }
 }
@@ -204,7 +206,8 @@ fn local_ip_address(force: bool) -> &'static IpAddr {
         .map(|(_, ipaddr)| ipaddr)
         .filter(|ipaddr| match ipaddr {
           IpAddr::V4(i) => i != &Ipv4Addr::LOCALHOST,
-          _ => false,
+          IpAddr::V6(i) => i.to_string().ends_with("::2"),
+
         })
         .collect();
       match addresses.len() {
@@ -239,8 +242,8 @@ fn local_ip_address(force: bool) -> &'static IpAddr {
 
 fn use_network_address_for_dev_url(
   config: &ConfigHandle,
-  config_extension: &mut Option<ConfigValue>,
-  force_ip_prompt: bool,
+  options: &mut Options,
+  dev_options: &mut DevOptions,
 ) -> crate::Result<()> {
   let mut dev_url = config
     .lock()
@@ -251,7 +254,7 @@ fn use_network_address_for_dev_url(
     .dev_url
     .clone();
 
-  if let Some(url) = &mut dev_url {
+  let ip = if let Some(url) = &mut dev_url {
     let localhost = match url.host() {
       Some(url::Host::Domain(d)) => d == "localhost",
       Some(url::Host::Ipv4(i)) => {
@@ -261,15 +264,23 @@ fn use_network_address_for_dev_url(
     };
 
     if localhost {
-      let ip = local_ip_address(force_ip_prompt).to_string();
-      println!(
-        "Replacing devUrl host with {ip}. {}. {}.",
-        "If your frontend is not listening on that address, try configuring your development server to use 0.0.0.0 as host",
-        "When this is required, Tauri sets the TAURI_DEV_HOST environment variable"
+      let ip = options
+        .host
+        .unwrap_or_default()
+        .unwrap_or_else(|| *local_ip_address(options.force_ip_prompt));
+      log::info!(
+        "Replacing devUrl host with {ip}. {}.",
+        "If your frontend is not listening on that address, try configuring your development server to use the `TAURI_DEV_HOST` environment variable or 0.0.0.0 as host"
       );
-      url.set_host(Some(&ip)).unwrap();
 
-      if let Some(c) = config_extension {
+      *url = url::Url::parse(&format!(
+        "{}://{}{}",
+        url.scheme(),
+        SocketAddr::new(ip, url.port_or_known_default().unwrap()),
+        url.path()
+      ))?;
+
+      if let Some(c) = &mut options.config {
         if let Some(build) = c
           .0
           .as_object_mut()
@@ -282,11 +293,34 @@ fn use_network_address_for_dev_url(
         let mut build = serde_json::Map::new();
         build.insert("devUrl".into(), url.to_string().into());
 
-        config_extension.replace(crate::ConfigValue(serde_json::json!({
-          "build": build
-        })));
+        options
+          .config
+          .replace(crate::ConfigValue(serde_json::json!({
+            "build": build
+          })));
       }
-      reload_config(config_extension.as_ref().map(|c| &c.0))?;
+      reload_config(options.config.as_ref().map(|c| &c.0))?;
+
+      Some(ip)
+    } else {
+      None
+    }
+  } else if !dev_options.no_dev_server {
+    let ip = options
+      .host
+      .unwrap_or_default()
+      .unwrap_or_else(|| *local_ip_address(options.force_ip_prompt));
+    dev_options.host.replace(ip.clone());
+    Some(ip)
+  } else {
+    None
+  };
+
+  if let Some(ip) = ip {
+    std::env::set_var("TAURI_DEV_HOST", ip.to_string());
+    if ip.is_ipv6() {
+      // in this case we can't ping the server for some reason
+      dev_options.no_dev_server_wait = true;
     }
   }
 
@@ -306,14 +340,13 @@ fn run_dev(
   noise_level: NoiseLevel,
 ) -> Result<()> {
   // when running on an actual device we must use the network IP
-  if options.host
+  if options.host.is_some()
     || device
       .as_ref()
       .map(|device| !matches!(device.kind(), DeviceKind::Simulator))
       .unwrap_or(false)
   {
-    std::env::set_var("TAURI_DEV_HOST", "true");
-    use_network_address_for_dev_url(&tauri_config, &mut options.config, options.force_ip_prompt)?;
+    use_network_address_for_dev_url(&tauri_config, &mut options, &mut dev_options)?;
   }
 
   crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?;

+ 0 - 1
tooling/cli/templates/plugin/__example-api/tauri-app/package.json

@@ -15,7 +15,6 @@
   },
   "devDependencies": {
     "@sveltejs/vite-plugin-svelte": "^1.0.1",
-    "internal-ip": "^7.0.0",
     "svelte": "^3.49.0",
     "vite": "^3.0.2",
     "@tauri-apps/cli": "^2.0.0-alpha.17"

+ 2 - 3
tooling/cli/templates/plugin/__example-api/tauri-app/vite.config.js

@@ -1,6 +1,5 @@
 import { defineConfig } from "vite";
 import { svelte } from "@sveltejs/vite-plugin-svelte";
-import { internalIpV4Sync } from 'internal-ip';
 
 const host = process.env.TAURI_DEV_HOST;
 
@@ -13,12 +12,12 @@ export default defineConfig({
   clearScreen: false,
   // tauri expects a fixed port, fail if that port is not available
   server: {
-    host: host ? "0.0.0.0" : false,
+    host: host || false,
     port: 1420,
     strictPort: true,
     hmr: host ? {
       protocol: 'ws',
-      host: internalIpV4Sync(),
+      host,
       port: 1421
     } : undefined,
   },