Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DioxusLabs/dioxus/llms.txt
Use this file to discover all available pages before exploring further.
Dioxus supports mobile app development for both iOS and Android using the same desktop renderer infrastructure (Wry/Tao). Your Rust code compiles natively while the UI renders through the platform’s native webview.
Quick Start
Prerequisites
For iOS:
- macOS with Xcode installed
- iOS Simulator or physical device
- Rust iOS targets:
rustup target add aarch64-apple-ios
For Android:
- Android SDK and NDK installed
- Android Studio (recommended)
- Rust Android targets:
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add i686-linux-android
rustup target add x86_64-linux-android
Create a Mobile App
Initialize a new mobile project:
dx new my-app --platform mobile
cd my-app
Your app structure:
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[component]
fn App() -> Element {
let mut count = use_signal(|| 0);
rsx! {
div {
style: "padding: 20px; text-align: center;",
h1 { "Mobile App" }
button {
onclick: move |_| count += 1,
style: "padding: 10px 20px; font-size: 18px;",
"Count: {count}"
}
}
}
}
iOS Development
Run on iOS Simulator
This will:
- Build your Rust code for iOS
- Generate an Xcode project
- Launch the iOS Simulator
- Install and run your app
Run on Physical Device
- Connect your iOS device
- Configure signing in Xcode
- Run:
dx serve --platform ios --device
Build for Release
dx build --platform ios --release
The .app bundle will be in target/ios/release/.
iOS-Specific Configuration
Create an Info.plist for iOS-specific settings:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>My App</string>
<key>CFBundleDisplayName</key>
<string>My App</string>
<key>CFBundleIdentifier</key>
<string>com.example.myapp</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
Android Development
Run on Android Emulator
dx serve --platform android
This will:
- Build your Rust code for Android
- Generate an Android project
- Launch the Android Emulator
- Install and run your APK
Run on Physical Device
- Enable USB debugging on your device
- Connect via USB
- Run:
dx serve --platform android --device
Build for Release
dx build --platform android --release
The APK will be in target/android/release/.
Android-Specific Configuration
Configure your app in Dioxus.toml:
[android]
package = "com.example.myapp"
version_name = "1.0.0"
version_code = 1
[android.permissions]
INTERNET = true
CAMERA = true
ACCESS_FINE_LOCATION = true
Android Manifest
Customize AndroidManifest.xml for advanced features:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:label="My App"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Mobile-Specific Features
Touch Events
Handle touch interactions:
use dioxus::prelude::*;
#[component]
fn TouchExample() -> Element {
let mut position = use_signal(|| (0.0, 0.0));
rsx! {
div {
ontouchstart: move |evt| {
if let Some(touch) = evt.touches().first() {
position.set((touch.page_x(), touch.page_y()));
}
},
ontouchmove: move |evt| {
if let Some(touch) = evt.touches().first() {
position.set((touch.page_x(), touch.page_y()));
}
},
style: "width: 100%; height: 100vh; background: #f0f0f0;",
"Touch Position: ({position.0}, {position.1})"
}
}
}
Responsive Design
Detect and respond to screen size:
use dioxus::prelude::*;
#[component]
fn ResponsiveLayout() -> Element {
rsx! {
style { {include_str!("./mobile.css")} }
div { class: "container",
h1 { class: "mobile-title", "Mobile App" }
div { class: "button-grid",
button { class: "mobile-button", "Button 1" }
button { class: "mobile-button", "Button 2" }
button { class: "mobile-button", "Button 3" }
}
}
}
}
/* mobile.css */
.container {
padding: env(safe-area-inset-top) env(safe-area-inset-right)
env(safe-area-inset-bottom) env(safe-area-inset-left);
max-width: 100%;
}
.mobile-title {
font-size: clamp(1.5rem, 5vw, 3rem);
text-align: center;
}
.button-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
padding: 1rem;
}
.mobile-button {
padding: 1rem;
font-size: 1.2rem;
min-height: 60px;
touch-action: manipulation;
}
Device Orientation
use dioxus::prelude::*;
#[component]
fn OrientationDetector() -> Element {
let mut orientation = use_signal(|| "unknown");
use_effect(move || {
spawn(async move {
// Detect orientation using window dimensions
let window = web_sys::window().unwrap();
let width = window.inner_width().unwrap().as_f64().unwrap();
let height = window.inner_height().unwrap().as_f64().unwrap();
orientation.set(if width > height {
"landscape"
} else {
"portrait"
});
});
});
rsx! {
div { "Orientation: {orientation}" }
}
}
Haptic Feedback
Trigger device vibration:
use dioxus::prelude::*;
#[component]
fn HapticButton() -> Element {
let trigger_haptic = move |_| {
#[cfg(target_os = "android")]
{
// Android vibration API
use jni::JNIEnv;
// Call Java vibration API
}
#[cfg(target_os = "ios")]
{
// iOS haptic feedback
// Use AudioToolbox framework
}
};
rsx! {
button { onclick: trigger_haptic, "Tap for Haptic" }
}
}
Native Plugins
Access native device features through custom plugins:
// lib.rs
#[cfg(target_os = "android")]
pub mod android {
use jni::JNIEnv;
use jni::objects::JObject;
pub fn call_native_method() {
// JNI calls to Android APIs
}
}
#[cfg(target_os = "ios")]
pub mod ios {
use objc::runtime::Object;
pub fn call_native_method() {
// Objective-C calls to iOS APIs
}
}
Camera Access
Use the device camera:
use dioxus::prelude::*;
#[component]
fn CameraAccess() -> Element {
let mut image_src = use_signal(|| String::new());
let take_photo = move |_| {
spawn(async move {
// Use file input with camera capture
// Or native camera APIs
});
};
rsx! {
div {
input {
r#type: "file",
accept: "image/*",
capture: "environment",
onchange: move |evt| {
spawn(async move {
// Handle file selection
});
}
}
if !image_src().is_empty() {
img { src: "{image_src}" }
}
}
}
}
Geolocation
use dioxus::prelude::*;
#[component]
fn Location() -> Element {
let mut position = use_signal(|| "Getting location...".to_string());
use_effect(move || {
spawn(async move {
// Request location permission
// Use Geolocation API
position.set("Lat: 0.0, Lng: 0.0".to_string());
});
});
rsx! {
div { "{position}" }
}
}
Local Storage
Persist data on mobile:
use dioxus::prelude::*;
#[component]
fn PersistentData() -> Element {
let mut data = use_signal(|| load_from_storage());
let save = move || {
save_to_storage(&data());
};
rsx! {
button { onclick: move |_| save(), "Save Data" }
}
}
fn load_from_storage() -> String {
// Load from platform-specific storage
String::new()
}
fn save_to_storage(data: &str) {
// Save to platform-specific storage
}
1. Minimize JavaScript Bridge Calls
// Bad: Multiple calls
for item in items {
eval_js(&format!("update({})", item));
}
// Good: Single batched call
let batch = items.iter().map(|i| format!("{}", i)).collect::<Vec<_>>().join(",");
eval_js(&format!("updateBatch([{}])", batch));
2. Optimize Images
Use responsive images and lazy loading:
rsx! {
img {
src: "image.jpg",
loading: "lazy",
srcset: "image-320w.jpg 320w, image-640w.jpg 640w, image-1280w.jpg 1280w"
}
}
3. Reduce Bundle Size
Strip debug symbols and optimize:
dx build --platform android --release
strip target/aarch64-linux-android/release/libmyapp.so
Testing
iOS Simulator Testing
dx test --platform ios --simulator
Android Emulator Testing
dx test --platform android --emulator
Publishing
iOS App Store
- Build release version
- Archive in Xcode
- Upload to App Store Connect
- Submit for review
Google Play Store
- Build signed APK:
dx bundle --platform android --release
- Upload to Google Play Console
- Submit for review
Troubleshooting
iOS Build Issues
- Ensure Xcode is up to date
- Check provisioning profiles
- Verify bundle identifier matches
Android Build Issues
- Update Android SDK and NDK
- Check
ANDROID_HOME environment variable
- Verify NDK version compatibility
Next Steps