Skip to content

fix(ios): load RCTDefines.h first in React umbrella + drop submodule wildcard so RCT_* macros stay visible#56862

Closed
wneel wants to merge 1 commit into
facebook:mainfrom
wneel:fix/ios-react-umbrella-rctdefines-first
Closed

fix(ios): load RCTDefines.h first in React umbrella + drop submodule wildcard so RCT_* macros stay visible#56862
wneel wants to merge 1 commit into
facebook:mainfrom
wneel:fix/ios-react-umbrella-rctdefines-first

Conversation

@wneel
Copy link
Copy Markdown
Contributor

@wneel wneel commented May 16, 2026

Summary:

When RCT_USE_PREBUILT_RNCORE=1 (the 0.84+ default) and a consumer pod builds under use_frameworks!, RCT macros like RCT_EXTERN, RCT_EXTERN_C_BEGIN, RCT_EXPORT_METHOD, RCT_REMAP_METHOD fail to propagate.

The .m files using these macros hit cascading parse errors like :

  • unknown type name 'RCT_EXTERN_C_BEGIN' in <React/RCTBridgeModule.h> line 51,
  • unknown type name 'RCT_EXTERN' in <React/RCTEventDispatcherProtocol.h> line 17,
  • and type specifier missing, defaults to 'int' on every RCT_EXPORT_METHOD(...) call site.

Root cause is in two places in packages/react-native/scripts/ios-prebuild/templates/:

  1. React-umbrella.h orders RCTBridgeConstants.h (line 56) before RCTDefines.h (line 84). RCTBridgeConstants.h uses RCT_EXTERN at its first declaration but the macro is only defined later in RCTDefines.h. When the umbrella is loaded as a single parse context, the RCT_EXTERN use is unresolvable.

  2. module.modulemap declares module * { export * } inside both framework module blocks, which creates an inferred submodule per header. That isolates macro #defines into per-header parse scopes. Even fixing the umbrella order, sibling submodules don't share macros: macros defined in the RCTDefines.h submodule are invisible to the RCTBridgeConstants.h submodule, and to consumers of the React module.

This PR fixes both:

  • Move #import <React/RCTDefines.h> to the very top of the umbrella (right after the prologue and before any other <React/...> import), with a comment explaining why ordering matters.
  • Remove the module * { export * } wildcard from both framework module blocks in the modulemap. The umbrella header alone is sufficient to declare the module's contents, and dropping the wildcard means the whole module shares one parse context where macros propagate.

The combination of use_frameworks! + prebuilt RNCore is the path of least resistance today: use_frameworks! is the Expo default and is required by firebase-ios-sdk for its Swift bridges. Prebuilt RNCore is the 0.84+ default. The colliding defaults break native-module ecosystems like react-native-firebase that consume the RCT macros. Producer-side fix is in flight at invertase/react-native-firebase#9024; this PR closes the consumer side.

Changelog:

[IOS] [FIXED] - Load RCTDefines.h first in the prebuilt React umbrella and drop the module * submodule wildcard so RCT_* macros propagate to consumer pods under use_frameworks!.

Test Plan:

Reproduced on RN 0.85.3 (latest stable at time of writing) on macOS 26.3.1 / Xcode 26.5 / iOS 26.5 Simulator (iPhone 17 Pro).

Reproducer setup

Fork of mikehardy/rnfbdemo with these adjustments in make-demo.sh:

  • RN_VER=0.85.3
  • RNFB_VER=24.0.0
  • FB_IOS_VER=12.10.0
  • Remove @react-native-firebase/dynamic-links from the bulk yarn add (deprecated and removed in RNFB 24.x).

Default Podfile mods produced by make-demo.sh are preserved: use_frameworks! :linkage => :static + $RNFirebaseAsStaticFramework = true. No RCT_USE_PREBUILT_RNCORE override (stays at the 1 default).

Public reproducer: https://github.com/wneel/rnfbdemo (see its REPRO.md for the two-stage flow).

The reproducer also has invertase/react-native-firebase#9024 (producer-side podspec fixes) applied as an overlay. Without those, the build fails earlier at -Wnon-modular-include-in-framework-module. With them applied, the build progresses to the consumer side and surfaces the macro propagation bug this PR fixes.

Before this PR

Same reproducer config. iOS build fails on consumer pods (RNFBAuth, RNFBStorage, RNFBMessaging) with:

.../Pods/Headers/Public/React-Core/React/RCTEventDispatcherProtocol.h:17:1: error: unknown type name 'RCT_EXTERN'
.../Pods/Headers/Public/React-Core/React/RCTEventDispatcherProtocol.h:17:27: error: expected ';' after top level declarator
.../node_modules/@react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h:26:21: error: declaration of 'RCTPromiseRejectBlock' must be imported from module 'RNFBApp.RNFBAppModule' before it is required

After this PR

Same reproducer config builds cleanly: pod install clean, xcodebuild Debug build produces the app, zero RCT_EXTERN macro errors anywhere in the log.

Verified by editing packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h and packages/react-native/scripts/ios-prebuild/templates/module.modulemap in place (the diff in this PR), regenerating the prebuilt React.xcframework artifact, and re-running the reproducer.

Output of npx @react-native-community/cli info from the reproducer environment:

System:
  OS: macOS 26.3.1
  CPU: (10) arm64 Apple M2 Pro
  Memory: 466.16 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.14.0
    path: /usr/local/bin/node
  Yarn:
    version: 3.6.4
    path: /usr/local/bin/yarn
  npm:
    version: 11.12.1
    path: /usr/local/bin/npm
  Watchman:
    version: 2026.05.11.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.5
      - iOS 26.5
      - macOS 26.5
      - tvOS 26.5
      - visionOS 26.5
      - watchOS 26.5
IDEs:
  Xcode:
    version: 26.5/17F42
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 21.0.9
    path: /usr/bin/javac

Cross-references

Copy link
Copy Markdown
Contributor

@cipolleschi cipolleschi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this

@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented May 18, 2026

@cipolleschi has imported this pull request. If you are a Meta employee, you can view this in D105582598.

@wneel
Copy link
Copy Markdown
Contributor Author

wneel commented May 18, 2026

Thanks for the quick review and import! Happy this one lands cleanly :)

Copy link
Copy Markdown
Contributor

@cortinico cortinico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

@meta-codesync meta-codesync Bot closed this in 90c303f May 18, 2026
@facebook-github-tools facebook-github-tools Bot added the Merged This PR has been merged. label May 18, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented May 18, 2026

@cipolleschi merged this pull request in 90c303f.

@react-native-bot
Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @wneel in 90c303f

When will my fix make it into a release? | How to file a pick request?

@wneel wneel deleted the fix/ios-react-umbrella-rctdefines-first branch May 18, 2026 19:23
react-native-bot pushed a commit that referenced this pull request May 21, 2026
…wildcard so RCT_* macros stay visible (#56862)

Summary:
When `RCT_USE_PREBUILT_RNCORE=1` (the 0.84+ default) and a consumer pod builds under `use_frameworks!`, RCT macros like `RCT_EXTERN`, `RCT_EXTERN_C_BEGIN`, `RCT_EXPORT_METHOD`, `RCT_REMAP_METHOD` fail to propagate.

The `.m` files using these macros hit cascading parse errors like :
- `unknown type name 'RCT_EXTERN_C_BEGIN'` in `<React/RCTBridgeModule.h>` line 51,
- `unknown type name 'RCT_EXTERN'` in `<React/RCTEventDispatcherProtocol.h>` line 17,
- and `type specifier missing, defaults to 'int'` on every `RCT_EXPORT_METHOD(...)` call site.

Root cause is in two places in `packages/react-native/scripts/ios-prebuild/templates/`:

1. `React-umbrella.h` orders `RCTBridgeConstants.h` (line 56) before `RCTDefines.h` (line 84). `RCTBridgeConstants.h` uses `RCT_EXTERN` at its first declaration but the macro is only defined later in `RCTDefines.h`. When the umbrella is loaded as a single parse context, the `RCT_EXTERN` use is unresolvable.

2. `module.modulemap` declares `module * { export * }` inside both `framework module` blocks, which creates an inferred submodule per header. That isolates macro `#define`s into per-header parse scopes. Even fixing the umbrella order, sibling submodules don't share macros: macros defined in the `RCTDefines.h` submodule are invisible to the `RCTBridgeConstants.h` submodule, and to consumers of the `React` module.

This PR fixes both:

- Move `#import <React/RCTDefines.h>` to the very top of the umbrella (right after the prologue and before any other `<React/...>` import), with a comment explaining why ordering matters.
- Remove the `module * { export * }` wildcard from both `framework module` blocks in the modulemap. The umbrella header alone is sufficient to declare the module's contents, and dropping the wildcard means the whole module shares one parse context where macros propagate.

The combination of `use_frameworks!` + prebuilt RNCore is the path of least resistance today: `use_frameworks!` is the Expo default and is required by `firebase-ios-sdk` for its Swift bridges. Prebuilt RNCore is the 0.84+ default. The colliding defaults break native-module ecosystems like `react-native-firebase` that consume the RCT macros. Producer-side fix is in flight at invertase/react-native-firebase#9024; this PR closes the consumer side.

## Changelog:

[IOS] [FIXED] - Load `RCTDefines.h` first in the prebuilt React umbrella and drop the `module *` submodule wildcard so RCT_* macros propagate to consumer pods under `use_frameworks!`.

Pull Request resolved: #56862

Test Plan:
Reproduced on RN 0.85.3 (latest stable at time of writing) on macOS 26.3.1 / Xcode 26.5 / iOS 26.5 Simulator (iPhone 17 Pro).

**Reproducer setup**

Fork of `mikehardy/rnfbdemo` with these adjustments in `make-demo.sh`:
- `RN_VER=0.85.3`
- `RNFB_VER=24.0.0`
- `FB_IOS_VER=12.10.0`
- Remove `react-native-firebase/dynamic-links` from the bulk yarn add (deprecated and removed in RNFB 24.x).

Default Podfile mods produced by `make-demo.sh` are preserved: `use_frameworks! :linkage => :static` + `$RNFirebaseAsStaticFramework = true`. No `RCT_USE_PREBUILT_RNCORE` override (stays at the `1` default).

Public reproducer: https://github.com/wneel/rnfbdemo (see its `REPRO.md` for the two-stage flow).

The reproducer also has invertase/react-native-firebase#9024 (producer-side podspec fixes) applied as an overlay. Without those, the build fails earlier at `-Wnon-modular-include-in-framework-module`. With them applied, the build progresses to the consumer side and surfaces the macro propagation bug this PR fixes.

**Before this PR**

Same reproducer config. iOS build fails on consumer pods (RNFBAuth, RNFBStorage, RNFBMessaging) with:

```
.../Pods/Headers/Public/React-Core/React/RCTEventDispatcherProtocol.h:17:1: error: unknown type name 'RCT_EXTERN'
.../Pods/Headers/Public/React-Core/React/RCTEventDispatcherProtocol.h:17:27: error: expected ';' after top level declarator
.../node_modules/react-native-firebase/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h:26:21: error: declaration of 'RCTPromiseRejectBlock' must be imported from module 'RNFBApp.RNFBAppModule' before it is required
```

**After this PR**

Same reproducer config builds cleanly: `pod install` clean, `xcodebuild` Debug build produces the app, zero `RCT_EXTERN` macro errors anywhere in the log.

Verified by editing `packages/react-native/scripts/ios-prebuild/templates/React-umbrella.h` and `packages/react-native/scripts/ios-prebuild/templates/module.modulemap` in place (the diff in this PR), regenerating the prebuilt React.xcframework artifact, and re-running the reproducer.

**Output of `npx react-native-community/cli info` from the reproducer environment:**

```
System:
  OS: macOS 26.3.1
  CPU: (10) arm64 Apple M2 Pro
  Memory: 466.16 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.14.0
    path: /usr/local/bin/node
  Yarn:
    version: 3.6.4
    path: /usr/local/bin/yarn
  npm:
    version: 11.12.1
    path: /usr/local/bin/npm
  Watchman:
    version: 2026.05.11.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.5
      - iOS 26.5
      - macOS 26.5
      - tvOS 26.5
      - visionOS 26.5
      - watchOS 26.5
IDEs:
  Xcode:
    version: 26.5/17F42
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 21.0.9
    path: /usr/bin/javac
```

**Cross-references**

- `react-native-firebase` producer-side fix in flight: invertase/react-native-firebase#9024
- `react-native-firebase` `.m` import hygiene follow-up: invertase/react-native-firebase#9026
- Original RNFB user-facing issue: invertase/react-native-firebase#8883

Reviewed By: cortinico

Differential Revision: D105582598

Pulled By: cipolleschi

fbshipit-source-id: ab364d46fc94d64274197cdd717a06e425a9324f
@react-native-bot
Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @wneel in ff2562e

When will my fix make it into a release? | How to file a pick request?

qq382724935 added a commit to unif-design/react-native-umeng that referenced this pull request May 27, 2026
CI build-ios 一直挂 'memory' file not found,本地复现也一致。
根因:RN 0.85.3 默认开 RCT_USE_PREBUILT_RNCORE 时,React-umbrella.h 把
RCTBridgeConstants.h 放在 RCTDefines.h 之前,且 module.modulemap 用
wildcard 把每个 header 隔离成 sub-module —— ReactCodegen 编译 .cpp
时找不到 <memory> 等 C++ stdlib header(facebook/react-native#56862)。

修复路径 —— 临时禁掉 prebuilt(从源码编译 React-Core),等 0.85.4 含
PR #56862 后再恢复:
- ci.yml build-ios: RCT_USE_RN_DEP=0 + RCT_USE_PREBUILT_RNCORE=0
- example/ios/Podfile: 撤销之前加的 CLANG_CXX_LIBRARY workaround
  (根因找到后不再需要 hack)

本地用 RCT_USE_PREBUILT_RNCORE=0 重 pod install 后跑 build:ios 通过,
生成 ReactNativeUmengExample.app 成功。

参考:
- facebook/react-native#56862 (fix backport to 0.84/0.85)
- invertase/react-native-firebase#8883 (workaround 推荐)
- expo/expo#35517 (同问题,同根因)
qq382724935 added a commit to unif-design/react-native-umeng that referenced this pull request May 27, 2026
之前禁 prebuilt(RCT_USE_PREBUILT_RNCORE=0) 绕开 'memory' file not found,
代价是 CI 每次从源码编译 React-Core 慢 5-10 分钟。改成原地 patch
prebuilt xcframework 里的 React-umbrella.h + module.modulemap
(facebook/react-native#56862 改的 ios-prebuild/templates/)。

变更:
- example/ios/Podfile post_install: ruby patch 把 RCTDefines.h 移到
  RCTBridgeConstants.h 之前 + 删 modulemap wildcard sub-module
- ci.yml build-ios: RCT_USE_PREBUILT_RNCORE=1, RCT_USE_RN_DEP=1 恢复

本地验证: prebuilt+patch 模式 yarn build:ios 成功生成 .app,零
'memory' file not found 报错。

清理时机: RN 0.86.0 stable (rc.2 已验证含 fix) → 升 RN + 删 patch。
qq382724935 added a commit to unif-design/react-native-umeng that referenced this pull request May 27, 2026
只升 example 端的 react-native + @react-native/* 配套包,library
peerDependencies 仍写 *,不影响下游用户的 RN 版本选择。

RN 0.86.0-rc.2 已含 facebook/react-native#56862 fix(prebuilt
xcframework 里 React-umbrella.h 把 RCTDefines.h 提前 + 删
modulemap wildcard sub-module),所以可以直接走 prebuilt 不再
需要 post_install patch。

变更:
- example/package.json: react-native + 4 个 @react-native/*
  从 0.85.3 升 0.86.0-rc.2
- example/ios/Podfile: 删 PR #56862 ruby patch 整段
- example/ios/...pbxproj: pod install 自动加 PODFILE_DIR build setting

本地验证:
- yarn typecheck 干净, 38/38 jest 测试通过
- pod install 成功, prebuilt umbrella + modulemap 自带 fix
- yarn build:ios (RCT_USE_PREBUILT_RNCORE=1) 成功生成
  ReactNativeUmengExample.app,零 'memory' file not found

清理时机: RN 0.86 stable 出来后,把 example 升到 0.86.x (去掉
-rc.2 后缀)。
qq382724935 added a commit to unif-design/react-native-umeng that referenced this pull request May 28, 2026
* feat(types): export PLATFORM_BRAND_COLORS for ShareSheet leading tile

把微信 (#07C160) 和钉钉 (#2595E8) 品牌色从 PlatformLeading hardcode 抽出,
作为 PLATFORM_BRAND_COLORS 公开导出。消费者 (宿主 App / 自定义 UI) 也能复用
品牌色与 ShareSheet 视觉一致。

* chore: release-it 启用 changelog 落盘到 CHANGELOG.md

* fix(build): wire codegen on Android library + workaround C++ stdlib on iOS

- android/build.gradle: apply 'com.facebook.react' plugin 让 example app
  autolinking 时触发 codegen 生成 NativeUmengXxxSpec 抽象基类,否则
  compileDebugKotlin 报 Unresolved reference 'NativeUmengCommonSpec' 等
- example/ios/Podfile: post_install 强制设 CLANG_CXX_LIBRARY=libc++ +
  c++20 + -stdlib=libc++,绕开 Xcode 26 + RN 0.85.3 ReactCodegen
  .cpp 文件找不到 <memory> 的环境兼容问题

* fix(ci): disable prebuilt RNCore on iOS — RN 0.85.3 + Xcode 26 incompat

CI build-ios 一直挂 'memory' file not found,本地复现也一致。
根因:RN 0.85.3 默认开 RCT_USE_PREBUILT_RNCORE 时,React-umbrella.h 把
RCTBridgeConstants.h 放在 RCTDefines.h 之前,且 module.modulemap 用
wildcard 把每个 header 隔离成 sub-module —— ReactCodegen 编译 .cpp
时找不到 <memory> 等 C++ stdlib header(facebook/react-native#56862)。

修复路径 —— 临时禁掉 prebuilt(从源码编译 React-Core),等 0.85.4 含
PR #56862 后再恢复:
- ci.yml build-ios: RCT_USE_RN_DEP=0 + RCT_USE_PREBUILT_RNCORE=0
- example/ios/Podfile: 撤销之前加的 CLANG_CXX_LIBRARY workaround
  (根因找到后不再需要 hack)

本地用 RCT_USE_PREBUILT_RNCORE=0 重 pod install 后跑 build:ios 通过,
生成 ReactNativeUmengExample.app 成功。

参考:
- facebook/react-native#56862 (fix backport to 0.84/0.85)
- invertase/react-native-firebase#8883 (workaround 推荐)
- expo/expo#35517 (同问题,同根因)

* chore(deps): bump @unif/react-native-design ^0.2.0 -> ^0.3.0

* ci: align github actions automation with @unif/react-native-design 0.3.0

- 加 .github/workflows/pr-agent.yml: PR Agent + DeepSeek 自动 review
  (走 org 级 reusable workflow unif-design/.github/.github/workflows/pr-agent.yml)
- 加 .pr_agent.toml: umeng 项目特有 review 规则
  (TurboModule 三端同步 / PIPL / 错误码 / 友盟拼写陷阱 / U-Share UI thread)
- ci.yml + release.yml 升级 actions 版本:
  - actions/checkout v5.0.0 -> v6.0.2
  - actions/cache v4.2.3 -> v5.0.5
  - actions/setup-java v4.7.1 -> v5.2.0

需要 repo secret: DEEPSEEK_API_KEY (从 design 同款配置)

* perf(ci): patch prebuilt RNCore instead of disabling — saves 5-10 min

之前禁 prebuilt(RCT_USE_PREBUILT_RNCORE=0) 绕开 'memory' file not found,
代价是 CI 每次从源码编译 React-Core 慢 5-10 分钟。改成原地 patch
prebuilt xcframework 里的 React-umbrella.h + module.modulemap
(facebook/react-native#56862 改的 ios-prebuild/templates/)。

变更:
- example/ios/Podfile post_install: ruby patch 把 RCTDefines.h 移到
  RCTBridgeConstants.h 之前 + 删 modulemap wildcard sub-module
- ci.yml build-ios: RCT_USE_PREBUILT_RNCORE=1, RCT_USE_RN_DEP=1 恢复

本地验证: prebuilt+patch 模式 yarn build:ios 成功生成 .app,零
'memory' file not found 报错。

清理时机: RN 0.86.0 stable (rc.2 已验证含 fix) → 升 RN + 删 patch。

* chore(example): bump RN 0.85.3 -> 0.86.0-rc.2 (drops Podfile patch)

只升 example 端的 react-native + @react-native/* 配套包,library
peerDependencies 仍写 *,不影响下游用户的 RN 版本选择。

RN 0.86.0-rc.2 已含 facebook/react-native#56862 fix(prebuilt
xcframework 里 React-umbrella.h 把 RCTDefines.h 提前 + 删
modulemap wildcard sub-module),所以可以直接走 prebuilt 不再
需要 post_install patch。

变更:
- example/package.json: react-native + 4 个 @react-native/*
  从 0.85.3 升 0.86.0-rc.2
- example/ios/Podfile: 删 PR #56862 ruby patch 整段
- example/ios/...pbxproj: pod install 自动加 PODFILE_DIR build setting

本地验证:
- yarn typecheck 干净, 38/38 jest 测试通过
- pod install 成功, prebuilt umbrella + modulemap 自带 fix
- yarn build:ios (RCT_USE_PREBUILT_RNCORE=1) 成功生成
  ReactNativeUmengExample.app,零 'memory' file not found

清理时机: RN 0.86 stable 出来后,把 example 升到 0.86.x (去掉
-rc.2 后缀)。

* docs: add docusaurus website + lefthook + align org automation

同步 design 仓库 #13/#14/#15/#16:
- website/: docusaurus 3.10 workspace (intro + share-sheet),
  RNW plugin alias @unif/react-native-umeng -> ../src/index.ts
- .github/workflows/deploy-docs.yml: build + deploy 到
  https://unif-design.github.io/react-native-umeng/
- lefthook.yml + devDep: pre-commit eslint/tsc + commit-msg commitlint
- CONTRIBUTING.md: 链接到 org AUTOMATION.md,删冗余
- tsconfig.json + eslint.config.mjs: exclude / ignore website
- .gitignore: website/.docusaurus + website/build

本地验证: yarn workspace ...-website build 成功生成 static files,
yarn typecheck + 38/38 jest 通过。

* docs: 把 homepage / readme 指向 docs 站

- package.json#homepage: github repo readme -> 文档站
  https://unif-design.github.io/react-native-umeng/
  npm registry 包页面 'Homepage' 链接自动用这个(下次发版生效)
- README.md 顶部加显眼链接到文档站 + npm

* fix(ci): tsconfig.build exclude website + restore Podfile RNCore patch

build-library CI 挂: tsconfig.build.json 自己的 exclude 覆盖了父 tsconfig
的 exclude (TypeScript 不合并),没把 website 排除 → bob build typescript
target 扫到 website/src/*.tsx 报 22 个 type 错。

build-ios CI 挂: RN 0.86.0-rc.2 prebuilt 自带 PR #56862 fix,但 CI
macos-latest Xcode 26 上仍报 ReactCodegen .cpp 'memory' file not found,
本地 Xcode 26.5 复现不出。先恢复 Podfile post_install 的 umbrella +
modulemap 二次 patch 兜底,带 marker idempotent,RN 已含 fix 时自动跳过。

修复:
- tsconfig.build.json: exclude 加 'website' (对齐 design)
- example/ios/Podfile post_install: 加回 React-umbrella.h + modulemap
  patch,带 marker 检测避免重复修

* fix(ci): disable prebuilt RNCore on iOS — Xcode 26.3 stdlib incompat

GitHub macos-15 runner 上 Xcode 26 系列最高 26.3,本地 Xcode 26.5
能跑 prebuilt 模式,CI 26.3 上 ReactCodegen .cpp 仍报 'memory' file
not found —— C++ stdlib include path 在 26.3 配置不全 (跟 React
umbrella / modulemap 无关,PR #56862 patch 治不了)。

回到从源码编译 React-Core 方案 (commit e996bb2 已验证过): CI 多
5-10 分钟但 100% 稳。本地开发保留 prebuilt=1 + Podfile patch 走
快路径,patch 带 marker 在 RN ≥ 0.86 自带 fix 时自动跳过。

清理时机: GitHub runner 出 Xcode 26.5(或 stdlib 配置补全的子版本)
后,把 ci.yml 改回 RCT_USE_PREBUILT_RNCORE=1。

* fix(example): 把 library 显式加为 workspace dep

build-android 一直挂 'Unresolved reference NativeUmengCommonSpec' 等 ——
codegen 没生成抽象基类。根因: example/node_modules 下没 @unif/react-native-umeng
软链,RN 0.86 autolinking 找不到 library 的 codegenConfig 就不触发 codegen
任务。

example/react-native.config.js 里 'dependencies.{pkg.name}.root' 这种显式
配置在 0.86 不再被 codegen 流程读 —— 0.86 走标准 node_modules 解析。

修复: example/package.json dependencies 加 '@unif/react-native-umeng:
workspace:*',让 yarn workspace 建软链
example/node_modules/@unif/react-native-umeng -> ../../.. → autolinking
能扫到 → codegen 任务被 wire 进 :unif_react-native-umeng:preBuild → Native*Spec
正确生成 → compileDebugKotlin 不再报 Unresolved reference。

本地 yarn install 后软链已生成,push 等 CI 验证。

* chore(example): revert RN 0.86.0-rc.2 -> 0.85.3

按用户决定回到 RN 0.85.3 stable。example/package.json 把 react-native
+ 4 个 @react-native/* 改回 0.85.3。

forward 改不撤之前 commits (7976424 升 0.86 / ac56bc7 恢复 Podfile patch
/ d8b6d5c CI 禁 prebuilt) —— 各项 commit 历史保留作为 timeline 记录。

当前组合:
- example RN 0.85.3 (stable)
- ci.yml RCT_USE_PREBUILT_RNCORE=0 (CI Xcode 26.3 stdlib bug 兜底)
- example/ios/Podfile post_install: PR #56862 patch 保留 (本地
  prebuilt=1 走快路径时给 0.85.3 prebuilt umbrella 加 fix)

* fix(android): codegenConfig 加 android.javaPackageName + 删 sourceSets 手抄

build-android 一直挂 Unresolved reference NativeUmeng{Common,Share,Analytics}Spec
—— codegen 根本没生成抽象基类。

根因(对比 npx create-react-native-library 标准 turbo-module 模板):

1. package.json codegenConfig 缺 'android.javaPackageName' 字段。
   RN 0.85+ codegen 需要这个告诉它 Native*Spec 生成到哪个 Java/Kotlin
   package。没这字段 Android 端 codegen 直接跳过 → import 报 Unresolved。
   plan task 1 写 codegenConfig 时漏了这一段(iOS 不需要,看不出来)。

2. android/build.gradle 删 'sourceSets.main.java.srcDirs += [generated/...]'
   —— 标准模板没有这一段,RN gradle plugin apply 后自动注册 generated dirs,
   我们手抄反而可能干扰路径。

修复参考: /tmp/ref-turbo (npx create-react-native-library 0.62 现跑的
turbo-module-kotlin-objc 模板)

* chore(android): build.gradle 全面对齐 npx create-react-native-library 0.62 模板

对照本地 /Users/liulijun/tongyi/kj (npx create-react-native-library@latest
--type turbo-module --languages kotlin-objc 现跑的模板) 把 library 的
android/build.gradle 对齐:

- 用 ext.ReactNativeUmeng = [kotlinVersion: '2.0.21', minSdk: 24,
  compileSdk: 36, targetSdk: 36] 集中默认值,getExtOrDefault 兜底
- apply 顺序: com.android.library → kotlin-android → com.facebook.react
  (之前 react 放第一个,kj 放最后)
- 加 buildTypes { release { minifyEnabled false } }
- 加 lint { disable 'GradleCompatible' }
- compileOptions JavaVersion.VERSION_1_8 (跟模板一致,RN 0.85 example 会
  在 root project 注入 VERSION_17,这里 1_8 不影响 example build)
- 删 def reactNativeArchitectures() —— dead code,模板没用
- 删 kotlinOptions { jvmTarget = '17' } —— 模板没显式声明

namespace + 友盟/微信/钉钉 deps 保留为业务特有部分。

实际触发 build-android 修复的关键是上一个 commit 17894d2 加的
codegenConfig.android.javaPackageName,这次的 build.gradle 对齐是
进一步消除潜在不一致风险。

* chore(example): 删 workspace dep 多余引用

example 找 library 走 react-native.config.js (autolinking) + metro 的
withMetroConfig({ root: '..' }) (JS resolve),不需要 example/node_modules
软链。npx create-react-native-library 标准模板 (kj 对照) 的 example/package.json
deps 也只列 react + react-native。

之前 commit 46ece37 误加 '@unif/react-native-umeng: workspace:*' 是基于
'autolinking 走 node_modules 标准路径' 的错误诊断 —— 实际 RN 走 config.js
显式 dependencies。删除该行后 example/node_modules/@unif 只剩
react-native-design 软链。

* docs(plan): 加 Errata 段记录 plan task 1/3/23 偏差与教训

在 implementation plan 顶部 (Spec 链接和 File Structure 之间) 加 Errata 段:

1. 列出已知漏抄/改坏 (task 1 codegenConfig 漏 android.javaPackageName,
   task 3 build.gradle 手抄简化, task 11 注释误导, task 23 后期误加
   workspace dep) 和对应修复 commit
2. 根因分析: 9 处 Kotlin Unresolved reference 全部串错指向同一个根因
   —— codegenConfig.android.javaPackageName 缺失
3. 下次类似项目的 plan 写法教训:
   - 'patch 模板字段' 而非 '整段重写新内容'
   - 不在 plan 里贴整段新文件内容
   - task 完成后 git diff initial-commit 校对模板字段保留
   - native build 验证不能跳

不动后面 task 1-26 原文 —— 保留历史决策记录。Errata 给将来跑同样 plan
的人 / agent 看,提前避雷。

* chore(ios): podspec 对齐 npx create-react-native-library 0.62 模板

对照 /Users/liulijun/tongyi/kj (npx 现跑模板) iOS podspec 清理本 plan
task 2 自加的非模板内容:

- 删 pod_target_xcconfig 整段 (DEFINES_MODULE / SWIFT_VERSION=5.0 /
  CLANG_ENABLE_MODULES / OTHER_LDFLAGS): kj 模板没这段,RN 默认 +
  install_modules_dependencies(s) 帮设。我们手设的 SWIFT_VERSION=5.0
  尤其可疑 (RN 0.85 默认 Swift 5.10+,强制降级潜在风险),其它三个跟
  install_modules_dependencies 重复设。
- 加 s.private_header_files = 'ios/**/*.h': 把 .h 标 private,不暴露到
  framework umbrella,避免污染消费者 import 空间 + 跟 RN modulemap 冲突。

保留: 友盟/微信/钉钉 deps (业务必需) + install_modules_dependencies。

本地 pod install + yarn build:ios (RCT_USE_PREBUILT_RNCORE=1) 验证通过,
ReactNativeUmengExample.app 生成,零 'memory' file not found。

这是 Android task 1/3 同性质的 'plan 改坏模板' 问题在 iOS 端的修复。
Plan task 2 详见 docs/superpowers/plans/...md。

* docs(plan): 补 errata task 2 iOS podspec 偏差

补 plan Errata 段:
- 表格加 task 2 行: ReactNativeUmeng.podspec 手加 pod_target_xcconfig
  4 字段 + 缺 s.private_header_files,跟 install_modules_dependencies(s)
  重复且 SWIFT_VERSION=5.0 强制降级有风险
- 教训章节加 'Task 2 应这样写' 段(原 task 3 改成 task 2/3 两段)
- 编号 3→4 / 4→5 / 5→6 顺延
- '当前修复路径' 加 124b354

* chore: 加 dependabot automerge + security policy + feature request 模板

补齐 GitHub 标准开源仓库的 3 项配置:

1) .github/workflows/dependabot-automerge.yml: 自动批准 + auto-merge
   dependabot patch / minor PR,跳过人审。major bump 仍走人审。
   - 用 pull_request_target 拿 base branch 上下文 (GITHUB_TOKEN 有 write)
   - 双 if 检查 actor + PR user = dependabot[bot] 防伪
   - 所有外部输入走 env 注入,不在 run 命令体展开 expr (防 injection)
   - --auto 配合 ruleset required_status_checks 一起工作,等 CI 全绿才合

2) SECURITY.md: 漏洞报告流程,指向 GitHub Private vulnerability reporting
   入口,列了范围 (不包含友盟 / 微信 / 钉钉 SDK 本身)、回复 SLA、致谢规则。

3) .github/ISSUE_TEMPLATE/feature_request.yml: 跟现有 bug_report.yml 同
   风格的功能请求模板,加自检 / 用户故事 / API 提案 / 备选方案 / 影响范围 /
   是否破坏兼容 字段。

CodeQL 已通过 GitHub Default Setup 跑 (b6af026 check-runs 有 Analyze
(javascript-typescript/ruby/actions) 都 success),不需要 yml。

* docs: readme 顶部加 4 个 shields.io badges (同步 design #18)

npm version / CI status / license / docs 链接,提升 repo 第一印象。
badges 已包含 npm + docs 链接,所以原来 emoji 链接段去掉。

* fix(android): onEvent map value 类型改 Any? 适配 ReadableMap.toHashMap()

RN 0.85 ReadableMap.toHashMap() 返回 HashMap<String, Any?>(value 可空),
之前声明 MutableMap<String, Any> 不接受 → compileDebugKotlin 报
'Type mismatch: inferred type is Any?, but Any was expected.'

修复: MutableMap<String, Any?> —— 友盟 MobclickAgent.onEventObject 是
Java Map<String, Object> 接受 Any?,行为不变。JS 层 src/analytics.ts
已经 stringify 所有 value,实际 null 不会进来,只是类型上对齐。

注: 这是上一轮 commit 17894d2 修 codegenConfig 后真正暴露出来的代码
错(在 codegen 修之前,父类都不存在,这种 type mismatch 被遮蔽)。
codegen 修后只剩这一处真实编译错,其它 9 处 Unresolved reference 全消。

* chore(website): 删 design-only 演示组件 (IconCatalog/Swatches/LiveDemo)

这些是从 design 仓库 copy 来的 UI 组件演示工具,展示 design 的图标库 /
颜色 token / 组件库,umeng 文档站 (sidebar: intro + share-sheet) 完全
不用。

顺手解决 PR Agent (DeepSeek) review 的 2 条真 issue:
- IconCatalog.tsx onKeyDown 没处理 Space 浏览器默认滚动 (a11y)
- IconCatalog 按钮缺 aria-label (a11y)

第 3 条 review "process.env.NODE_ENV / JEST_WORKER_ID 安全风险" 是
误判 —— DefinePlugin 字面量替换是 webpack 标准模式做 dead-code
elimination,JEST_WORKER_ID=undefined 是 docusaurus 浏览器跑 RN 库
内部 jest 分支 short-circuit 的标准 workaround,不是安全风险。
docusaurus-rnw plugin 那段保持不变,PR 上驳回。

验证: yarn workspace ...-website build 成功生成 static files。

* refactor(ios): swift adapter → 纯 objc++ (跟 rn 官方 + 友盟生态对齐)

调研结论:
1) RN 官方明确推荐 turbo-module iOS 端用 Objective-C++ (.mm),不推荐 Swift
2) 友盟 UMShare 6.11.1 用旧式 .framework 不带 Modules/ 目录,非 Clang
   module。友盟 Swift 集成指南只针对 App target 用 bridging header,
   library framework 不支持 bridging header,Swift adapter 是孤儿路径
3) GitHub 搜 react-native umeng 找到 67 个桥库,全部 ObjC,零 Swift 实现
4) Plan task 16/17/18 选 Swift Adapter Pattern 是过度设计

改造内容:
- 新建 ios/UmengBootstrap.h + .mm 替代原 UmengBootstrap.swift
- 重写 ios/UmengCommon.mm: 合并 UmengCommonImpl.swift 逻辑
- 重写 ios/UmengAnalytics.mm: 合并 UmengAnalyticsImpl.swift 逻辑
- 重写 ios/UmengShare.mm: 合并 UmengShareImpl.swift 逻辑
- 删 ios/Umeng{Bootstrap,CommonImpl,AnalyticsImpl,ShareImpl}.swift
- ReactNativeUmeng.podspec 撤回 pod_target_xcconfig (Swift 才需要)
- example/ios/Podfile 撤回 'UMShare', :modular_headers (Swift 才需要)

业务逻辑零损失 — Swift 实现全部是 ObjC API 包装,机械翻译 ObjC++。
错误码映射 / 友盟拼写陷阱 / PIPL 合规 / Universal Link 处理 全部保留。

本地验证: yarn build:ios (RCT_USE_PREBUILT_RNCORE=1) 成功生成 .app,
零 'memory file not found' / 'Unable to find module' 错误。

修复 PR #10 build-ios 长期挂的 'Unable to find module dependency:
UMShare' 根因 — Swift import UMShare 在非 modular pod 上找不到
Clang module。改 ObjC++ 后根本不依赖 module 机制。

* docs(plan): 补 errata task 16/17/18 swift adapter 偏差

完成 plan errata 全闭环。补 task 16/17/18 (iOS Swift Adapter Pattern)
的过度设计偏差记录:

- Errata 表格加 task 16/17/18 行,详述 3 条事实链:
  1) RN 官方原文推 ObjC++ 而非 Swift
  2) 友盟 UMShare 6.11.1 非 modular framework,library 不支持 bridging
     header,Swift adapter 在友盟生态是孤儿路径
  3) GitHub 67 个 RN 友盟桥库零 Swift
- 教训章节加第 4 条 'Task 16/17/18 不要选 Swift Adapter Pattern' 写法
- '当前修复路径' commit 列表加 9003025 / 289cd8a
- 移除 d8b6d5c 注释里关于 'iOS Xcode stdlib bug' 的早期误判残留 (改写
  说明真根因是 Swift 路径,不是 stdlib)

* fix(ios): umengshare 用显式 *weakSelf 类型替代 typeof 扩展

CI Xcode 26.3 clang 报:
  ##[error]expected unqualified-id
  ##[error]use of undeclared identifier 'weakSelf'

3 处 `__weak typeof(self) weakSelf = self;` 的 `typeof` 是 GCC 扩展,
某些 ObjC++ 严格模式下 parser 不识别。本地 Xcode 26.5 容错过。

最稳的修法是显式类型 `__weak UmengShare *weakSelf = self;` —— 不依赖
任何 typeof 变体 (typeof / __typeof / __typeof__),跨 clang 版本通用。

本地 yarn build:ios 通过 (.app 生成,零 error)。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants