Descripción general de expo-brownfield
Manual para envío de módulos Expo dentro de shells iOS/Android existentes - desde la instalación de expo-brownfield hasta la publicación de artefactos e integración con la aplicación host.
Busca en todas las páginas de la documentación
Manual para envío de módulos Expo dentro de shells iOS/Android existentes - desde la instalación de expo-brownfield hasta la publicación de artefactos e integración con la aplicación host.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
# 1. Crea módulo RN (repositorio separado o paquete monorepo)
npx create-expo-app@latest CheckoutModule --template default@sdk-57
cd CheckoutModule
npx expo install expo-brownfield// app.config.ts - plugin + módulos precompilados opcionales de iOS
{
"expo": {
"scheme": "checkout",
"plugins": [
["expo-build-properties", { "ios": { "usePrecompiledModules": true } }],
[
"expo-brownfield",
{
"ios": { "targetName": "CheckoutBrownfield" },
"android": {
"group": "com.example",
"libraryName": "checkout-brownfield",
"package": "com.example.checkout.brownfield",
"version": "1.0.0"
}
}
]
]
}
}# 2. Genera objetivos de brownfield nativos (depura código nativo, codegen de CI)
npx expo prebuild
# 3. Construye artefactos
npx expo-brownfield build:android --release
npx expo-brownfield build:ios --release --package CheckoutPackage
# 4. Dev loop - Metro + host debug build
npx expo start
# Lanza la aplicación host desde Xcode / Android Studio - la pantalla RN carga desde Metro// Host de Android - dependencia build.gradle.kts (versión del config del plugin)
dependencies {
implementation("com.example:checkout-brownfield:1.0.0")
}// Host de iOS - AppDelegate + presenta RN
import CheckoutBrownfield
ReactNativeHostManager.shared.initialize()
let vc = ReactNativeViewController(moduleName: "main", initialProps: ["cartId": id])
navigationController?.pushViewController(vc, animated: true)Cuándo usarlo:
BrownfieldMessaging) entre host y RN sin escribir un TurboModule personalizado el primer día.El proyecto RN no tiene que vivir dentro del repositorio nativo. Un monorepo packages/checkout-rn/ o un repositorio Git separado funcionan ambos.
npx create-expo-app@latest CheckoutModule --template default@sdk-57
cd CheckoutModule
npx expo install expo-brownfieldConfirma el pin del SDK:
{
"dependencies": {
"expo": "~57.0.4",
"expo-brownfield": "~57.0.3",
"react": "19.2.3",
"react-native": "0.86.0"
}
}Estructura las pantallas con rutas delgadas y características grasas según Mobile Architecture Basics.
expo-brownfield añade un plugin de configuración que genera:
BrownfieldActivity, ReactNativeFragment, ReactNativeHostManager, BrownfieldMessagingReactNativeViewController, ReactNativeView (SwiftUI), ReactNativeHostManager, BrownfieldMessaging// app.config.ts
import type { ExpoConfig } from "expo/config";
const config: ExpoConfig = {
name: "Checkout Module",
slug: "checkout-module",
scheme: "checkout",
plugins: [
[
"expo-brownfield",
{
ios: {
targetName: "CheckoutBrownfield",
bundleIdentifier: "com.example.checkout.brownfield",
},
android: {
group: "com.example",
libraryName: "checkout-brownfield",
package: "com.example.checkout.brownfield",
version: "1.0.0",
publishing: [{ type: "localMaven" }],
},
},
],
],
};
export default config;Ejecuta prebuild para materializar los objetivos:
npx expo prebuildVer Config Plugins para patrones de plugin idempotentes al combinar expo-brownfield con otros modificadores nativos.
npx expo-brownfield build:android --releaseEl objetivo de publicación predeterminado es Maven local (~/.m2). El host build.gradle.kts necesita:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
mavenLocal()
}
}
dependencies {
implementation("com.example:checkout-brownfield:1.0.0")
}Presenta RN desde el host:
import com.example.checkout.brownfield.BrownfieldActivity
import com.example.checkout.brownfield.showReactNativeFragment
class CheckoutActivity : BrownfieldActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showReactNativeFragment()
}
}La entrada AndroidManifest.xml necesita un tema NoActionBar y configChanges para teclado/orientación - los documentos de BrownfieldActivity generados enumeran el conjunto completo de atributos.
# XCFrameworks en ./artifacts/
npx expo-brownfield build:ios --release
# Swift Package independiente (recomendado para la integración de Xcode host)
npx expo-brownfield build:ios --release --package CheckoutPackageRuta de Swift Package: En Xcode - Agregar dependencias de paquetes - Agregar local - selecciona artifacts/CheckoutPackage-release/. Xcode vincula archivos .xcframework incluidos (brownfield, Hermes, React, dependencias).
Ruta de XCFramework: Arrastra {TargetName}.xcframework y hermesvm.xcframework al proyecto host; establece Embed & Sign.
Inicializa temprano:
import CheckoutBrownfield
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
ReactNativeHostManager.shared.initialize()
return true
}
}Presentación de SwiftUI:
import SwiftUI
import CheckoutBrownfield
struct CheckoutButton: View {
@State private var showCheckout = false
var body: some View {
Button("Checkout") { showCheckout = true }
.fullScreenCover(isPresented: $showCheckout) {
ReactNativeView(moduleName: "main", initialProps: ["cartId": cartId])
}
}
}Construye paquetes de depuración y release por separado - los objetivos binarios de SPM son específicos del sabor.
// Módulo RN - envía eventos a nativo
import * as Brownfield from "expo-brownfield";
export function completeCheckout(orderId: string) {
Brownfield.sendMessage({ type: "CHECKOUT_COMPLETE", orderId });
Brownfield.popToNative(true);
}// Android - recibe de RN
BrownfieldMessaging.addListener { event ->
if (event["type"] == "CHECKOUT_COMPLETE") {
// Actualiza lista de órdenes nativa, extrae fragmento RN
}
}Habilita el retroceso de hardware para regresar a nativo cuando sea apropiado:
Brownfield.setNativeBackEnabled(true);Patrones de sesión completa: Shared Authentication & Bridges.
Cuando dos módulos brownfield de Expo coexisten en una aplicación iOS:
{
"plugins": [
[
"expo-brownfield",
{
"ios": {
"targetName": "CheckoutBrownfield",
"multipleFrameworks": true
}
}
]
]
}Esto prefija símbolos de ObjC para evitar errores de vinculador duplicados. Trátalo como avanzado - prefiere un módulo RN con múltiples rutas hasta que los límites fuercen una división.
acme-mobile/
├── apps/
│ ├── host-ios/ # Xcode - consume Swift Package
│ └── host-android/ # Gradle - consume Maven AAR
├── packages/
│ └── checkout-rn/ # Proyecto Expo con expo-brownfield
│ ├── app/
│ ├── app.config.ts
│ └── package.json
└── package.json # raíz del espacio de trabajoBoceto de CI:
# packages/checkout-rn - publica artefactos en tag
- run: npx expo-brownfield build:android --release
- run: npx expo-brownfield build:ios --release --package CheckoutPackage
- run: aws s3 sync ./artifacts s3://ci-artifacts/checkout-rn/${{ github.sha }}/Los pipelines del host descargan versiones de artefactos fijadas - sin npm install en corredores nativos. Detalles: Brownfield CI/CD.
| Herramienta Expo | Host aislado de Brownfield |
|---|---|
| Módulos de Expo SDK | ✓ |
| Expo Router | ✓ (dentro del módulo RN) |
expo start / Metro | ✓ (depuración) |
| EAS Build (proyecto RN) | ✓ |
| EAS Update | ✓ (con disciplina de versión en tiempo de ejecución) |
| Expo Go | ✗ |
| Expo Dev Client en host | ✗ (usa builds de depuración + Metro) |
El soporte de Brownfield es alfa - fija expo-brownfield a la misma línea del SDK que expo y lee las notas de lanzamiento en cada actualización.
Aislado cuando la CI nativa debe permanecer libre de Node. Integrado cuando un equipo edita nativo y RN en un repositorio diariamente. Ver Brownfield Basics.
Objetivos de biblioteca de Brownfield junto a (no reemplazando) los objetivos de la aplicación - úsalos para depurar el pegamento nativo y ejecutar comandos de CLI build:*.
Aumenta android.version / etiqueta de paquete de iOS, ejecuta build:android / build:ios, publica artefactos, actualiza las coordenadas de dependencia del host - igual que cualquier biblioteca nativa.
Sí - las rutas viven completamente dentro del paquete RN. Nativo abre moduleName: "main"; Router maneja rutas internas.
useSharedState y mensajeríaexpo-brownfieldVersiones de stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 16 jul 2026