# Limitations and Known Issues When Building Mobile Apps with Tauri (iOS/Android)

> Explore Tauri's alpha mobile limitations for iOS/Android. Learn about URI schemes, Rust targets, and platform configs to prevent build failures and runtime errors. Optimize your Tauri app development.

- Repository: [Tauri/tauri](https://github.com/tauri-apps/tauri)
- Tags: deep-dive
- Published: 2026-02-26

---

**Tauri mobile support is currently in alpha and requires careful handling of URI scheme registration, Rust target installations, and platform-specific configuration to avoid build failures and runtime errors.**

Tauri v2 extends the framework’s Rust backend and system WebView architecture to iOS and Android, but building for mobile introduces distinct constraints not present in desktop development. Understanding these **limitations and known issues when building mobile apps with Tauri** is essential for avoiding silent failures and debugging complex toolchain interactions in the `tauri-apps/tauri` repository.

## Critical Runtime Limitations

Mobile apps rely on the same core runtime as desktop, but specific timing and threading constraints apply.

### URI Scheme Registration Timing

Custom **URI scheme protocols** must be registered **before** the WebView is instantiated. According to the source code in [`crates/tauri/src/plugin.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri/src/plugin.rs) (lines 601–604), if a plugin attempts to register a scheme after the WebView creation completes, the scheme will never be reachable, causing deep-links and asset loading to fail silently.

Register schemes during plugin initialization:

```rust
use tauri::{plugin::{Builder, TauriPlugin}, Runtime};

fn init<R: Runtime>() -> TauriPlugin<R> {
  Builder::new("myplugin")
    // Register early, otherwise the scheme won't be available
    .register_uri_scheme_protocol("myscheme", |_ctx, req| {
      // Example: serve a static file from the assets folder
      let path = req.uri().path().trim_start_matches('/');
      std::fs::read(path)
        .map(|data| http::Response::builder().body(data).unwrap())
        .unwrap_or_else(|_| http::Response::builder().status(404).body(Vec::new()).unwrap())
    })
    .build()
}

```

*The registration must happen during the plugin’s `init` so the protocol exists when the WebView is instantiated.*

### iOS Async Entry Point Stability

Early versions of the `mobile_entry_point` macro caused panics on iOS when using async functions. This was resolved in **v2.0.0-alpha.11** (see [`crates/tauri/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri/CHANGELOG.md), line 453). Ensure you are running this version or later to prevent crashes when initializing async Rust code at startup.

## Configuration and Setup Requirements

Mobile builds require specific toolchain components and strict configuration validation.

### Required Rust Targets for Cross-Compilation

The mobile CLI commands (`tauri android …`, `tauri ios …`) **require the appropriate Rust targets** to be installed. As documented in [`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md) (commit f70b28529), the CLI now checks for these targets and aborts early if they are missing.

Install the necessary targets before running mobile commands:

```bash

# Install Android targets

rustup target add aarch64-linux-android armv7-linux-androideabi

# Install iOS targets

rustup target add aarch64-apple-ios x86_64-apple-ios

# Then run the dev command

tauri android dev   # or `tauri ios dev`

```

### Product Name and Identifier Constraints

An empty **`productName`** in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) triggers a warning and can break generated Android and iOS project names, as Android package names and iOS bundle identifiers must be non-empty strings ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 113).

Additionally, changing the **`identifier`** (Android `applicationId` or iOS `bundleIdentifier`) after the mobile project has been generated can cause the CLI to fail when merging configurations, leaving stale identifiers in native project files ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 255).

Ensure your configuration is stable:

```json
// tauri.conf.json
{
  "tauri": {
    "android": {
      "identifier": "com.example.myapp"
    }
  }
}

```

### Android Identifier Sanitization

Using a **Kotlin keyword** (e.g., `in`, `class`, `when`) in the Android `identifier` previously caused ProGuard failures during the build process. The CLI now sanitizes these identifiers automatically ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 639), but providing a clean identifier avoids potential edge cases in [`crates/tauri-cli/src/mobile/android/android_studio_script.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-cli/src/mobile/android/android_studio_script.rs).

## Platform-Specific Development Issues

Mobile development environments impose additional constraints related to simulators, permissions, and network configuration.

### Xcode 16.3 and iOS Simulator Compatibility

**iOS dev** commands stopped working on the Xcode 16.3 simulator until the project is regenerated or the `arm64-sim` architecture is removed. Newer Xcode versions changed supported architectures, breaking the default project template included in earlier CLI versions ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 277).

Regenerate the iOS project after upgrading:

```bash

# Remove the problematic architecture from the project

rm -rf src-tauri/gen/apple
tauri ios init   # regenerate with the new template

```

### Intel Mac Development Limitations

The iOS dev and build commands **did not work on Intel Macs** before the fix included in **v2.0.0-alpha.17** (commit a9b342125). Developers on older hardware must update to this version or later to test iOS apps locally ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 134).

### Android External Storage Permissions

Accessing files via **`convertFileSrc`** on Android 7+ can return **500 errors** when the external storage permission is not granted. The runtime now includes better error handling and logging for this scenario ([`crates/tauri/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri/CHANGELOG.md), line 26). Applications loading local media must request `READ_EXTERNAL_STORAGE` on older Android versions.

### Dev Server Connectivity and Port Forwarding

The development server requires explicit network configuration depending on the host OS. By default on **Windows**, the dev server uses the **public network IP**; on macOS and iOS, you must explicitly enable public access using the **`--host`** flag. Misconfiguration leads to "could not connect to dev server" errors on physical devices ([`crates/tauri-cli/src/mobile/android/dev.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-cli/src/mobile/android/dev.rs), lines 81–96).

Additionally, the dev server port-forward on Android can **fail** under certain conditions, such as slow device boot sequences, though recent updates have improved resilience and logging ([`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), line 508).

Use the host flag for physical device testing:

```bash

# Use the machine's public IP so the device can reach the dev server

tauri android dev --host

# or specify an explicit address

tauri ios dev --host 192.168.1.23

```

## Build and Distribution Constraints

Mobile app distribution requires valid signing credentials that the CLI cannot generate automatically.

### Code Signing and Provisioning Requirements

iOS apps require a valid **Apple developer certificate** and **provisioning profile**, while Android apps need proper **keystore configuration**. The bundling step will abort if these signing keys are missing, preventing installation on physical devices or submission to app stores. Verify your signing configuration matches the platform requirements listed in the repository [`README.md`](https://github.com/tauri-apps/tauri/blob/main/README.md) (platform versions table).

## Summary

- **Register URI schemes early** in the plugin initialization phase before the WebView is created to ensure protocol availability.
- **Install required Rust targets** (`aarch64-linux-android`, `aarch64-apple-ios`, etc.) before running mobile CLI commands to prevent early aborts.
- **Keep `productName` and `identifier` stable and non-empty**; changes after project generation require regenerating native project files.
- **Update to v2.0.0-alpha.17 or later** to resolve Intel Mac compatibility and Xcode 16.3 simulator issues.
- **Use the `--host` flag** when testing on physical iOS or Android devices to ensure the dev server is reachable.
- **Request external storage permissions** on Android when using `convertFileSrc` to avoid 500 errors.

## Frequently Asked Questions

### Why does my custom URI scheme return 404 on mobile but work on desktop?

Custom URI schemes must be registered **before** the WebView is instantiated. In [`crates/tauri/src/plugin.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri/src/plugin.rs), the registration window closes once the WebView creation completes. If your plugin registers the scheme during an asynchronous setup or after the app launches, the scheme will be unreachable. Move the registration to the plugin's `init` function as shown in the examples above.

### How do I fix "target not installed" errors when running tauri android dev?

The CLI requires specific Rust targets for cross-compilation that are not installed by default. Run `rustup target add aarch64-linux-android armv7-linux-androideabi` for Android or `rustup target add aarch64-apple-ios` for iOS. The CLI validates these targets before building (see [`packages/cli/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/cli/CHANGELOG.md), commit f70b28529).

### Why does my iOS app crash immediately on launch in Xcode 16.3?

Older project templates included an `arm64-sim` architecture that Xcode 16.3 no longer supports. Delete the `src-tauri/gen/apple` directory and run `tauri ios init` to regenerate the project with the updated template, as documented in the CLI changelog (line 277).

### Can I use Kotlin keywords like "class" or "in" in my Android app identifier?

No. Using Kotlin reserved keywords in the Android `identifier` field causes ProGuard failures during the build process. While the CLI now sanitizes identifiers in [`crates/tauri-cli/src/mobile/android/android_studio_script.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-cli/src/mobile/android/android_studio_script.rs), you should avoid keywords entirely to prevent build ambiguity.