# Design — 新老架构双兼容

> 来源：2026-06-15 多轮 explore + 2026-06-17 代码实读校正。Android 对照 `AppLovin-MAX-React-Native/android/`；iOS 视图双架构以同库 `ios/` 为准（[`docs/iOS-双架构方案对比.md`](../../../docs/iOS-双架构方案对比.md)）。
>
> **上线门禁**：Android + iOS 双端完成 0.72.x↔0.85 兼容方可发版。索引：[`docs/OLD-ARCH-COMPAT-上线必读.md`](../../../docs/OLD-ARCH-COMPAT-上线必读.md)。

## 1. 核心策略

把"架构绑定的薄壳"和"真实业务逻辑"分离。业务逻辑只写一遍（共享），新旧架构各一份薄壳（父类 / 方法暴露方式不同），构建时按 `newArchEnabled` 只编译其一。

```
android/src/
  main/    共享：业务逻辑(各 Manager/Helper 单例)、共享视图类、*Impl 静态方法、
           ATReactNativePackage(运行时 BuildConfig 分流)
  newarch/ 仅新架构编译：extends Spec / implements codegen Interface
  oldarch/ 仅旧架构编译：extends ReactContextBaseJavaModule + @ReactMethod /
           @ReactProp + 手写 receiveCommand
```

JS 层（`src/`）完全不动 —— 见 §6 的 fallback 链。

## 2. 构建配置（总闸）

### 2.1 android/build.gradle（现 63 行，纯新架构，需加双架构逻辑）

对照参考库 `AppLovin-MAX-React-Native/android/build.gradle`：
- 加 `def isNewArchitectureEnabled() { return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" }`
- **关键修复**：现第 28 行 `apply plugin: "com.facebook.react"` 是**无条件**的 → 旧架构下会误跑 codegen。改为 `if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" }`。
- `sourceSets { main { java.srcDirs += isNewArch ? ['src/newarch'] : ['src/oldarch'] } }`
- `defaultConfig { buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) }`

### 2.2 ATReactNativeBridge.podspec（iOS 总闸，与 Android gradle 同级阻塞上线）

对照参考库 `react-native-applovin-max.podspec`：
- **关键修复**：现第 19 行 `install_modules_dependencies(s)` 无条件 → 用 `if respond_to?(:install_modules_dependencies, true)` 包裹，`else s.dependency "React-Core"`。
- 加 `if ENV['RCT_NEW_ARCH_ENABLED'] == '1'` 分支：folly 编译标志、`s.compiler_flags += " -DRCT_NEW_ARCH_ENABLED=1"`、`pod_target_xcconfig`（boost / C++17）、依赖 `React-RCTFabric`/`React-Codegen`/`RCT-Folly`/`RCTRequired`。

## 3. Android — Module（92 桥方法）

现状：`ATReactNativeBridgeModule extends NativeATBridgeSpec`，注释明确"仅做转发"，每方法是 `XxxManager.getInstance().sameMethod(args)` 一行。这天然符合"薄壳转发 + 业务下沉"的分离哲学。

```
                 newarch (现有平移)            oldarch (AI 逐方法翻译)
─────────────────────────────────────────────────────────────────
类头        extends NativeATBridgeSpec    extends ReactContextBaseJavaModule
方法注解    @Override                     @ReactMethod
方法体      转发 Manager 单例             完全相同（转发同一 Manager）
getName()   Spec 自带                     需手写 return NAME
```

**生成 oldarch 壳 = AI 逐方法语义翻译（不用脆弱正则脚本）**：AI 读 newarch 原文，逐个方法译成 oldarch（换类头/@Override→@ReactMethod/补 getName/同步标记），方法体与原文一字不差；再用 `verify:arch-parity`（机器对账 TS 真相源）兜底查漏。理由：正则转换遇跨行/泛型/注解顺序会漏转且不报错（壳照编译过、方法运行时静默失效）；AI 懂语义 + 机器查漏才可靠。
- ⚠️ **同步返回方法**（非 void 非 Promise，确切 3 个：`getSDKVersionName():String`、`autoLoadRewardedVideoReady():boolean`、`autoLoadInterstitialReady():boolean`）：旧架构必须标 `@ReactMethod(isBlockingSynchronousMethod = true)`，否则注册失败。verify 脚本会校验这 3 个标记。

**Package**（共享 `main/`）：对齐参考库 `AppLovinMAXPackage` — **`extends TurboReactPackage`**（0.72 可用；现 `BaseReactPackage` 仅 0.76+）；`getReactModuleInfoProvider` 里 `boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED`（**禁止硬编码 true**）。若 `ReactModuleInfo` 构造在 0.72 与 0.85 不兼容 → Package 也分 newarch/oldarch 两份。

## 4. Android — 2 个 Fabric ViewManager

`receiveCommand(T root, String commandId, ReadableArray args)` 这个 **String 版签名新旧架构通用**（0.76.2 `ViewManager.java`：第 295 行 int 废弃版、第 306 行 String 版并存）。

```
                  newarch                        oldarch
─────────────────────────────────────────────────────────────────
props           implements ...Interface       @ReactProp(name="placementID"...)
                (@Override)                    方法体不变
command 分发    Delegate 自动按字符串路由       手写 receiveCommand:
                                                switch(commandId) {
                                                  case "updateAssetView":
                                                    impl(view, args.getInt(0),
                                                              args.getString(1));
                                                  case "renderNativeAd": impl(view);
                                                }
```

**建议抽 `*ManagerImpl` 静态方法**：把命令分发 + 参数解包 + 业务放共享 `main/`，新旧壳都转发 `Impl.receiveCommand(view, commandId, args)`，命令逻辑零分叉。

**自渲染 react tag 绑定（参考库模型）新旧通用**：参考库自渲染视图用相同机制（`updateAssetView` + `renderNativeAd` + `findViewById`/uiManager），oldarch/newarch 共用 Impl → 我们 Android 侧对齐此模型。

## 5. Android — EventEmitter（零改动）

`ATReactNativeEventEmitter.java` 用 `ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(callName, payload)` —— 与参考库一致，`RCTDeviceEventEmitter.emit` 新旧架构通用。**不改**。
- 注：之前查到的 `splashDidShowSuccess` JS 侧双回调（原生 emit 1 次 / JS dispatch 2 次）与架构无关，旧架构下行为相同，属独立待查项（见 [[rn-sdk-callbackname-landmines]]）。

## 6. JS 零改动的依据（fallback 链 — 0.76.2 源码实证）

```
TurboModule:  TurboModuleRegistry.getEnforcing → requireModule
              → turboModuleProxy(name)            (新架构)
              → 否则 if useLegacyNativeModuleInterop: NativeModules[name]  (旧架构)
Fabric 组件:  codegenNativeComponent → requireNativeComponent  (旧架构)
Fabric 命令:  codegenNativeCommands → UIManager.dispatchViewManagerCommand (旧架构)
```
均在 0.76.2 源码确认。0.72.5 待验证点 #1/#3 最终确认（0.72.5 非 Bridgeless，`requireNativeComponent` 可用；偏旧架构，fallback 只会更直接）。

## 7. 三个 0.72.5 验证点

| # | 验证什么 | 怎么验 | 成本 | 坏了的后果 |
|---|---|---|---|---|
| 1 | TurboModuleRegistry 旧架构 fallback | 读 0.72.5 `node_modules/react-native/Libraries/TurboModule/TurboModuleRegistry.js`，看 `requireModule` 是否有 `NativeModules[name]` 分支 | 5 分钟 | 中：`NativeATBridge.ts` 加一处架构分支改 `NativeModules.ATReactNativeBridge` 直取 |
| 2 | 自渲染 react tag 绑定跨架构 | 0.72.5 真机 load 自渲染 native 广告，看 `findViewById(assetViewTag)` 命中（标题/图显示 + 可点） | 需真机 + oldarch 就绪 | 高（参考库 Android 已实证，概率较高） |
| 3 | codegenNativeComponent fallback | 读 0.72.5 `Libraries/Utilities/codegenNativeComponent.js`，确认旧架构走 `requireNativeComponent`（注意 Bridgeless 注释，0.72.5 非 Bridgeless） | 5 分钟 | 高（视图渲染不了；0.72.5 非 Bridgeless 概率低） |

#1/#3 现在就能做（拿到 0.72.5 `node_modules` 即可，或 `npx react-native@0.72.5 init` 空壳）。

## 8. iOS 双架构设计方案

> **权威文档**：[`docs/iOS-双架构方案对比.md`](../../../docs/iOS-双架构方案对比.md)（2026-06-17 校正，对照参考库 `AppLovin-MAX-React-Native/ios/` 实读）。本节为摘要。

### 8.1 真实现状（2026-06-18 实测，iOS 双架构约 70% 完成）

- **Bridge ❌未做**：`.h` 协议无 `#ifdef`（无条件 `<NativeATBridgeSpec>`）；`.mm` 0 个 `RCT_EXPORT_METHOD`/`RCT_EXPORT_MODULE`；`getTurboModule` 未包 `#ifdef`。→ **iOS 唯一剩余阻塞**（旧架构编不过、桥全废）。
- **视图 ✅已做**：`ATRNBannerView`/`ATRNNativeAdView` 已 `#ifdef` 切基类（`RCTViewComponentView`\|`UIView`），Fabric 块已包 `#ifdef`。
- **ViewManager ✅已做**：`ATBannerViewManager`（5 props）/`ATNativeAdViewManager`（6 props+2 命令）均已建为 `RCTViewManager`。
- **事件 ✅已做**：`ATReactNativeEventEmitter` 双通路 + 主线程守护，正确，可保留。
- **podspec ✅已做**：已 `if respond_to?` + `RCT_NEW_ARCH_ENABLED` 分支，对齐 MAX。

### 8.2 推荐路线：参考库范式（非「删 Fabric」）

参考库视图双架构 = **ViewManager 始终存在** + 视图基类 `#ifdef`（`RCTViewComponentView` / `UIView`）+ 新架构 **保留** Fabric `updateProps`/`handleCommand`。

```
JS codegen component
       ▼
RCTViewManager（新旧都有：MODULE + VIEW_PROPERTY + EXPORT_METHOD 命令）
       ▼
#ifdef 视图基类：ComponentView（新）| UIView（旧）
       ▼
共享 *UIComponent 业务（ATBannerUIComponent / ATNativeUIComponent）
```

**不要**采用旧文档「删 Fabric、纯 UIView、无 `#ifdef`」——与参考库不符，且会丢掉已跑通的 0.85 Fabric 实现。

### 8.3 Bridge 薄壳

| 必做 | 说明 |
|---|---|
| `.h` `#ifdef` | `<NativeATBridgeSpec>` / `<RCTBridgeModule>` |
| 92× `RCT_EXPORT_METHOD` | 含 3 同步 + `addListener`/`removeListeners` |
| `RCT_EXPORT_MODULE` | 旧架构模块注册 |
| `getTurboModule` `#ifdef` | 仅新架构 |
| `registerComponentViewClass` `#ifdef` | RN 0.85 特供，旧架构不需要 |

**事件基类**：保持 `NSObject` + 现有 EventEmitter（方案甲）**或** 对齐参考库改 `RCTEventEmitter`（方案乙）——**二选一，非阻塞**。

### 8.4 剩余改造清单（实测后，仅剩 Bridge 一块）

视图 / ViewManager / podspec / 事件均已做（见 §8.1）。**iOS 上线只差 Bridge**：
1. `ATReactNativeBridge.h`：协议加 `#ifdef`（`<NativeATBridgeSpec>` / `<RCTBridgeModule>`）。
2. `ATReactNativeBridge.mm`：92 方法各加 `RCT_EXPORT_METHOD`（3 同步用 `RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD`）+ `RCT_EXPORT_MODULE()`；`getTurboModule` 包 `#ifdef`。
3. 真机验证（0.72.x 旧架构 + 0.85 新架构回归）。
> ✅ 第 2 步的 92 方法完整签名表已生成：[`docs/iOS-Bridge-92方法签名表.md`](../../../docs/iOS-Bridge-92方法签名表.md)（逐行给好宏写法 + 类型映射，照抄即可，无需逐个查 TS+.mm）。

### 8.5 自渲染

Native ViewManager 已暴露 `updateAssetView`/`renderNativeAd` 的 `RCT_EXPORT_METHOD`（旧架构命令通路就位）。iOS 自渲染**视觉**仍用 SDK 内置布局、不读 JS AssetView，是**既有双端差异、非双架构阻塞**；与 Android 视觉对齐另排期。

### 8.6 历史说明

2026-06-15 版 design §8.1–8.6（「90→102」「必改 RCTEventEmitter」「删 Fabric 路线 A」）已作废，勿据此实施。


## 9. 用户配置与 peer 依赖（兼容后）

```
              新架构(0.76~0.85)          旧架构(0.72.x)
─────────────────────────────────────────────────────────
npm peerDep   `"*"`（对齐 MAX）              同左；实测 0.72.x↔0.85
Android       newArchEnabled=true        newArchEnabled=false
iOS           RCT_NEW_ARCH_ENABLED=1     0 或未设
JS 代码       完全相同
```

交付时 **`package.json`**：`peerDependencies` 对齐 MAX（`react` / `react-native` 均为 `"*"`）；**实际支持 RN 0.72.x↔0.85** 写在发布说明，由双架构原生实现保证。

## 10. 工作量与排序（双端上线，赶工并行）

```
轨道          内容                              工作量    备注
──────────────────────────────────────────────────────────────
A Android     Phase 0→6（gradle/Impl/oldarch）   ~1.5周    TurboReactPackage 必做
B iOS         Bridge + ViewManager + podspec     ~1~1.5周  与 A 并行，同版发布
C 门禁        0.72.5 客户双端 + 0.85 回归        ~3天      阻塞发版
D 收口        peerDep + 文档 + verify:arch-parity      0.5天     Phase 9
独立后续      iOS 自渲染对齐 / nativeAdOnResume    另计      不进门禁
```

**禁止**：「Android 先交付、iOS 后续」——不满足上线门禁。
