Manual/Reference

iOS

Meratyn runs as a native iOS app built from the same React codebase via Tauri v2 mobile — no separate app. The webview UI (WKWebView) is bundled in the app, so the shell works offline; map tiles and the heavier engines are fetched on demand (same as the desktop and Android builds).

Status: scaffolding. The iOS config, privacy plist, and CI build/signing workflow are in place, but no iOS build has been shipped yet. Local builds still require a Mac because iOS cannot be cross-compiled from Linux.

What works on iOS vs desktop

Same split as Android. The iOS build ships the full map workspace, Add Data, the Vector tools (Turf.js / in-browser GeoPandas via Pyodide), the SQL Workspace (DuckDB-WASM and PGlite/PostGIS), the Python Console (Pyodide), geocoding, statistics, the AI assistant, story maps, and plugins.

iOS has no Python sidecar or local helper binaries and its sandbox forbids spawning subprocesses. Browser-capable processing runs on the device where the operation and input format are supported: Whitebox and raster tools use their WASM engines, and browser conversion formats remain available. Sidecar-only tools, native-file paths, and the local PostgreSQL/Martin source stay hidden on mobile. These limits are gated by a user-agent isMobile() check (which already matches iPhone/iPad), so an unavailable path does not appear and then fail.

Location permission (required)

This is the one place iOS differs sharply from Android. Android’s geolocation plugin declares the runtime permission and the OS shows a generic dialog; iOS terminates the app the instant it requests location if no usage-description string is present. Meratyn supplies it in src-tauri/Info.ios.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>Meratyn uses your location to center the map, capture GPS points during Field Collection, and record GPS tracks.</string>

Tauri merges Info.ios.plist into the generated gen/apple/mappview_iOS/Info.plist at build time. gen/apple is git-ignored, so this file is the durable home for the string — the same reason Android’s manifest permissions come from the plugin rather than a hand-edited, regenerated manifest. It covers all three location consumers: Field Collection, GPS Tracking, and the Controls → GeoLocate map control. After a build, confirm the key survived the merge (see Build below).

Toolchain setup (one time)

You need a Mac with Xcode (from the App Store; open it once to accept the license and install the iOS platform), the command-line tools, CocoaPods, and the Rust iOS targets.

xcode-select --install                 # command-line tools (if not already)
sudo xcodebuild -license accept
brew install cocoapods                 # or `gem install cocoapods`

# Rust device + simulator targets (install rustup first if needed)
rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios

aarch64-apple-ios is real devices and signed release .ipa archives; aarch64-apple-ios-sim is the simulator on Apple Silicon Macs.

Build

cd apps/mappview
bunx --no-install tauri ios init                     # generate src-tauri/gen/apple (once)
bunx --no-install tauri ios dev                      # run in the simulator / on a tethered device
bunx --no-install tauri ios build                    # release archive → signed .ipa (needs signing, below)
  • gen/apple is generated (git-ignored) and regenerated on demand. init also applies tauri.ios.conf.json (bundle id, drops the Python backend). Info.ios.plist is merged later by tauri ios build or tauri ios dev.

  • The app is named Meratyn on iOS (the desktop build is “Meratyn Desktop”) and uses the bundle id com.mapptech.mappview, both set via src-tauri/tauri.ios.conf.json — the same override pattern and reasoning as Android (identifier in tauri.conf.json stays com.mapptech.mappview so desktop upgrades keep using the existing data and configuration namespaces).

  • The durable iOS deployment target is iOS 15.0, configured as bundle.iOS.minimumSystemVersion in tauri.ios.conf.json. The CI workflow verifies that Tauri carries it into both the generated Xcode project and a signed IPA before an upload can proceed.

  • Verify the location string landed after a build:

    /usr/libexec/PlistBuddy -c 'Print :NSLocationWhenInUseUsageDescription' \
      src-tauri/gen/apple/mappview_iOS/Info.plist

Signing

Every build that runs on a real device must be signed — there is no debug-keystore shortcut like Android’s. You need:

  1. An Apple Developer Program membership ($99/year).
  2. A signing certificate (Apple Development for device testing; the distribution certificate, when available, for distribution builds), exported from Keychain as a .p12.
  3. A provisioning profile for the com.mapptech.mappview app id.
  4. Your Team ID (Developer portal → Membership details).

Opening gen/apple/mappview.xcodeproj in Xcode and enabling “Automatically manage signing” with the Meratyn team is the simplest local path.

The iOS GitHub Actions workflow also runs on releases or manually. Without signing secrets it performs a real-device Rust compile check. With the complete secret set it creates an unsigned archive, stamps a unique build number, exports it under explicit manual signing, verifies the shipped bundle identifier/signature/plist, and uploads the .ipa:

  • APPLE_IOS_CERTIFICATE_BASE64 — Apple Distribution .p12, base64 encoded
  • APPLE_IOS_CERTIFICATE_PASSWORD
  • APPLE_IOS_PROVISIONING_PROFILE_BASE64 — manually managed profile for com.mapptech.mappview, base64 encoded
  • APPLE_TEAM_ID

The iOS certificate secrets are intentionally separate from the macOS Developer ID credentials; those certificate types are not interchangeable.

Install / test

  • Simulator: bunx --no-install tauri ios dev and pick a simulator, or open the Xcode project and Run. No paid account needed for the simulator.
  • Your own device: tether it, open gen/apple/mappview.xcodeproj in Xcode, select the device, and Run (a free Apple ID allows 7-day device signing).
  • Testers: hand them the signed .ipa to sideload via Xcode (Devices & Simulators window), Finder, or Apple Configurator; or they can open gen/apple/mappview.xcodeproj in Xcode themselves and Run on their own device.

Known limitations / follow-ups

Most mirror Android:

  • Local-file sources (MBTiles, local rasters, project files) assume real filesystem paths; iOS hands apps sandboxed URLs via the document picker, so those flows need adapting before they work natively.
  • The Download Offline Area tool relies on a service worker, which the Tauri builds don’t use — it’s a PWA feature. Native offline basemap caching is future work.
  • Earth Engine OAuth uses a desktop loopback/multi-window flow; a mobile deep-link redirect (an iOS URL scheme / universal link) is future work.
  • iPadOS multitasking (Split View / Stage Manager) hasn’t been tuned; the responsive layout should adapt, but verify on a real iPad before release.