Tauri mobile for iOS
Adimac93
Posted on August 5, 2023
I've been recently experimenting with Tauri alpha to try out mobile app development. By following the official guide and resolving problems, this is how I managed to set up a basic project utilising web view.
Fast forward template solution
It's highly recommended to follow this simplified guide including the project template.
You can find it here https://github.com/Adimac93/tauri-mobile-apple-ecosystem
Also, an android version (based on my template) is available here https://github.com/casey-SK/tauri-mobile-android
You may read along with this post if you are interested in particular set-up steps.
MacOS
XCode
I've tried to set up XCode both with the latest stable release (14.3.1) and the beta release (for IOS 17). However, only a stable release worked for me.
⚠️ Warning
XCode from AppStore is known for notorious problems with downloading.
Instead download it from Apple website XCode 14.3.1 download.
You will need to make sure you have command line tools installed on your machine:
$ xcode-select --install
If you have multiple XCode CLI tool versions installed, you can set CLI version in XCode Settings... > Locations > Command Line Tools
.
You should log in in XCode with your Apple ID to sign apps with a personal certificate. This will enable you to test your apps directly on your device.
Settings... > Accounts > + > Apple ID
Rust
Next dependency is Rust which can be downloaded by following command:
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
If you have it already installed, make sure it's up to date:
$ rustup update
iOS targets
$ rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
App setup
Using Tauri scaffolding utility it's easier to set up a new project with desired frontend framework.
In this example I'll use the following options:
- Frontend language: TypeScript
- Package manager: pnpm
- UI template: Svelte
- UI flavour: TypeScript
$ cargo install create-tauri-app
$ cargo create-tauri-app
Install frontend dependencies:
$ cd tauri-mobile
$ pnpm add -D internal-ip
$ pnpm i
Update tauri CLI:
$ pnpm update @tauri-apps/cli@next @tauri-apps/api@next
and if you'd like to use CLI with cargo
$ cargo install tauri-cli --version "^2.0.0-alpha"
Vite
Default Vite config for Svelte generated by create-tauri-app
.
vite.config.ts
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
// https://vitejs.dev/config/
export default defineConfig(async () => ({
plugins: [svelte()],
clearScreen: false,
server: {
port: 1420,
strictPort: true,
},
envPrefix: ["VITE_", "TAURI_"],
}));
We need to change it to the following:
vite.config.ts
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { internalIpV4 } from 'internal-ip'
// https://vitejs.dev/config/
export default defineConfig(async () => ({
plugins: [svelte()],
clearScreen: false,
server: {
host: "0.0.0.0",
port: 5173,
strictPort: true,
hmr: {
protocol: 'ws',
host: await internalIpV4(),
port: 5183,
},
},
envPrefix: ["VITE_", "TAURI_"],
}));
Tauri
- Remove
allowlist
- Match
devPath
port (same asvite.config.ts > server > port
) - Change bundle identifier (use only alphanumeric characters because other chars are bugged right now)
💡 Tip
A bundle ID uniquely identifies a single app throughout the system. The bundle ID string must contain only alphanumeric characters (A–Z, a–z, and 0–9), hyphens (-), and periods (.). Typically, you use a reverse-DNS format for bundle ID strings. Bundle IDs are case-insensitive.
Apple docs
src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
- "devPath": "http://localhost:1420",
+ "devPath": "http://localhost:5173",
"distDir": "../dist",
"withGlobalTauri": false
},
"package": {
"productName": "tauri-mobile",
"version": "0.0.0"
},
"tauri": {
- "allowlist": {
- "all": false,
- "shell": {
- "all": false,
- "open": true
- }
- },
"bundle": {
"active": true,
"targets": "all",
- "identifier": "com.tauri.dev",
+ "identifier": "com.<YOUR ID>.dev"
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
},
"security": {
"csp": null
},
"windows": [
{
"fullscreen": false,
"resizable": true,
"title": "tauri-mobile",
"width": 800,
"height": 600
}
]
}
}
Install iOS codegen dependencies:
$ brew install cocoapods
Install core Cargo dependecies:
$ cargo add tauri@2.0.0-alpha.<VERSION>
$ cargo add tauri-build@2.0.0-alpha.<VERSION> --build
If you'll get the following error:
➜ cargo add tauri@2.0.0-alpha.10
Updating crates.io index
Adding tauri v2.0.0-alpha.10 to dependencies.
error: unrecognized feature for crate tauri: shell-open
all you do is
src-tauri/Cargo.toml
[package]
name = "tauri-mobile"
version = "0.0.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.4", features = [] }
[dependencies]
- tauri = { version = "1.4", features = ["shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!
- custom-protocol = ["tauri/custom-protocol"]
after upgrading dependencies put this line back
custom-protocol = ["tauri/custom-protocol"]
Include embedded library
src-tauri/Cargo.toml
[lib]
crate-type = ["staticlib", "cdylib", "rlib"]
Then you set up rest of the project files.
Library
src-tauri/src/lib.rs
use tauri::App;
#[cfg(mobile)]
mod mobile;
#[cfg(mobile)]
pub use mobile::*;
pub type SetupHook = Box<dyn FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send>;
#[derive(Default)]
pub struct AppBuilder {
setup: Option<SetupHook>,
}
impl AppBuilder {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn setup<F>(mut self, setup: F) -> Self
where
F: FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send + 'static,
{
self.setup.replace(Box::new(setup));
self
}
pub fn run(self) {
let setup = self.setup;
tauri::Builder::default()
.setup(move |app| {
if let Some(setup) = setup {
(setup)(app)?;
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
}
Entry point
src-tauri/src/mobile.rs
#[tauri::mobile_entry_point]
fn main() {
super::AppBuilder::new().run();
}
Main
src-tauri/src/main.rs
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
pub fn main() {
app::AppBuilder::new().run();
}
That's all you need!
Now run ios dev
and test your app with an emulator or connected iOS device.
Posted on August 5, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.