Files
archy/docs/research/ios-app.md
T
DorianandClaude Opus 4.6 4ac18cedb6 docs: add research docs for iOS app, Mac desktop, plugin security
- iOS: Capacitor vs WKWebView vs React Native WebView analysis
- Mac: Tauri v2 vs Electron comparison with menu bar app patterns
- Plugins: Signature validation, sandboxed iframes, permission system

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:56:54 +00:00

4.8 KiB

iOS App Research — AIUI

Overview

Three approaches for shipping AIUI (Vue 3 + Vite SPA) as an iOS app.

Capacitor wraps the Vite build output (dist/) in a native iOS Xcode project. The web app runs inside WKWebView with a JavaScript bridge to native device APIs.

pnpm add @capacitor/core @capacitor/cli @capacitor/ios
npx cap init && npx cap add ios
pnpm build && npx cap sync
npx cap open ios  # opens Xcode

Pros:

  • Near-zero code changes to existing Vue 3 app — one codebase for web + iOS + Android
  • Large, mature plugin ecosystem (camera, biometrics, push, geolocation, haptics)
  • Hot reload during dev via npx cap run ios --livereload
  • OTA live updates possible via Capgo, bypassing App Store review for JS changes
  • @capacitor/push-notifications wraps APNs natively

Cons:

  • Service workers do NOT work in WKWebView on iOS (capacitor:// protocol breaks SW registration)
  • Performance ceiling is WebKit JS engine (not V8)
  • Each iOS SDK bump requires Capacitor + plugin updates

Push Notifications: Full support via @capacitor/push-notifications (APNs). Production-grade.

Offline: Entire app bundle ships inside .ipa — available offline. Dynamic data must use @capacitor/preferences or local SQLite. Workbox/SW caching does not work.

Performance: Modern WKWebView uses Nitro JS engine (same as Safari). For a chat UI like AIUI, indistinguishable from Safari. GPU-accelerated CSS transforms work well.

Approach 2: Custom WKWebView Swift Wrapper

Write a native Swift/SwiftUI app embedding WKWebView. Use WKScriptMessageHandler for JS↔Swift communication.

Pros:

  • Maximum native control — own the shell, native navigation, gestures
  • Can implement App Clips, Share Extensions, Widgets alongside web content
  • Full access to all iOS APIs at the native layer

Cons:

  • Requires Swift knowledge — adds second language + build system
  • JS↔Swift bridge must be hand-written for every integration
  • No structured plugin community; each integration is bespoke
  • More setup friction vs Capacitor

Push/Offline/Performance: Same as Capacitor (all use WKWebView). More manual setup.

Approach 3: React Native WebView

Create a React Native app with react-native-webview rendering the Vite build output.

Pros:

  • RN has deep native API access and large ecosystem
  • Surrounding shell can be fully native

Cons:

  • Two separate tech stacks (Vue + RN) — highest maintenance burden
  • No code sharing between Vue app and RN shell
  • Performance often worse (full RN runtime + WebView engine)
  • RN's own breaking changes cadence adds risk

Verdict: Only justified if an existing RN app is already in production.

App Store Risk: Guideline 4.2

Apple's Guideline 4.2 (Minimum Functionality) is the primary risk for all webview-based apps. Apps that pass share these traits:

  • Native tab bar or navigation (not web-based menus)
  • At least one native API integration (push, biometrics, camera, Apple Pay)
  • Offline functionality beyond what a browser bookmark offers
  • UI formatted for iOS, not a desktop website in a phone frame

For AIUI: the chat interface, push notifications, and offline message history constitute sufficient native functionality.

Service Workers in WKWebView

SWs do not run inside WKWebView — this is a fundamental WebKit limitation, not framework-specific. The correct offline strategy for all three approaches: ship assets in app bundle + implement dynamic caching via native storage APIs.

Deep Linking

All three support iOS Universal Links via AASA file + Associated Domains capability:

  • Capacitor: @capacitor/app appUrlOpen event → Vue Router
  • Custom WKWebView: AppDelegate.application(_:continue:...) → JS evaluation
  • RN: React Navigation linking config → WebView postMessage

Comparison

Dimension Capacitor Custom WKWebView RN WebView
Vue code reuse 100% 100% 100%
Native shell effort Low High Very high
Push notifications First-class Manual APNs Via RN layer
App Store risk Moderate* Moderate* Moderate*
Performance Good Good Adequate
Maintenance burden Low-moderate High Very high
Team fit (web-first) Best Poor Poor

*All face identical Guideline 4.2 scrutiny — framework choice is irrelevant to reviewers.

Concrete Next Steps

  1. Add @capacitor/core, @capacitor/cli, @capacitor/ios to packages/app
  2. Set Vite base: './' for the Capacitor build config
  3. Disable PWA service worker for native builds (partially done already)
  4. Add @capacitor/push-notifications for APNs
  5. Implement native splash screen and app icon
  6. Test on iOS Simulator via npx cap run ios
  7. Set up Apple Developer account + code signing
  8. Submit TestFlight build for internal testing