Mobile Development

Skelenote uses Tauri 2.0's mobile support to build native iOS and Android apps from the same codebase as the desktop app. This guide covers setup, development, and mobile-specific patterns.

Overview

The mobile apps share the same React frontend and Rust backend as the desktop app, with platform-specific native capabilities accessed through Tauri plugins and custom commands.

Mobile code locations:

Path
Description

src-tauri/gen/apple/

iOS/macOS Xcode project

src-tauri/gen/android/

Android Gradle project

src/components/mobile/

Mobile-specific React components

src/hooks/use*.ts

Platform-aware hooks (many are mobile-specific)

Prerequisites

iOS Development

  1. macOS - iOS development requires macOS

  2. Xcode 15+ - Install from the App Store

  3. Xcode Command Line Tools:

    xcode-select --install
  4. CocoaPods (for iOS dependencies):

    sudo gem install cocoapods
  5. iOS Simulator - Included with Xcode (download additional simulators in Xcode > Settings > Platforms)

Android Development

  1. Android Studio - Download from developer.android.comarrow-up-right

  2. Android SDK - Install via Android Studio (SDK Manager)

  3. Android NDK - Required for Rust compilation

    • Open Android Studio > SDK Manager > SDK Tools

    • Check "NDK (Side by side)" and install

  4. Environment variables - Add to your shell profile (.zshrc or .bashrc):

  5. Java 17 - Required by Gradle:

Rust Targets

Install the mobile Rust targets:

iOS Development Setup

Initial Setup

  1. Initialize iOS project (if not already done):

  2. Install CocoaPods dependencies:

  3. Open in Xcode (optional, for signing and capabilities):

Running on iOS Simulator

This will:

  1. Build the Rust library for the iOS simulator

  2. Build the frontend

  3. Launch the iOS simulator

  4. Install and run the app

Specify a simulator:

List available simulators:

Running on Physical iOS Device

  1. Connect your device via USB

  2. Open src-tauri/gen/apple/skelenote.xcworkspace in Xcode

  3. Select your team in Signing & Capabilities

  4. Select your device as the run target

  5. Run from Xcode (Cmd+R) or:

Building for Release

Output: src-tauri/gen/apple/build/skelenote_iOS.xcarchive

For App Store distribution, archive and export from Xcode.

Android Development Setup

Initial Setup

  1. Initialize Android project (if not already done):

  2. Verify environment:

    Check that Android SDK and NDK are detected.

Running on Android Emulator

  1. Create an AVD (Android Virtual Device) in Android Studio:

    • Open AVD Manager (Tools > Device Manager)

    • Create a device with API 24+ (Android 7.0+)

  2. Start the emulator and run:

Specify an emulator:

Running on Physical Android Device

  1. Enable Developer Options on your device

  2. Enable USB Debugging

  3. Connect via USB and authorize the connection

  4. Run:

Building for Release

Output: src-tauri/gen/android/app/build/outputs/apk/

For Play Store distribution, generate a signed AAB:

Platform Detection Patterns

Use the usePlatform() hook to detect the current platform and adapt the UI:

Conditional Rendering

Safe Area Handling

Mobile devices have safe area insets for notches, home indicators, and status bars. The usePlatform() hook provides these values:

CSS Environment Variables

For CSS-based handling, use the env() function:

Default Values

Platform

safeAreaTop

safeAreaBottom

iOS (iPhone with notch)

47px

34px

Android

24px

0px

Desktop

0px

0px

The hook reads actual values from CSS env() on mount and uses these defaults as fallbacks.

Mobile Hooks Reference

usePlatform()

Platform detection and safe area insets.

useHaptics()

Haptic feedback for tactile responses on mobile.

Tauri commands called:

  • haptic_impact

  • haptic_notification

  • haptic_selection

useBiometric()

Biometric authentication (Face ID, Touch ID, fingerprint).

Plugin used: @tauri-apps/plugin-biometric

useQRScanner()

QR code scanning for device pairing.

Plugin used: @tauri-apps/plugin-barcode-scanner

useNotifications()

Push notifications for task reminders.

Plugin used: @tauri-apps/plugin-notification

useAppIcon()

Dynamic app icon switching (iOS, Android, macOS).

Platform behavior:

  • iOS: Shows system confirmation prompt, persists across launches

  • Android: Uses activity aliases, persists across launches

  • macOS: Changes dock icon for current session only

Tauri commands called:

  • is_icon_switching_supported

  • get_available_icons

  • set_app_icon

useShareHandler()

Handle content shared from other apps.

Behavior:

  • Checks for pending shares on mount

  • Checks when app returns from background

  • Creates Link objects for URLs, Note objects for text

  • Shows toast notification on success

Native implementation:

  • iOS: Share Extension in src-tauri/gen/apple/SkelenoteShare/

  • Android: Share Intent handler in ShareReceiverActivity.kt

useBackgroundTask()

iOS background execution for completing sync.

Note: iOS grants approximately 30 seconds for background execution.

Tauri commands called:

  • begin_background_task

  • end_background_task

Handle skelenote:// URLs for navigation.

Supported URL formats:

  • skelenote://task/{id} - Navigate to task

  • skelenote://note/{id} - Navigate to note

  • skelenote://object/{id} - Navigate to any object

  • skelenote://inbox - Navigate to inbox

  • skelenote://tasks - Navigate to tasks view

  • skelenote://daily - Navigate to daily notes

Plugin used: @tauri-apps/plugin-deep-link

Mobile Components

Mobile-specific React components are in src/components/mobile/:

Primitives

Basic building blocks for mobile UI:

Component
Description

SwipeableRow

Row with swipe-to-reveal actions

BottomSheet

iOS-style bottom sheet modal

ActionSheet

iOS-style action menu

FAB

Floating action button

PullToRefresh

Pull-to-refresh wrapper

CollapsibleSection

Expandable/collapsible section

AnimatedCheckbox

Animated task checkbox

SelectionToolbar

Multi-select action toolbar

MobileViewHeader

Standard mobile view header

MobileSyncIndicator

Sync status indicator

PropertyChip

Compact property display

EmptyState

Empty state placeholder

Views

Full-screen mobile views:

View
Description

MobileInboxView

Inbox with swipe actions

MobileTasksView

Tasks with filters and quick add

MobileDailyNotesView

Daily notes timeline

MobileObjectDetailView

Object detail/editor

MobileSearchModal

Full-screen search

MobileSettingsView

Settings with nested sheets

MobileBrowseView

Browse by type/project/area

MobileArchiveView

Archived objects

LockScreen

Biometric lock screen

Sheets

Bottom sheet modals for actions and pickers:

Sheet
Description

QuickAddTaskSheet

Quick task creation

QuickCaptureSheet

Quick capture to inbox

PropertyEditorSheet

Edit object properties

StatusPickerSheet

Task status picker

PriorityPickerSheet

Priority picker

DueDateSheet

Date picker with presets

ReminderSheet

Reminder time picker

RecurrenceSheet

Recurrence pattern editor

TagPickerSheet

Tag multi-select

ProjectPickerSheet

Project selector

AreaPickerSheet

Area selector

TemplatePickerSheet

Template selector

BulkActionsSheet

Multi-select actions

AccountSettingsSheet

Account settings

SyncSettingsSheet

Sync configuration

DeviceManagerSheet

Device management

Debugging on Mobile

iOS Debugging

Safari Web Inspector (recommended):

  1. Enable Web Inspector on device: Settings > Safari > Advanced > Web Inspector

  2. Open Safari on Mac

  3. Develop menu > [Device Name] > [App WebView]

  4. Full DevTools access (Console, Network, Elements, etc.)

Xcode Console:

  1. Run from Xcode

  2. View > Debug Area > Activate Console

  3. See println! output from Rust and console.log from JavaScript

Logging:

Android Debugging

Chrome DevTools:

  1. Enable USB debugging on device

  2. Open chrome://inspect in Chrome

  3. Find your app's WebView and click "inspect"

  4. Full DevTools access

Android Studio Logcat:

  1. Run from Android Studio or connect device

  2. View > Tool Windows > Logcat

  3. Filter by app package name

ADB Logcat (command line):

Common Debugging Tips

  1. Check platform detection: Log usePlatform() values on mount

  2. Verify Tauri commands: Wrap in try/catch and log errors

  3. Test on real devices: Simulators may behave differently

  4. Check permissions: Camera, biometric, notifications need explicit permission

Building for Release

iOS Release Build

Output: src-tauri/gen/apple/build/skelenote_iOS.xcarchive

For App Store submission:

  1. Open the xcarchive in Xcode Organizer

  2. Validate App

  3. Distribute App > App Store Connect

Android Release Build

Signing the release:

  1. Create a keystore:

  2. Configure signing in src-tauri/gen/android/app/build.gradle.kts:

Output: src-tauri/gen/android/app/build/outputs/

Configuration Files

iOS (src-tauri/tauri.conf.json):

Android (src-tauri/gen/android/app/build.gradle.kts):

  • minSdk, targetSdk, compileSdk

  • Signing configuration

  • ProGuard rules

Troubleshooting

iOS Issues

"Could not find a development team"

  • Open the Xcode project and select a team in Signing & Capabilities

CocoaPods errors

Simulator not starting

Android Issues

"NDK not found"

  • Install NDK via Android Studio SDK Manager

  • Set NDK_HOME environment variable

"JAVA_HOME is not set"

Emulator performance

  • Enable hardware acceleration (HAXM on Intel, Hypervisor on ARM)

  • Use x86_64 system image for better performance

General Issues

"Command not found: tauri"

Rust target not installed

Build cache issues

Last updated