new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Expo & React Native · all subjects

expo-core

512 notes in this subject, read out of this brain and free to use. This is page 4 of 9.

Run TypeScript compiler for module development

Run `npm run build` (or yarn/pnpm/bun equivalent) in the module root directory to start the TypeScript compiler in watch mode during development.

Run example app from development build

Navigate to the example directory and run `npx expo run:android` or `npx expo run:ios` to build and run the example app on Android or iOS respectively.

Module exports public API functions

Export public functions from index.ts that call the native module methods. These functions serve as the module's public API that consumers import. Example: `export function getTheme(): Theme { return ExpoSettingsModule.getTheme(); }`.

Example: Complete native module with persistence and events

A complete example showing: Android using SharedPreferences for storage, iOS using UserDefaults, TypeScript events using EventSubscription, and an example app with useState hook that subscribes to theme changes via `Settings.addThemeListener()` and updates on button press with `Settings.setTheme()`.

Example: Minimal native module setup

Step 1 boilerplate sets up a minimal module with: Android Kotlin module with `getTheme()` returning "system", iOS Swift module with matching `getTheme()`, TypeScript declarations in ExpoSettingsModule.ts and ExpoSettings.types.ts, and a public API in index.ts that calls the native module.

Invalid enum value runtime error

When an invalid enum value is passed to a native function expecting an enum type, the runtime error is: ArgumentCastException with EnumNoSuchValueException indicating the invalid value and listing valid options. Example: 'not-a-real-theme' is not present in Theme enum, it must be one of: 'light', 'dark', 'system'.

Use enums in TypeScript module types

Define a Theme type as a union of string literals: `type Theme = 'light' | 'dark' | 'system';`. This provides compile-time type safety that matches the native enum constraints.

Implement type-safe enums in iOS native modules

Create a Swift enum conforming to String and Enumerable protocols. The raw values are the string representations. Example: `enum Theme: String, Enumerable { case light, case dark, case system }`.

Implement type-safe enums in Android native modules

Create a Kotlin enum class implementing the Enumerable interface from expo.modules.kotlin.types. Each enum value has a String value property. Example: `enum class Theme(val value: String) : Enumerable { LIGHT("light"), DARK("dark"), SYSTEM("system") }`.

Define TypeScript event types

Create an ExpoSettingsModuleEvents type with properties for each event, where each property is a function type that receives the event payload. Example: `onChangeTheme: (params: ThemeChangeEvent) => void;`.

Subscribe to native module events in TypeScript

Use `ExpoSettingsModule.addListener(eventName, listener)` to subscribe to events. The method returns an EventSubscription that has a `remove()` method to unsubscribe.

Emit events from native modules

Declare events using the Events() definition component. On Android, use `sendEvent(eventName, bundleOf("key" to value))` to emit an event with a Bundle payload. On iOS, use `sendEvent(eventName, ["key": value])` to emit with a dictionary payload.

Access UserDefaults on iOS

On iOS, use `UserDefaults.standard` to access the default user defaults database.

Access SharedPreferences on Android

On Android, access SharedPreferences using `context.getSharedPreferences(context.packageName + ".settings", Context.MODE_PRIVATE)`. Get the context from `appContext.reactContext` in your module.

Store and retrieve values from SharedPreferences

Use `getSharedPreferences().getString(key, defaultValue)` to read a string value with a default fallback. Use `getSharedPreferences().edit().putString(key, value).commit()` to write and persist a value.

iOS native module function definition syntax

In Swift, define functions in a Module using the ModuleDefinition block with Function() calls. Explicitly specify parameter types and return type in parentheses. Example: `Function("getTheme") { () -> String in "system" }`.

TypeScript interface for native module

Create a TypeScript class extending NativeModule with declared methods matching the native implementation. Use `requireNativeModule<ModuleType>('ModuleName')` to load the native module via JSI.

Android native module function definition syntax

In Kotlin, define functions in a Module using the ModuleDefinition block with Function() calls. The function body uses an arrow function with implicit return. Example: `Function("getTheme") { return@Function "system" }`.

Create a new Expo Module scaffold

Use `npx create-expo-module <module-name>` to initialize a new Expo Module. Accept default values for all prompts to get started quickly.

Store and retrieve values from UserDefaults

Use `UserDefaults.standard.string(forKey:)` to read a string value, which returns an optional. Use `UserDefaults.standard.set(_:forKey:)` to write a value.

ExpoView base class for native views

Native views should extend ExpoView (from expo.modules.kotlin.views), which extends RCTView from React Native and ultimately extends View on Android and UIView on iOS. This allows React Native's layout engine to manage the view's layout.

Rebuild development build after native changes

After modifying native Android or iOS code, run 'npx expo prebuild --clean' to regenerate the native project files, then 'npx expo run:android' or 'npx expo run:ios' to rebuild and run the app.

Type conversion for URL props

When declaring a prop of type 'URL' in the module definition (Kotlin/Swift), the Expo modules API automatically converts string values from JavaScript to native URL/NSURL types.

TypeScript wrapper for native view

Use 'const NativeView: React.ComponentType<Props> = requireNativeViewManager("ExpoWebView")' to get the native component, then export a functional component that wraps it. Define Props as an intersection of custom props and ViewProps from 'react-native'.

Event payload structure in TypeScript

Event payloads are accessed through the 'nativeEvent' property: 'onLoad?: (event: { nativeEvent: EventPayloadType }) => void'. Define a type for the payload shape (e.g., 'OnLoadEvent = { url: string }').

Initialize a new Expo module

Run 'npx create-expo-module <module-name>' (npm), 'yarn create expo-module <module-name>' (yarn), 'pnpm create expo-module <module-name>' (pnpm), or 'bun create expo-module <module-name>' (bun) to scaffold a new Expo module with workspace structure.

Handle WebView page load events on iOS

Make the ExpoView subclass conform to WKNavigationDelegate, assign 'webView.navigationDelegate = self', and implement 'webView(_:didFinish:)' to detect page load completion. Call the EventDispatcher from this method.

Handle WebView page load events on Android

Override 'onPageFinished(view: WebView, url: String)' in a WebViewClient subclass to detect when a page finishes loading. Call the EventDispatcher from this callback to send the event to JavaScript.

WebView layout setup for iOS

On iOS, override layoutSubviews() and set 'webView.frame = bounds' to ensure WKWebView matches the parent ExpoView's bounds. Also set 'clipsToBounds = true' in init to prevent the WebView from drawing outside its bounds.

WebView layout setup for Android

On Android, when creating a WebView subview, use: 'it.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)' to ensure the WebView fills the parent ExpoView's bounds as calculated by React Native's layout engine.

Define events for native views

Declare events in the ModuleDefinition with Events("eventName"). On Android, use EventDispatcher to dispatch events: 'private val onLoad by EventDispatcher()' then call 'onLoad(mapOf("key" to value))'. On iOS, create EventDispatcher properties and call them with a dictionary.

Define props for native views

Use the Prop definition component with the syntax: Prop("propName") { view: ViewClass, propValue: Type -> ... }. The Expo modules API automatically converts values to the declared type. For a URL prop, declare it as type 'URL' and Expo will convert string values automatically.

Module definition structure for native views

The ModuleDefinition block in both Android (Kotlin) and iOS (Swift) must include: Name("ModuleName") and View(ViewClass::class or ViewClass.self) with configuration blocks inside. For Android, use 'Prop' for properties and 'Events' for event declarations. For iOS, use the same structure with Swift syntax.

Create a native view with WebView example

Tutorial for building an Expo module with a native view that renders a WebView using Android's WebView component and iOS's WKWebView. For Android, set LayoutParams to MATCH_PARENT for both width and height when instantiating the WebView, add it as a subview, and assign a WebViewClient. For iOS, set clipsToBounds to true, add the WKWebView as a subview, and in layoutSubviews() set webView.frame = bounds. The TypeScript wrapper uses requireNativeViewManager('ExpoWebView') to bridge to the native implementation.

Expo Modules API performance characteristics

The Expo Modules API has similar performance characteristics to React Native's Turbo Modules API. Both APIs leverage React Native's JavaScript Interface (JSI) rather than the legacy JSON message queue bridge approach. Both can easily execute hundreds of thousands of native method calls per second, and the overhead of method invocation is unlikely to be a bottleneck since the time spent executing the body of a native method is often orders of magnitude greater than the overhead of the method invocation.

Expo Modules API has experimental support for macOS and tvOS

The Expo Modules API has experimental support for macOS and tvOS platforms beyond the standard Android, iOS, and web support.

Expo Modules support New Architecture and backward compatibility

All Expo Modules support the New Architecture and are automatically backwards compatible with existing React Native apps using the old architecture.

Expo Modules API has negligible impact on app size

Adding the Expo Modules API to an app has a negligible impact on app size, potentially increasing it by a few hundred kilobytes.

Turbo Modules versus Expo Modules API recommendation

Use Turbo Modules if you intend to use C++ in your native module since it provides easier access to lower-level mechanisms. Use the Expo Modules API if you are looking for a better developer experience and are willing to depend on the expo package in your module.

Expo Modules API enables native module development in Swift and Kotlin

The Expo Modules API allows developers to write Swift and Kotlin to add new capabilities to their app with native modules and views. The API is designed to take advantage of modern language features, be consistent across both platforms, require minimal boilerplate, and provide comparable performance to React Native's Turbo Modules API.

Run Expo module in existing project

To run an example Expo module in an existing Expo project, execute `npx expo run:android` (npm), `yarn expo run:android` (yarn), `pnpm expo run:android` (pnpm), or `bun expo run:android` (bun) from the project root directory for Android. Use `run:ios` instead for iOS.

Third-party native library wrapping overview

Expo modules allow wrapping native external libraries built for Android and iOS. The workflow involves creating a module, adding native dependencies via build.gradle (Android) and .podspec (iOS), defining TypeScript types, implementing native views in Kotlin and Swift, and exposing them via Module definitions using the Prop function.

Create standalone Expo module

To create a new standalone Expo module that can be published on npm, run `npx create-expo-module <module-name>` (npm), `yarn create expo-module <module-name>` (yarn), `pnpm create expo-module <module-name>` (pnpm), or `bun create expo-module <module-name>` (bun). You can press Return for all prompts to accept default values.

Expo module web platform stub

For web platform in src/ExpoRadialChartView.web.tsx, create a default export component that returns a div or placeholder when the module is not implemented for web. This allows the module to be used in cross-platform projects.

iOS Prop definition in module

Define a prop in ExpoRadialChartModule.swift using Prop("propName") { (view: ViewClass, prop: PropType) in view.setPropMethod(prop: prop) } inside the View block. The prop handler receives the view instance and the new prop value.

iOS ExpoView with native library integration

On iOS, create a native view by extending ExpoView. Instantiate the native library component and add it as a subview. Set clipsToBounds to true and override layoutSubviews to keep the child view bounds synchronized with the parent. Define methods to update the view state when props change.

Expo Modules API Record type definition

Define Record types in Expo modules by creating a Kotlin class with @Field annotations (Android) or a Swift struct with @Field property wrappers (iOS). Both Android and iOS implementations of a Record must have matching field names and types.

iOS source files organization with frameworks

When using vendored frameworks on iOS, ensure the source_files option in the podspec does not match any files inside the framework. Move your iOS Swift source files into a separate src directory and update source_files to only match the src directory.

iOS framework dependency configuration

On iOS, you can use dependencies bundled as .xcframework or .framework by using the vendored_frameworks config option in the .podspec file. The file path pattern is relative to the podspec file and does not support traversing the parent directory (..), so frameworks must be placed inside the ios directory or a subdirectory of it.

.aar dependency integration for SDK 51 and earlier

To use a .aar dependency in Android module for SDK 51 and earlier, place the .aar file in an android/libs directory and add the directory as a flatDir repository in android/build.gradle. Add the dependency to the dependencies list using the package path with @aar at the end.

.aar dependency integration for SDK 52+

To use a .aar dependency in Android module for SDK 52 and later, place the .aar file in an android/libs directory. Create an expo-module.config.json that configures the .aar as a Gradle project through autolinking. Then add the dependency to android/build.gradle using the ${project.name}$ prefix.

Build and run new Expo module

For a new standalone Expo module, run `npm run build` (npm), `yarn run build` (yarn), `pnpm run build` (pnpm), or `bun run build` (bun) from the module directory in one terminal to watch for TypeScript changes and rebuild the module JavaScript. In another terminal, navigate to the example-expo-app directory and run `npx expo run:android` or `npx expo run:ios` to compile and run the example app.

Android ExpoView with native library integration

On Android, create a native view by extending ExpoView. Instantiate the native library component in the constructor, set its layout parameters to MATCH_PARENT for both width and height, and add it to the view hierarchy using addView(). Define methods to update the view state when props change.

Create local Expo module in existing project

To create a new module inside an existing Expo project, run `npx create-expo-module --local <module-name>` (npm), `yarn create expo-module --local <module-name>` (yarn), `pnpm create expo-module --local <module-name>` (pnpm), or `bun create expo-module --local <module-name>` (bun). This creates a new modules/<module-name> directory within the existing project.

Android shared object implementation with shared reference export

In Android, when exposing a shared object result to other modules that understand specific reference types, create a specialized SharedRef subclass. For example, class ImageRef : SharedRef<Bitmap>() creates a reference type that expo-image and other image-aware modules already understand. This allows the render method to return an ImageRef instead of the raw bitmap, enabling seamless integration with other Expo modules.

Android SharedObject lifecycle callback

In Android, the sharedObjectDidRelease() method is a lifecycle callback invoked when JavaScript releases all references to the shared object. This provides an opportunity to clean up native resources. For example, if a shared object manages a Bitmap, you would call current.recycle() in the sharedObjectDidRelease() method to free the bitmap's native memory when no references remain.

Performance benefits of shared objects

Shared objects provide several performance improvements: reduced disk I/O with a single read operation instead of multiple reads, fewer decode operations since expensive decoding like JPEG/PNG to bitmap happens once not repeatedly, lower memory pressure with one decode instance in memory instead of multiple copies, faster operations since in-memory transformations are significantly faster than disk-based ones, and avoiding frame drops because less I/O blocking means smoother UI interactions.

Shared objects definition and purpose

A shared object is a custom class that bridges a native instance from Android and/or iOS to JavaScript/TypeScript code through an Expo module. On the native side in Kotlin and Swift, you declare the class by inheriting from SharedObject and expose it in your module definition using Class(). A shared object is deallocated automatically once neither JavaScript nor native holds a reference. Shared objects let you expose long-lived native instances without giving control of their lifecycle, allowing you to keep heavy state objects such as a decoded bitmap alive across React components rather than spinning up a new native instance every time a component mounts.

iOS shared object implementation with shared reference export

In iOS, when exposing a shared object result to other modules that understand specific reference types, create a specialized SharedRef subclass. For example, final class ImageRef: SharedRef<UIImage> {} creates a reference type that expo-image and other image-aware modules already understand. This allows the render method to return an ImageRef instead of the raw UIImage, enabling seamless integration with other Expo modules.

Android Module definition for shared objects

In Android, expose a shared object through the module definition using a declarative syntax with ModuleDefinition. Use AsyncFunction or Function to create instances and return the SharedObject. Use Class<ClassName>("ClassName") block to bind methods to the shared object. Inside the Class block, use Function for synchronous methods and AsyncFunction with Coroutine modifier for asynchronous methods. Example: AsyncFunction("createContextAsync") creates an instance, and Function("rotate") { ctx: ClassName, arg -> ctx.rotate(arg) } binds instance methods.

Give your agent this brain