Skip to main content

Brownfield 团队协作机制

Date: 2026-07-09
Status: 生效
相关: SOP 操作手册平台设计方法、项目根目录 README.md(团队开发)、Remote 双路径架构

背景

本项目采用 Brownfield + Split Bundle + OTA:原生壳(ios_native)嵌入 RN 运行时(BrownfieldLib),业务 JS 在 rn_app/ 中开发。

同事不应:

  • 使用 npx react-native init 或自建 RN 工程
  • 自行搭建 Xcode / CocoaPods / Brownfield 打包链路
  • 在业务 PR 中私自 pod install 或升级含 native 代码的 npm 包

平台(壳维护者)提供:

  • 版本化的 Debug / Release 壳
  • 约定好的 rn_app 目录结构与开发 SOP
  • 已接入的原生能力清单(Capability Catalog)
  • 新 Remote 入口脚手架流程(见 SOP-E

核心原则:

同事 ≠ 新建 RN 项目
同事 = 在平台提供的 RN 应用脚手架里写 JS,跑在平台发布的壳上

角色与目录边界

平台区 vs 业务区

角色拥有目录日常动作
壳维护者ios_native/rn_app/ios/rn_app/ios/BrownfieldLib/src/specs/(Codegen)发 Shell、审 native 依赖、实现 TurboModule
核心 RN 开发者screens/(Scheme 1)、src/ 通用逻辑npm start + 共享 Debug 壳
Remote 业务开发者screens/remote/bundles/ota_<id>/Metro 日常开发 + OTA 发版
服务端维护者bundle-server/manifest、upload、回滚

操作细节见 SOP §1 角色分工SOP-F 壳维护与分发

禁止事项(全员)

禁止原因
npx react-native init 新建工程与 Brownfield 运行时、module id、OTA split 不兼容
Podfile / rn_app/ios 不经壳维护者破坏团队共享 Debug 壳一致性
ios_native 不经壳维护者导航、权限、壳 UI 由平台统一维护
主 bundle runtime import bundles/ota_*破坏 Metro / OTA 双路径隔离
只改 bundles/ota_*/ 却等 Metro HMROTA 目录不参与 Metro 图

平台交付物(脚手架)

同事拿到的不是 RN CLI,而是以下 三类交付物

1. 开发壳(Debug Shell Artifact)

壳维护者构建并分发模拟器 App:

chmod +x scripts/build-debug-shell.sh
./scripts/build-debug-shell.sh
# 产物:dist/ios_native-debug-simulator.app

建议(待实施): 壳版本化命名与 manifest,便于团队对齐:

shell-ios-debug-1.2.0-simulator.app
shell-ios-debug-1.2.0-manifest.json # RN 版本、pod 清单、构建时间、最低 Xcode

2. 同事 onboarding(四步)

# 1. 克隆 monorepo
git clone <repo-url> && cd native-app-multi-rn-bundle

# 2. 安装 RN 依赖并启动 Metro
cd rn_app && npm install && npm start

# 3. 安装壳维护者分发的 Debug 壳(模拟器已启动)
xcrun simctl install booted /path/to/ios_native-debug-simulator.app

# 4. 模拟器桌面打开 ios_native → 自动连本机 Metro

同事 不需要:Xcode、pod installbrownfield:package:ios

3. JS 应用脚手架(仓库内约定)

Remote 新入口按 SOP-E 手工创建;建议(待实施) 提供 CLI:

npm run scaffold:remote -- --id billing --title "账单"

自动生成:screens/remote/billing/bundles/ota_billing/、segment 配置、构建列表占位、seed 占位。

日常 UI 开发默认只改 screens/remote/;OTA 包装页仅在 badge/文案差异时改 bundles/ota_*/screens/。见工程仓 rn_app/screens/remote/README.mdrn_app/bundles/README.md


依赖分层

┌─────────────────────────┐
│ L3 原生依赖(Pod / SPM) │ ← 仅壳维护者
└───────────┬─────────────┘

┌───────────▼─────────────┐
│ L2 JS + Native 库 │ ← 壳维护者评估后纳入壳
│ (reanimated, camera…) │
└───────────┬─────────────┘

┌───────────▼─────────────┐
│ L1 纯 JS 依赖 │ ← 业务开发者 npm install
│ (lodash, zustand…) │
└─────────────────────────┘
层级谁可添加流程是否重发壳
L1 纯 JS业务开发者PR 改 package.json,CI 跑 test
L2 含 native 的 npm壳维护者Capability Request → pod + 发新 Shell
L3 壳 / TurboModule壳维护者设计评审 / OpenSpec → 原生实现

判断标准:

npm install xxx 后是否需要改 Podfile、原生注册、或 Info.plist 权限?
是 → L2/L3,找壳维护者。否 → L1,业务 PR 即可。

常见 L2 示例:react-native-reanimatedreact-native-vision-camera、地图/扫码/推送等。


Capability Catalog(能力清单)

业务代码 只能使用下表已提供的能力;未列出的 native 能力须提 Capability Request。

CapabilityJS / API引入版本说明
Brownfield 嵌入ReactNativeBrownfield初始Debug 连 Metro,Release 内嵌 bundle
Scheme 1 本地页AppRegistry + moduleName初始Home / Profile / Settings
Remote FeatureHostuseFeatureHost / manifest初始远程业务容器
OTA Split 加载SplitBundleLoader.load(path, segmentId)初始segment 0 = shared,1+ = feature
OTA 公共 splitensureSharedBundleCachedshared split先 load shared 再 load feature
回原生菜单NativeShellNavigation.popToNative()初始Remote 根页「菜单」
React Navigation@react-navigation/*shared splitota_shared 中,非主 bundle
Gesture Handler / Screens已 linkshared split导航依赖
相机 / 蓝牙 / 自定义原生模块未提供需 Capability Request

壳维护者扩能力后 必须更新本表 与 Shell CHANGELOG。


Capability Request 流程

何时提交

  • 需要 L2/L3 依赖或新 TurboModule
  • 需要新系统权限(相机、定位、推送等)
  • 需要改壳 UI、导航结构、Brownfield 配置

提交方式

在 issue 跟踪系统创建 Capability Request(GitHub Issue / 飞书工单等),使用下方模板。

处理分级(壳维护者 SLA 参考)

级别示例壳维护者动作
P0 已有能力使用 Navigation、popToNative指向文档,无需改壳
P1 纯 JSaxios、dayjs、zustand批准 package.json PR
P2 新 native 库地图、扫码、相册pod + 权限 + 发 Shell vX.Y+1
P3 新 TurboModule自定义桥、原生 SDK 封装OpenSpec + 原生开发 + 发 Shell

每次发壳必带

  • Shell 版本号(建议 semver)
  • CHANGELOG:新增/升级/移除的 native 依赖
  • 兼容矩阵Shell x.y.zrn_app 最低 git tag / commit

Issue 模板(复制使用)

## Capability Request

### 业务场景
(为什么要这个能力?)

### 候选方案
- 库名 / SDK:
- npm 链接(如有):
- 是否纯 JS(你认为):是 / 否 / 不确定

### 使用范围
- [ ] 仅 Remote OTA split
- [ ] Scheme 1 主 bundle
- [ ] 两者都要

### 平台
- [ ] iOS(优先)
- [ ] Android(后续)

### 期望时间
(可选)

### 验收标准
(可选)

何时重发壳

SOP-F §8.1 一致:

变更重发壳发版通道
只改 JS/TS(screens/remote/src/Metro HMR / OTA upload
Remote UI 发版build:bundles + upload
新增/升级 native npm 依赖新 Shell + App
ios_native 原生代码新 Shell
SplitBundleLoader 等 TurboModule新 Shell
升级 RN 大版本 / Brownfield 大版本新 Shell + 全量回归
改 Scheme 1 核心页(随主 bundle)⚠️需发 App(非 OTA)

技术护栏

文档约定需配合工具 enforce,避免误操作。

护栏作用状态
目录 README标明改哪、哪条路径生效
npm run verify:ota-scope主 bundle 图不含 bundles/ota_*
npm run verify:native-deps生产依赖树中 native 包须在 allowlist
ESLint / Metro blockList禁止错误 import 方向部分
CODEOWNERS平台目录必须壳维护者 approve待实施
CI 分支保护业务 PR 不可单独改平台区待实施
Shell 版本 manifest壳过旧时 App 内提示升级待实施
npm run scaffold:remote新 Remote 入口一键脚手架待实施

Native 依赖检测(verify:native-deps

扫描 dependencies 生产依赖树(含传递依赖),用启发式识别 含 native 代码的 npm 包(podspec、codegenConfigandroid/ 等)。未列入 allowlist 的 native 包 → CI / PR 失败

命令用途
npm run verify:native-depsPR / CI 门禁(失败则打印 Capability Request 指引)
npm run verify:native-deps:audit列出当前树中全部 native 包及 allow 状态
node scripts/verify-native-deps.js --explain <pkg>调试单个包为何被判为 native

Allowlist 文件: rn_app/config/approved-native-deps.json

  • platformPackages — 平台内置(reactreact-native
  • approvedNativePackages — 壳维护者已接入的 L2 native 库

壳维护者新增 native 依赖时:同一 PR 内更新 allowlist + pod + 发 Shell。

业务开发者新增纯 JS 依赖(如 zustand):无需改 allowlist,verify:native-deps 自动放行。

组合校验: npm run verify = verify:ota-scope + verify:native-deps

CODEOWNERS 示例(待提交)

/ios_native/ @shell-maintainer
/rn_app/ios/ @shell-maintainer
/rn_app/ios/BrownfieldLib/ @shell-maintainer
/rn_app/src/specs/ @shell-maintainer
/rn_app/screens/remote/ @remote-team
/rn_app/bundles/ @remote-team
/bundle-server/ @server-maintainer

@shell-maintainer 等替换为实际 GitHub 团队或用户名。


Remote 双路径(协作默认规则)

对新同事一句话:

Remote UI 默认只改 screens/remote/;发版跑 build:bundles + upload;不要新建 RN 项目;不要自己 pod。

路径改哪里如何验证
Metro 日常screens/remote/components/npm start + Debug 壳
OTA 发版同上 + 必要时 bundles/ota_*/screens/build:bundles + upload + OTA 模式

详见 dynamic-multi-bundle.md — Remote 双路径


实施优先级

优先级动作成本
P0本文档 + Capability 模板 + 能力清单维护
P0Shell 版本化分发 + 「何时重发壳」宣贯
P1CODEOWNERS + 平台目录 CI 保护
P1PR 跑 npm run verify(含 native-deps)
P1npm run scaffold:remote
P2native 依赖 allowlist CI
P2Shell manifest + App 内版本校验
P3拆 repo(业务仓 + shell 制品仓)高,团队扩大后再做

参考