How One's native APIs are organized, where each runs, and how they get into your app
One ships native iOS and Android APIs inside the one package: shared views
that render a native control on each platform, SwiftUI and UIKit views for
iOS, Jetpack Compose views for Android, and services such as notifications,
storage, and the camera. Installing one brings all of it, and the native
build links it with no extra packages.
Every API hangs off the One namespace, and the namespace tells you where it
runs. Reach for One.UI and the root services first; they work on both
platforms. Use One.iOS or One.Android when you want a platform’s own
control exactly as that platform defines it.
import { useState } from 'react'import { One } from 'one'
function AirplaneMode() { const [on, setOn] = useState(false) if (One.platform === 'ios') { return <One.iOS.Toggle label="Airplane mode" isOn={on} onIsOnChange={setOn} /> } if (One.platform === 'android') { return <One.Android.Switch isOn={on} onIsOnChange={setOn} /> } return null}Each platform gets its own control, with that platform’s prop names, and the check keeps each one off the platform that cannot draw it.
Namespaces. The One object groups everything by where it runs:
One.UI holds shared views, such as One.UI.Image, One.UI.Map, and
One.UI.TextInput. One prop contract, drawn by a native control on each
platform, with a web version or nothing on web.One.iOS holds SwiftUI views and UIKit controllers under Apple’s names
and argument shapes, such as One.iOS.Toggle and One.iOS.List.One.Android holds Jetpack Compose views under Compose’s names and
parameters, such as One.Android.Switch and One.Android.Card.One.Notifications, One.Clipboard, and
One.FileSystem, have one contract on every platform.Hooks and state helpers, such as useSizeClass and useNativeState, are
named imports from one.
Platform checks. One.platform is 'ios', 'android', or 'web'. The
native build sets it for each bundle it makes, and anything else reads as
web. Use it, or Platform.OS, to pick between platform views.
Bridges. Services are Nitro hybrid objects: a TypeScript spec declares the interface, and Nitro generates the Swift and Kotlin bindings, so calls reach native code through JSI. Views are Fabric components: their specs declare the props and events, and React Native codegen builds the native view managers. Swift views render SwiftUI inside a hosting view; Android views render Compose inside a Compose view.
Linking. one includes a podspec, an Android Gradle module, and a codegen
config, so React Native autolinking adds the native code to the Xcode and
Android projects that one prebuild generates.
App config. Capabilities that change the native project, such as push,
picture in picture, or the Android maps key, are set under native.app in
your one() Vite config. Prebuild writes them into the plist, manifest, and
Gradle files, so a change takes a new prebuild and a native build. Each page
lists the keys it needs.
| iOS | Android | Web | |
|---|---|---|---|
| One.UI | Native control | Native control | Web version or nothing |
| One.iOS | SwiftUI or UIKit | Throws | Throws |
| One.Android | Throws | Compose | Throws |
| Services | Native | Native | Browser API or empty |
One.iOS SwiftUI
view outside iOS throws “requires an iOS native build”, and a
One.Android view outside Android throws “requires an Android native
build”. Branch on One.platform before rendering them.native.app changes the
generated projects, which hot reload cannot apply. Run prebuild and rebuild.import { Pressable, Text } from 'react-native'import { One } from 'one'
function CopyCode({ code }: { code: string }) { async function copy() { await One.Clipboard.setString(code) One.Haptics.notification('success') } return ( <Pressable onPress={copy} accessibilityRole="button"> <Text>Copy {code}</Text> </Pressable> )}Root services need no platform check. Clipboard writes on every platform, and haptics accepts the call on web and does nothing, since browsers have no matching feedback.
import { Text, View } from 'react-native'import { useSizeClass } from 'one'
function Inbox() { const sizeClass = useSizeClass() return ( <View style={{ flex: 1, flexDirection: sizeClass.horizontal === 'regular' ? 'row' : 'column' }}> <Text>Folders</Text> <Text>Messages</Text> </View> )}useSizeClass is a named import, not part of One. A regular width, such
as an iPad in landscape, puts the panes side by side.
One native services use Nitro Modules, created by Marc Rousavy and Margelo. Views are Fabric components, not Nitro views.
Edit this page on GitHub.