This is documentation for the next SDK version. For up-to-date documentation, see the latest version (SDK 54).

Expo Brownfield

Toolkit and APIs for integrating Expo into existing native applications.

Android
iOS

expo-brownfield is a toolkit for adding React Native views to existing native Android and iOS applications. It provides:

  • Built-in APIs for bi-directional communication and navigation between native and React Native apps
  • Config plugin for automatic setup of brownfield targets in your Expo project
  • CLI for building and publishing artifacts to Maven repositories (Android) and XCFrameworks (iOS)

Installation

Terminal
npx expo install expo-brownfield

If you are installing this in an existing React Native app, make sure to install expo in your project.

Usage

Communication API

The Communication API enables bi-directional, message-based communication between the native (host) app and React Native.

Sending messages from React Native to native

import * as Brownfield from 'expo-brownfield'; Brownfield.sendMessage({ type: 'MyMessage', data: { language: 'TypeScript', expo: true, platforms: ['android', 'ios'], }, });

Receiving messages from native in React Native

import * as Brownfield, { type MessageEvent } from 'expo-brownfield'; import { useEffect } from 'react'; function MyComponent() { useEffect(() => { const handleMessage = (event: MessageEvent) => { console.log('Received message:', event); }; Brownfield.addMessageListener(handleMessage); return () => { Brownfield.removeMessageListener(handleMessage); }; }, []); // ... }

Sending messages from native to React Native

import expo.modules.brownfield.BrownfieldMessaging BrownfieldMessaging.sendMessage(mapOf( "type" to "MyAndroidMessage", "timestamp" to System.currentTimeMillis(), "data" to mapOf( "platform" to "android" ) ))
import ExpoBrownfield BrownfieldMessaging.sendMessage([ "type": "MyIOSMessage", "timestamp": Date().timeIntervalSince1970, "data": [ "platform": "ios" ] ])

Receiving messages from React Native in native

import expo.modules.brownfield.BrownfieldMessaging val listenerId = BrownfieldMessaging.addListener { event -> println("Message from React Native: $event") } // Later, to remove the listener: BrownfieldMessaging.removeListener(listenerId)
import ExpoBrownfield let listenerId = BrownfieldMessaging.addListener { message in print("Message from React Native: \(message)") } // Later, to remove the listener: BrownfieldMessaging.removeListener(id: listenerId)

Configuration in app config

The expo-brownfield package provides a config plugin that can be used to configure the brownfield integration when using Continuous Native Generation (CNG). This plugin allows you to customize how your Expo project is packaged and integrated into your existing native app.

Example app.json with config plugin

app.json
{ "expo": { "plugins": [ [ "expo-brownfield", { "ios": { "targetName": "MyBrownfieldTarget", "bundleIdentifier": "com.example.brownfield" }, "android": { "group": "com.example", "libraryName": "brownfield", "package": "com.example.brownfield", "version": "1.0.0" } } ] ] } }

Configurable properties

NameDefaultDescription
ios.targetName"<scheme>brownfield" or "<slug>brownfield"
Only for:
iOS

Name of the Xcode target for the brownfield integration. This is used to create a separate target in your Xcode project for the React Native code.

ios.bundleIdentifier"<ios.bundleIdentifier base>.<targetName>" or "com.example.<targetName>"
Only for:
iOS

Bundle identifier for the brownfield target. This should be unique and different from your main app bundle identifier.

android.group"<package without last segment>"
Only for:
Android

Maven group ID for the generated Android library. This is used when publishing the library to a Maven repository.

android.libraryName"brownfield"
Only for:
Android

Name of the generated Android library module.

android.package"<android.package>.brownfield" or "com.example.brownfield"
Only for:
Android

Java/Kotlin package name for the generated Android library code.

android.version"1.0.0"
Only for:
Android

Version string for the generated Android library. This is used when publishing to a Maven repository.

android.publishing[{ type: "localMaven" }]
Only for:
Android

Publishing configuration for the generated Android library. Supports localMaven, localDirectory, remotePublic, and remotePrivate publication types. Each type has different configuration options for specifying where and how the library is published.

CLI

The expo-brownfield library includes a CLI for building and publishing to Maven repositories (Android) and XCFrameworks (iOS).

Terminal
npx expo-brownfield [command] [options]

Commands

build:android

Builds and publishes the brownfield library and its dependencies to Maven repositories.

Terminal
npx expo-brownfield build:android [options]
OptionDescription
-d, --debugBuild in debug mode
-r, --releaseBuild in release mode
-a, --allBuild in both debug and release mode (default)
-l, --librarySpecify brownfield library name
--repo, --repositorySpecify Maven repositories to publish to
-t, --taskSpecify Gradle publish tasks to run
--verboseInclude all logs from subprocesses

build:ios

Builds the brownfield XCFramework and copies the Hermes XCFramework to the artifacts directory.

Terminal
npx expo-brownfield build:ios [options]
OptionDescription
-d, --debugBuild in debug mode
-r, --releaseBuild in release mode (default)
-a, --artifactsPath to the artifacts directory (default: ./artifacts)
-s, --schemeXcode scheme to build
-x, --xcworkspaceXcode workspace path
--verboseInclude all logs from subprocesses

tasks:android

Lists all available publish tasks and Maven repositories.

Terminal
npx expo-brownfield tasks:android

API

import * as Brownfield from 'expo-brownfield';

No API data file found, sorry!