Asuka
What Asuka has, against SwiftUI and Expo

Reference

What Asuka has, against SwiftUI and Expo

What Asuka has, and what it doesn't yet.

Each row is something apps often need: how SwiftUI and Expo do it, and what Asuka has for it. A ✓ is on every platform Asuka runs on (iOS, Android, the Mac, Windows, Linux and the web) unless the row says otherwise; where a platform hasn't something (a Mac has no sensors, a browser no home screen widgets), its package answers that it hasn't. In a browser, what each package does instead where a browser can't do what a phone does is in The web.

SwiftUI also runs on the Mac. Expo runs on iOS, Android and the web; React Native reaches Windows and the Mac through Microsoft's React Native for Windows and macOS, outside Expo. For Asuka against the desktop's own frameworks (Electron, Tauri, Wails), see On the desktop.

✓ has it · ◐ in part (what's missing is said) · ✗ not yet

Layout

SwiftUI Expo (React Native) Asuka
Stacks, spacing, padding, alignment HStack, VStack, Spacer flexbox ✓ Row, Column, Style (flexbox: Grow, Gap, Align, Justify, Wrap)
Overlays, absolute placement ZStack, .overlay position: absolute ✓ Style.Absolute, Top/Left/...
Scrolling ScrollView ScrollView ✓ Scroll (vertical, horizontal; out-of-sight rows leave the tree)
Lazy lists, cell recycling List, LazyVStack FlatList ✓ List (the platform's: UICollectionView, RecyclerView; on the Mac, Windows, Linux and the web, the host binds and recycles the rows in view)
Grids LazyVGrid FlatList numColumns ✓ ListProps.Columns, Gap
Chat lists: start at the end, load older above defaultScrollAnchor(.bottom), scrollPosition FlatList inverted, maintainVisibleContentPosition ✓ ListProps.Anchor, OnStartReached; rows added above what shows leave it in place, in every list
Sections, sticky headers Section in a List SectionList, stickySectionHeadersEnabled ✓ ListProps.Section, Header (sticky in plain and bare lists)
Selecting rows List(selection:), EditButton community ✓ ListProps.Selecting, Selected, OnSelect, OnSelectBegin (iOS's edit mode and two-finger pan; Android's checkboxes and long press)
Safe area, keyboard automatic SafeAreaView, KeyboardAvoidingView ✓ SafeArea, UseEnvironment().Keyboard
Reading a view's size GeometryReader onLayout ✓ ViewProps.OnLayout
Aspect ratio, min/max sizes .aspectRatio, .frame(min:max:) style ✓ Style

Controls

SwiftUI Expo Asuka
Text, styled text, links Text, AttributedString Text ✓ Text, RichText (spans, links, inline views, selection), asuka/markdown
Buttons (variants, icons, menus) Button, Menu Pressable ✓ Button (filled, tinted, gray, bordered; icon; menu), Menu, context menus
Text fields TextField, SecureField, TextEditor TextInput ✓ TextField (secure, keyboards, return keys, multiline)
The cursor, inserting at it TextSelection selection, onSelectionChange ✓ TextFieldProps.Selection, ui.InsertText
Rich text editing (a mail's body) TextEditor with AttributedString (iOS 26) community (10tap, pell) ✓ TextFieldProps.Rich, ToggleFormat, SetLink, OnFormats
A bar on the keyboard .toolbar { ToolbarItemGroup(placement: .keyboard) } InputAccessoryView (iOS) ✓ TextFieldProps.Accessory (both)
Pasted images, keyboard GIFs and stickers onPasteCommand, PasteButton community (onPaste) ✓ TextFieldProps.PasteTypes, OnPaste (Android's commitContent too)
Toggle, slider Toggle, Slider community ✓ Toggle, Slider
Segmented control Picker(.segmented) community ✓ Segmented
Date and time DatePicker community ✓ DatePicker (date, time, both)
Progress, spinner ProgressView ActivityIndicator ✓ Progress, Activity
Wheel and menu pickers, stepper Picker, Stepper community ✓ Wheel, Stepper, a menu from Button.Menu
Color picker ColorPicker community ✓ ColorPicker (iOS's system picker; on Android, which has none, a Material dialog of Google's palette, with opacity)
Icons SF Symbols @expo/vector-icons ✓ Symbol (SF Symbols on iOS and the Mac; for the same names, Material Symbols on Android and the web, Segoe Fluent Icons on Windows, the icon theme's or Material Symbols on Linux: a curated set)
Images (remote, cached, placeholders) AsyncImage expo-image ✓ Image (memory and disk cache, Placeholder)
Video VideoPlayer expo-video ✓ Video (AVKit on iOS and the Mac, Media3 on Android, WebView2 on Windows, GStreamer on Linux, <video> on the web)
Web content WKWebView react-native-webview ✓ WebView (WKWebView on iOS and the Mac, Android's WebView, WebView2 on Windows, WebKitGTK on Linux; URL, HTML, messages both ways, scripts before the page's, blocked requests, its state and history, downloads, new windows, cookies, a script's value; each request on Android; on the web, all of it for the app's own site and for pages that cooperate through postMessage, while another site's page only loads); asuka/js runs JavaScript off screen
Maps Map expo-maps ✓ asuka/maps (Apple Maps; Google Maps with an API key: region, markers, the user's location, taps; libshumate's OpenStreetMap map on Linux; on Windows the host draws OpenStreetMap's tiles itself)
Custom drawing Shape, Path, Canvas react-native-svg, Skia ✓ Shape and Path (fill, stroke, caps, joins, dashes, an animatable trim); Canvas (paths, gradients, text, transforms, clips, opacity); SVG icons drawn natively (asuka/svg)
Charts Swift Charts victory-native, community ✓ asuka/chart (bars, lines, areas, points)
Shaders .colorEffect(ShaderLibrary...) Skia's runtime effects ✓ Shader (Kage, Go's syntax: Metal on iOS and the Mac, AGSL on Android, WebGL 2 on the web, the CPU on Windows and Linux)
Native escape hatch UIViewRepresentable native modules ✓ ui.Native views, ui.Call modules (Swift on iOS and macOS, Kotlin on Android, Go on the desktop, JavaScript on the web: Native code)
Paging, page dots .scrollTargetBehavior(.paging), TabView(.page) react-native-pager-view ✓ ScrollProps.Paging, PageControl
Checkbox Toggle (.checkbox, macOS) community ✓ ToggleProps.Checkbox
SwiftUI Expo (expo-router) Asuka
Stacks with native push, pop, back gestures NavigationStack Stack ✓ Stack, UseNavigator
Tabs TabView Tabs ✓ Tabs
Sidebar, drawer NavigationSplitView Drawer ✓ SplitView (a stack on iPhone, a drawer on Android; NSSplitViewController on the Mac, a navigation pane on Windows, libadwaita's split view on Linux)
Bar buttons, titles, search .toolbar, .searchable header options ✓ ScreenOptions (Actions, Search)
Sheets with detents .sheet, .presentationDetents modal ✓ Sheet (Detents, Grabber)
Taking back, preventing dismissal .navigationBarBackButtonHidden, .interactiveDismissDisabled BackHandler, usePreventRemove ✓ OnBack (screens, sheets, the app)
Popovers .popover — ✓ Popover (a popover on iPhone too)
Alerts, action sheets .alert, .confirmationDialog Alert ✓ Alert (both styles)
Deep links, universal and app links .onOpenURL Linking ✓ OnOpenURL, asuka.json scheme and links
Pull to refresh, swipe actions .refreshable, .swipeActions RefreshControl ✓ (both edges: SwipeActions, LeadingSwipeActions)

Motion

SwiftUI Expo (Reanimated) Asuka
Animating changes withAnimation withTiming, withSpring ✓ Animate, AnimateWith (ease, linear, spring; repeat, autoreverse)
Transforms .rotationEffect, .scaleEffect, .offset transform ✓ Style.Transform
Enter and exit transitions .transition entering/exiting ✓ Style.Transition (Fade, Pop, SlideUp, your own)
Frame-driven animation TimelineView(.animation) useFrameCallback ✓ OnFrame
Shadows, gradients, blur .shadow, LinearGradient, materials style, expo-linear-gradient, expo-blur ✓ Shadow, LinearGradient, Material
Gestures tap, long press, drag, magnify, rotate Gesture Handler ✓ tap, long press, pan, pinch, rotate, swipe
Pressed and hover states ButtonStyle's isPressed, .onHover Pressable's pressed, onHoverIn/onHoverOut ✓ Style.Pressed, Hovered variants; Interaction for a group's or a peer's (Style.When); OnPressedChange, OnHoverChange
Drag and drop .draggable, .dropDestination (none built in) ✓ Drag, Drop (Go values within the app; texts, links, files with other apps; Dragging and DragOver variants)
Shared-element transitions matchedGeometryEffect, .navigationTransition(.zoom) shared transitions ✓ Style.Match (a view grows from another's place and size), ScreenOptions.ZoomFrom (a pushed screen zooms out of a view: iOS 18's zoom; Material's container transform)
Haptics sensoryFeedback expo-haptics ✓ Haptic
Reduce Motion accessibilityReduceMotion useReducedMotion ✓ Environment.ReduceMotion (iOS transitions dissolve)

Data and services

SwiftUI / Apple Expo Asuka
State @State, @Observable hooks ✓ signals (fine-grained: a write updates only what reads it)
Small persisted values @AppStorage AsyncStorage ✓ asuka/store
SQLite SwiftData / GRDB expo-sqlite ✓ asuka/sqlite (migrations, typed queries, transactions, writes off the main thread, live queries that run again when a table they read is written, also with arguments that change: WatchWith; in the browser too, SQLite's WebAssembly build)
Secure storage Keychain expo-secure-store ✓ asuka/secure (on the web: encrypted in IndexedDB under a key the browser won't let out; not a keychain)
Files, network Foundation expo-file-system, fetch ✓ Go's os, net/http
Photos PhotosPicker expo-image-picker ✓ device.PickPhotos
Documents UIDocumentPickerViewController expo-document-picker ✓ device.PickFiles (MIME types, several)
Camera AVFoundation expo-camera ✓ asuka/camera: Take (the system's camera; on the Mac, Windows and Linux, a dialog with a live preview; Windows: Media Foundation's capture engine; Linux: the camera portal or Video4Linux through GStreamer), View (a live preview, front or back), Capture; asuka/camera/record records video with sound
Barcodes, QR codes AVFoundation, Vision expo-camera scanning ✓ asuka/scan: live in camera.View (Scan: scan.Codes(...)) and in image files (scan.File); ML Kit on Android, only in the apps that import it; ZBar on Linux; on Windows Asuka's own reader in Go (internal/barcode: QR, Data Matrix, EAN, UPC, Code 128, Code 39)
Location Core Location expo-location ✓ asuka/location (place names: on Windows, OpenStreetMap's Nominatim)
Translations, plurals, regional formats String Catalogs, FormatStyle expo-localization, i18next ✓ asuka/i18n, catalogs (Languages)
Right-to-left layout layoutDirection I18nManager ✓ follows the language, ui.WithDirection
Local notifications UserNotifications expo-notifications ✓ asuka/notify (now or scheduled, images; iOS, Android, macOS, Linux; Windows' toasts, with buttons and replies through the app's COM activator; on the web through the app's service worker, so they stay and answer after the page closes, a scheduled one showing at its time while a page of the app is open, else as the next opens: browsers can't schedule one)
Push notifications APNs expo-notifications ✓ asuka/push (APNs on iOS and macOS, Firebase Cloud Messaging, Web Push with VAPID on the web: the token, messages received and tapped; asuka/push/webpush sends Web Push from a Go server)
Notification actions, inline replies UNNotificationCategory, UNTextInputNotificationAction setNotificationCategoryAsync ✓ notify.SetCategories, OnAction (background actions run the app's Go code, started without a screen if it isn't running; Response.Defer; Android's reply posted back into the conversation; on the web, the service worker's notification actions, inline replies where Chrome has them)
Threads, the notifications showing, the badge threadIdentifier, getDeliveredNotifications, setBadgeCount getPresentedNotificationsAsync, setBadgeCountAsync ✓ Thread (Android: a group with its summary kept), notify.Showing, Remove, RemoveThread, SetBadge (Android: the launcher's, from the notifications)
Notifications in the foreground willPresent setNotificationHandler ✓ notify.Present (banner, quiet, hidden)
Android notification channels — setNotificationChannelAsync ✓ notify.SetChannels, SetChannelGroups; a push's channel_id (iOS has none)
Messages in conversations Communication notifications (INSendMessageIntent) community ✓ Notification.From, push.Message.From: iOS's communication notifications (the entitlement added for the apps that use it), Android's MessagingStyle and conversation shortcuts; plain on macOS; no bubbles
Changing a push before it shows Notification Service Extension community (expo-notifications has none) ✓ push.Rewrite: the app's Go code in iOS's extension (built and signed by asuka build), in the app's process for Android's data messages
Clipboard, share sheet, browser UIPasteboard, ShareLink, SFSafariViewController expo-clipboard, expo-sharing, expo-web-browser ✓ Copy, device.Clipboard (text; images: CopyImage, ClipboardImage; ClipboardHas, OnClipboardChange), Share (text), ShareFiles (files, with expo-sharing's MIME type, UTI, title and iPad anchor; done when the sheet closes), device.Browse
Previewing files QLPreviewController, .quickLookPreview react-native-file-viewer ✓ asuka/preview (Quick Look on iOS and the Mac, several files, Markup; Android's viewer apps; Windows's and Linux's default app)
Printing, PDFs from HTML UIPrintInteractionController, UIPrintPageRenderer expo-print ✓ asuka/print (files, HTML, a WebView, with the system's dialog and its result; PDF: paginated, the region's paper, margins)
Mail and message composers MFMailComposeViewController, MFMessageComposeViewController expo-mail-composer, expo-sms ✓ asuka/compose (recipients, subject, HTML body, attachments; what the user did on iOS; the mail apps only on Android; Messages on the Mac)
Keep awake, device info isIdleTimerDisabled, UIDevice expo-keep-awake, expo-device ✓ device.KeepAwake, device.GetInfo
Network state NWPathMonitor expo-network ✓ asuka/network (online, Wi-Fi or cellular, metered, Data Saver / Low Data Mode)
Saving to the gallery, Downloads PHPhotoLibrary expo-media-library ✓ asuka/library (MediaStore's collections; Photos, or Documents in Files)
Work in the background beginBackgroundTask, BGTaskScheduler expo-task-manager, expo-background-task ✓ asuka/background: Android keeps the app running, its progress and buttons in a notification; iOS gives about 30 seconds; the Mac keeps it running (App Nap off), Linux and Windows keep the system from suspending. asuka/periodic: tasks the system runs now and then, the app's Go code started without a screen (BGTaskScheduler, WorkManager; on the Mac while the app runs, NSBackgroundActivityScheduler; on Linux and Windows, a timer while it runs)
Receiving shares from other apps Share extension expo-sharing (useIncomingShare) ✓ ui.OnShare: texts, links, images, videos, audio and files, one or many, with their name, MIME type and size (asuka.json's shareTarget: types and max, Android's intent filters and iOS's activation rule from them; on iOS a share extension that opens the app, files through an App Group); app.ShareSheet, the app's own screen over the app that shares (iOS: its share extension; Android: a bottom sheet in a process of its own), its data shared with the app; no resolving of links (net/http)
Audio AVAudioPlayer, AVAudioRecorder expo-audio ✓ asuka/audio (load, play, pause, seek, volume, loop); asuka/audio/record (voice or music quality, pause, a level meter)
Sign in with Apple SignInWithAppleButton expo-apple-authentication ✓ asuka/appleauth (Apple's button, the credential, its state; iOS and macOS)
Face ID, fingerprints LocalAuthentication expo-local-authentication ✓ asuka/biometric (Windows Hello on Windows; on the web, the platform's authenticator through WebAuthn)
Store review requestReview expo-store-review ✓ asuka/review (the App Store's prompt, Play's in-app review)
Tracking permission App Tracking Transparency expo-tracking-transparency ✓ asuka/tracking
App integrity App Attest expo-app-integrity ✓ asuka/integrity (App Attest, Play Integrity)
Age range Declared Age Range expo-age-range ✓ asuka/agerange (Declared Age Range, Play Age Signals)
Sensors Core Motion expo-sensors ✓ asuka/sensors (accelerometer, gyroscope, magnetometer, device motion with attitude and heading, barometer, light, pedometer; the same axes and units on both; a Mac and Windows have none; Linux: iio-sensor-proxy's light and orientation)
Image editing Core Graphics, ImageIO expo-image-manipulator ✓ asuka/imageedit (resize, crop, rotate, flip, fill, pixelate; HEIC in, JPEG or PNG out, upright, without the source's metadata; GdkPixbuf's decoders on Linux, WIC's on Windows)
Text, faces and codes in an image Vision no ✓ asuka/vision, with where each is; ML Kit on Android, only in the apps that import it; Linux: ZBar's codes and Tesseract's text, no faces; Windows: its OCR's text and faces, Asuka's reader's codes
The photo library PhotoKit expo-media-library ✓ asuka/photos: permission, listing, thumbnails, the original files (Windows: the Pictures folder)
Video thumbnails AVAssetImageGenerator expo-video-thumbnails ✓ imageedit.VideoFrame
Text to speech AVSpeechSynthesizer expo-speech ✓ asuka/speech (a queue, voices, pitch, rate, pause at a word)
Contacts Contacts, ContactsUI expo-contacts ✓ asuka/contacts (the picker and new contact screen without permission; the address book with it; Windows: adding opens a vCard, no address book)
Calendars EventKit, EventKitUI expo-calendar ✓ asuka/calendar (the event editor without permission; calendars and events with it; Windows: adding opens an iCalendar file, no calendars)
Home screen widgets WidgetKit expo-widgets ✓ asuka/widget and asuka.json's widgets (a template in every size, the lock screen's on iOS; timelines, countdowns, taps with a URL)
App Intents, shortcuts App Intents, App Shortcuts — ✓ asuka.json's shortcuts (iOS: App Shortcuts with Siri phrases, in Spotlight and Shortcuts; Android: launcher shortcuts)
Custom fonts .font(.custom) expo-font ✓ Font.Family
Lifecycle scenePhase AppState ✓ app.OnLifecycle
Launch screen UILaunchScreen expo-splash-screen ✓ asuka.json's splash; asuka/splash holds it while the app loads
Status bar, navigation bar statusBarHidden, preferredStatusBarStyle expo-status-bar, expo-navigation-bar ✓ asuka/screen's SetBars
Orientation lock supportedInterfaceOrientations expo-screen-orientation ✓ asuka/screen's Lock
Screenshots isCaptured, userDidTakeScreenshotNotification expo-screen-capture ✓ asuka/screen's PreventCapture (Android: blank captures; iOS: covered while recorded; macOS and Windows: the windows left out), OnScreenshot (Linux and Windows: new images in Pictures/Screenshots)
Crash reports MetricKit, Crashlytics, Sentry Sentry, Crashlytics (@react-native-firebase/crashlytics) ✓ asuka/crash: Go panics and fatal errors, uncaught exceptions, MetricKit's crashes and hangs, Android's native crashes and ANRs, with breadcrumbs and values; the app sends them where it likes (no service built in); dSYMs and native debug symbols from asuka build

Appearance and accessibility

SwiftUI Expo Asuka
Dark mode, semantic colors, accent automatic useColorScheme ✓ semantic colors, asuka.json accent (Material 3 dynamic color on Android; on the Mac, AppKit's own controls keep the user's accent)
Dynamic Type, font scale automatic allowFontScaling ✓ text styles and custom fonts scale
Screen reader labels, roles, hiding .accessibilityLabel... accessibilityLabel... ✓ Label, Hint, Role, Decorative; pressable views are buttons
Announcements AccessibilityNotification.Announcement announceForAccessibility ✓ Announce
Moving a screen reader's focus @AccessibilityFocusState setAccessibilityFocus ✓ AccessibilityFocus
Is a screen reader on voiceOverEnabled isScreenReaderEnabled ✓ Environment.ScreenReader
Custom actions, adjustable .accessibilityAction, .accessibilityAdjustableAction accessibilityActions ✓ ViewProps.Actions, OnAdjust (and List swipe actions are TalkBack actions)

Tooling

Xcode / Expo Asuka
Live reload, keeping state previews, Fast Refresh ✓ asuka dev: reloads on save, keeps signals' values (on a phone the Go code runs on your computer; on the desktop the app is rebuilt and run again; in the browser the page reloads)
Release builds and signing Xcode, EAS Build ✓ asuka build: an .ipa, an .aab, a universal .app signed and notarized (or a Mac App Store .pkg), a Windows folder with its .exe signed, a Linux install prefix with a .tar.gz and a Flatpak manifest, a static site (Shipping)
Uploading to the stores Xcode, EAS Submit ✓ asuka publish: TestFlight, App Review, Google Play's tracks; not the Mac App Store yet
GUI tests XCUITest, Detox, Maestro ✓ e2e/: the examples on the iOS simulator, an Android emulator, Linux under Xvfb and headless Chrome; the Mac's and Windows' host tests drive real AppKit views and Win32 windows
Benchmarks Instruments ✓ bench/ (against SwiftUI and Compose)
Embedding in an existing app — brownfield (React Native's)
Over-the-air updates — EAS Update: ✗

On the desktop

On the Mac, Windows and Linux, apps are often made with a web view around HTML instead. How those frameworks compare with Asuka:

Electron Tauri Wails React Native for Windows and macOS Asuka
Platforms Mac, Windows, Linux Mac, Windows, Linux; iOS and Android (Tauri 2) Mac, Windows, Linux Windows, Mac (with React Native's iOS and Android) Mac, Windows, Linux, iOS, Android, the web
What shows the interface HTML and CSS in Chromium HTML and CSS in the system's web view (WKWebView, WebView2, WebKitGTK) HTML and CSS in the system's web view the platform's native views the platform's widgets: AppKit; Win32 and the common controls, drawn as Windows 11's; GTK 4 and libadwaita
The app's language JavaScript (Node.js beside the page) Rust, and JavaScript in the page Go, and JavaScript in the page JavaScript Go
What ships with the app Chromium and Node.js the app's binary (the web view is the system's) the app's binary (likewise) a JavaScript engine and React Native's runtime the app's Go binary (on Linux, GTK 4 and libadwaita come from the system); no web view unless the app shows a WebView

A web view app looks the same on every system, as its HTML and CSS say, and uses the web's libraries. A Asuka app looks as each platform's apps do (an app that sets no style is a Mac app on the Mac, a GNOME app on Linux, a Windows 11 app on Windows) and gets their accessibility, text input and menus, with one layout engine, in Go, for all of them. The desktop hosts run the app's Go in its own process, calling the platform without cgo, so asuka build makes Windows and Linux builds from any system.

Not yet

In order of what apps miss most: App Intents with parameters and entities (shortcuts take none yet), widgets of the app's own layout (one template for now), and over-the-air updates (EAS Update's; Asuka apps are compiled Go, which the stores don't let an app replace). On the Mac: ScreenOptions.ZoomFrom's zoom (a push slides instead), beginning a list's selection with a gesture, and uploading to the Mac App Store with asuka publish (upload the .pkg with Transporter).