Skip to main content

Build to a device

The Android emulator has no arm64 native libraries for these backends, and MLX only runs on physical iOS hardware. A simulator tells you the app launches. It tells you nothing about whether inference works or how fast it is.

Register a backend before initializing

Remember the plural inputs

Every other SDK names these AudioInput and ImageInput. Examples copied from the Swift or Web pages will not resolve here.

Use the pull-shaped streams

There is no stt.openStream or vad.openStream on React Native. Feed transcribeStream and detectStream an async iterable instead. AudioCaptureManager from @runanywhere/core saves you writing the bridge.

Batch state updates while streaming

Setting React state on every token re-renders on every token. Accumulate in a ref and flush on an interval:

Cap output length

maxOutputTokens is the biggest lever on latency and battery.

Unload what you are not using

Holding a language model, a speech model, and a vision model at once on a phone is how you get insufficientMemory.

Close sessions when the app backgrounds

Voice sessions hold the microphone. A session that survives backgrounding keeps recording.

Guard against setting state after unmount

Every streaming loop needs a cancellation ref. Without one, a slow generation writes state into a component that is gone.

Do not trust capabilities() for backends

capabilities() is a static literal on React Native and lists only llama.cpp and ONNX, regardless of what you installed. Use it to understand the API surface, not your build.

Keep tool executors fast

Generation is paused while your executor runs. A slow fetch inside a tool reads to the user as a hung model.

Show download size before downloading

Models are hundreds of megabytes. On cellular, that is the user’s money. Show the size, and prefer the smallest model that does the job.