tauri icon indicating copy to clipboard operation
tauri copied to clipboard

[feat] [2.0 beta] allow the configuration for the ip address for frontend dev server as well for ios/android

Open CatStudioApp opened this issue 1 year ago • 3 comments

Describe the problem

currently it is hard to debug because my android/ios devices always looking for an internal ip address.

as a mobile dev with 10+ year experience, I haven't found a way to debug tauri 2.0 apps on mobile devices

Screenshot_20240710-150512

Describe the solution you'd like

on android, we can use adb reverse to forward the port. on ios, it would be better to expose an env var to configure this port

Alternatives considered

No response

Additional context

No response

CatStudioApp avatar Jul 10 '24 21:07 CatStudioApp

sorry just noticed

pnpm tauri android dev --force-ip-prompt 127.0.0.1

is there a way to make the param 127.0.0.1 work?

CatStudioApp avatar Jul 10 '24 21:07 CatStudioApp

any new progress here? I encountered the same problem...

winjeysong avatar Jul 29 '24 08:07 winjeysong

I got it work. but needs a bit, too much code... This code lookup all local IP addresses and replaces the one that is accessible through WiFi connection instead of the devUrl inside tauri.conf.json .

  • You may want to modify it to use other network adapter such as ethernet if your device is sharing internet using USB
  • It does not modify the tauri.conf.json, it shares the ip in rust process and updates the context during runtime.
  • specifing devUrl in tauri.conf.json is still necessary since this code just replaces the hostname with the IP and reuses the same port.
  • When running tauri command, it still logs the internal IP. but the correct IP will be replaced during runtime.
tauri.conf.json
"build": {
    "devUrl": "http://localhost:1420",
    ...
},
build.rs
use if_addrs::get_if_addrs;
use serde_json::Value;
use std::fs;
use url::Url;

/// Detects the first 192.168.x.x IPv4 address on a Wi-Fi interface.
fn detect_wifi_ipv4() -> Option<String> {
    for iface in get_if_addrs().ok()? {
        let name = iface.name.to_lowercase();
        if !(name.contains("wlan")
            || name.contains("wifi")
            || name == "en0"
            || name.contains("wi-fi"))
        {
            continue;
        }
        if let std::net::IpAddr::V4(v4) = iface.ip() {
            let oct = v4.octets();
            if oct[0] == 192 && oct[1] == 168 {
                return Some(v4.to_string());
            }
        }
    }
    None
}

fn apply_dev_url() {
    let config_path = "tauri.conf.json";
    let config_str = fs::read_to_string(config_path).expect("Failed to read tauri.conf.json");
    let json: Value = serde_json::from_str(&config_str).expect("Invalid JSON in tauri.conf.json");

    // Extract the existing devUrl URL
    let dev_path = json["build"]["devUrl"]
        .as_str()
        .expect("build.devUrl must be a string");

    // Parse URL and replace host with detected IP (fallback to localhost)
    let mut url = Url::parse(dev_path).expect("devUrl is not a valid URL");
    let new_ip = detect_wifi_ipv4().unwrap_or_else(|| "127.0.0.1".into());
    url.set_host(Some(&new_ip)).expect("Failed to set host");

    // Preserve scheme, port, and path. Expose via env var for use in Rust.
    println!("cargo:rustc-env=TAURI_DEV_URL={}", url.as_str());
}

fn main() {
    apply_dev_url();

   ...
}
src/lib.rs
use tauri::Url;
use tauri_plugin_log::{Target, TargetKind};

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    let mut context = tauri::generate_context!();
    let custom_dev_url = env!("TAURI_DEV_URL");

    context.config_mut().build.dev_url = Some(Url::parse(custom_dev_url).unwrap());

    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![])
        .run(context)
        .expect("error while running tauri application");
}
Cargo.toml

Add These dependencies to build-deps

[build-dependencies]
serde_json = "1.0"
if-addrs = "0.13.4"
url = "2.5.4"
vite.config.mts (or any other frontend server/bundler)

For frontend, it is not required to do anything. But I lookup for WiFi IPV4 as same as the rust code to set websocket's IP, since vite is not smart enough to use the same IPV4 (or I may be wrong, but this is how it worked)

import os from "os";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

const host = getWifiIPv4();

// https://vitejs.dev/config/
export default defineConfig(async () => ({
  plugins: [react(), tailwindcss()],
  clearScreen: false,
  server: {
    port: 1420,
    strictPort: true,
    host: "0.0.0.0",
    hmr: {
      protocol: "ws",
      port: 1421,
      host,
    },
    watch: {
      // 3. tell vite to ignore watching `src-tauri`
      ignored: ["**/src-tauri/**"],
    },
  },
}));

function getWifiIPv4() {
  const nets = os.networkInterfaces();

  // Adjust these name checks for your platform if needed
  const isWifiInterface = (name: string) => {
    const lname = name.toLowerCase();
    return (
      lname.includes("wlan") || // common Linux
      lname.includes("wifi") || // Windows & Linux
      lname === "en0" || // macOS default Wi‑Fi
      lname.includes("wi-fi") // Windows
    );
  };

  for (const [name, addrs] of Object.entries(nets)) {
    if (!isWifiInterface(name) || !addrs) continue;
    for (const { family, address, internal } of addrs) {
      if (family === "IPv4" && !internal && address.startsWith("192.168.")) {
        return address;
      }
    }
  }

  return "127.0.0.1";
}

I generated these codes with the help of AI. They may have some issues that I am not aware of.

Edit: If you are using this code, give me your feedback. if the code becomes stable and reliable, I can create a library out of it for easier integration and customization.

arashi-dev avatar May 18 '25 11:05 arashi-dev

the IP address is determined by Tauri but your frontend needs to listen on that same address; you can either configure it to listen on 0.0.0.0 (or host: true on some frameworks) or use the TAURI_DEV_HOST environment variable. See https://tauri.app/develop/#development-server no need to go with build scripts and manually updating the config, the Tauri CLI handles that for you.

lucasfernog avatar Oct 10 '25 11:10 lucasfernog

the IP address is determined by Tauri but your frontend needs to listen on that same address; you can either configure it to listen on 0.0.0.0 (or host: true on some frameworks) or use the TAURI_DEV_HOST environment variable. See https://tauri.app/develop/#development-server no need to go with build scripts and manually updating the config, the Tauri CLI handles that for you.

As I remember TAURI_DEV_HOST is not settable and will be set by tauri and points to the internal IP which is not accessible by mobile (Is not in 192.168.X.X range). Currently I cannot test it but I think I tested that already when I got that problem. If you are sure about it and got it work, make a ROCKET reaction and I will delete this current comment.

arashi-dev avatar Oct 10 '25 12:10 arashi-dev