One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

Native Setup

Install One Native and generate iOS or Android projects with or without Expo

One Native is included in the one package. There is no separate native UI package to install. The v2 beta uses React 19.2.3 and React Native 0.87; the current examples use 0.87.1. Native components require the New Architecture. The installation guide lists the full dependency set, including screens, Worklets, and Liquid Glass. The iOS deployment floor is 17. See the platform notes for feature-specific requirements.

For a new app, start with:

Terminal window
npx one@beta

For an existing One app, update one to the beta and align its React, React Native, and React Navigation peers. Use your package manager to inspect the installed package’s peer dependencies. The navigation peers are 8 alpha versions, so keep their versions aligned.

A project without Expo

Configure the application through native.app in vite.config.ts:

import { one } from 'one/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
one({
native: {
app: {
name: 'MyApp',
ios: {
bundleId: 'com.example.myapp',
deploymentTarget: '17.0',
},
android: {
applicationId: 'com.example.myapp',
},
},
},
}),
],
})

Add react-native.config.cjs at the app root:

module.exports = require('one/react-native-config')

For an existing app, ensure its devDependencies include the community native template and CLI. The current One examples use template 0.87.1 and CLI 20.2.0:

Terminal window
npm install --save-dev @react-native-community/template@0.87.1 @react-native-community/cli@20.2.0

Then generate the projects from the app directory:

Terminal window
one prebuild

One generates ios/ and android/ from the React Native community templates. React Native autolinking includes One’s pod, Android module, Fabric components, and native service dependencies. Run this through the app’s scripts or your package manager’s local executable command if one is not on your shell PATH.

Use native.app for icons, launch screens, fonts, deep links, and permissions. The native project guide lists the manifest fields. Give each permission a description of why your app needs it. For example, native.app.imagePicker.camera supplies the camera usage configuration. Updating native configuration or adding a native dependency requires generating and rebuilding the native project.

A project with Expo

One’s native startup installs the ES2023 array methods toSorted, toReversed, toSpliced, and with before app modules load. This includes Hermes releases whose built-in array methods are incomplete. Apps use the standard methods directly; dependency code and app startup need no separate polyfill setup.

Apps that install expo use Expo prebuild. Add One’s adapter to the app’s Expo configuration while retaining the app’s other plugins:

{
"expo": {
"plugins": ["vxrn/expo-plugin"]
}
}
Terminal window
npx expo prebuild

Expo modules and config plugins remain available on this path. The adapter links the generated host to One and applies the One native configuration it supports. See Build or Run iOS and Ship with EAS. One Native requires a custom native build; Expo Go cannot load native code that is absent from its binary.

Run the app

Start One’s development server in one terminal:

Terminal window
one dev

Build and launch the generated app in another:

Terminal window
one run:ios

Or use one run:android. iOS builds need macOS, Xcode, and CocoaPods. Android builds need the Android SDK and JDK 17. Run native compilation on your build machine or CI as appropriate for your project.

The default bundler is Rolldown. If your dependencies require Metro, follow Metro Mode. Both modes use the same One route tree.

ONE_PUBLIC_ variables are exposed to app code. EXPO_PUBLIC_ variables remain accepted, including for Expo dependencies; see Environment. Rebuild the native app for native code or manifest changes, even when JavaScript hot reload is working.

Add a first native control

Put this in an iOS route, such as app/settings.ios.tsx:

import { useState } from 'react'
import { One } from 'one'
export default function Settings() {
const [enabled, setEnabled] = useState(true)
return (
<One.iOS.Form style={{ flex: 1 }}>
<One.iOS.Section title="Notifications">
<One.iOS.Toggle
label="Allow notifications"
isOn={enabled}
onIsOnChange={setEnabled}
/>
</One.iOS.Section>
</One.iOS.Form>
)
}

The callback updates the controlled setting in React state. For shared native text-input state, use useNativeState with TextInput. This sample changes a setting only; requesting notification permission is a separate Notifications API call.

Edit this page on GitHub.