48 KiB
48 KiB
RN SDK 重构实施接管文档
状态更新时间:2026-07-27 当前实施范围:
@xuqm/rn-common、@xuqm/rn-bugcollect、@xuqm/rn-update、@xuqm/rn-xwebview
发布约束:所有 XuqmGroup npm/Maven 制品和服务部署只能通过https://jenkins.xuqinmin.com/的 Jenkins 完成。
2026-07-26 / 当前实施状态
- common 已增加
idle / initializing / ready / degraded / failed初始化状态、XuqmError结构化错误、七天最后成功配置缓存,以及最多三次的指数退避抖动。 平台暂不可用时优先进入 degraded;没有缓存时扩展返回XUQM_NOT_READY,不向宿主 制造未处理异常。最后成功配置使用 AES-GCM 完整性加密,密钥由签发配置和 app/package/environment 上下文派生且不写入缓存;这里是应用沙箱内防明文与防篡改 边界,不宣称具备 Android Keystore/iOS Keychain 的硬件保密性。 - 扩展 SDK 的唯一正式初始化入口是平台签发
.xuqmconfig与 Metro 自动初始化;XuqmSDK.initialize(options)及公开XuqmInitOptions已删除,不保留兼容壳。 common-only 不初始化。未使用withXuqmConfig时,公开@xuqm/rn-common/auto-init-config空实现保证 Metro 能完成静态解析;真实 Metro fixture 已覆盖无配置构建。 - 唯一隐私入口为
XuqmSDK.setPrivacyConsent(boolean)。BugCollect 只有在平台启用、 用户已同意且非 Debug 时自动注册采集;Debug 单次验证使用BugCollect.sendTestErrorAndFlush(),宿主不再手动startCapture()。 - BugCollect 收到
BUGCOLLECT_DISABLED会立即停用并清除队列;上传请求不进入自身 HTTP 拦截链。部署中的{code:403,status:'1',message:'BUGCOLLECT_DISABLED'}同样 识别。持久化事件最多 500 条、保留七天,复用 common AES-GCM 沙箱加密,失败不会 先删除队列。冷启动首次获得“平台关闭”配置时,即使尚未创建内存 LogQueue,也会 直接删除该 appKey 的遗留加密队列;Debug 单次测试上传同样要求隐私同意。 - update 从原生 manifest/state 提供当前 Bundle 精确身份;BugCollect 仅在 stack 唯一
命中模块时附带
buildId/moduleId/moduleVersion/bundleHash。无法唯一归属时标记symbolicationStatus=unavailable,不伪造 latest 身份。 - Update 使用平台动态
updateRequiresLogin。需要登录时未登录正常跳过;登录后自动 补检一次并通过onAutomaticCheck交给宿主决定 UI。账号变化会取消旧下载授权和 灰度缓存;后台补检失败不影响宿主登录。服务端权威字段allowAnonymousUpdateCheck缺失时安全默认禁止匿名检查。 - Update 服务开关统一解析
features.update(兼容平铺updateEnabled),缺失安全 默认关闭并进入最后成功配置缓存。所有显式检查/下载/安装入口在网络和原生调用前 抛出UPDATE_DISABLED;自动启动路径正常跳过。 - 插件候选已实现 Ed25519 不可变 manifest 验签:common 集中维护 canonical JSON、
可信 keyId 与 Hermes 运行时验签,Metro 构建期复用同一规则和密钥集合。候选在计划
前与安装前双重验签,Android stager 进一步绑定 buildId、bundleFormat 和
bundleSha256;响应 ZIP
sha256以archiveSha256纳入同一签名,下载后仍使用 同值校验归档。未知 keyId、签名错误和字段篡改测试均已覆盖。 common 加密、Ed25519 与 secureCache 复用 common/security 唯一纯 JS Base64/Base64URL codec,不依赖 Hermes 全局atob/btoa;非法字母表、长度、填充和 尾随位直接拒绝。canonical JSON 对函数、symbol、非有限数、非普通对象、数组空位/undefined 确定性失败,避免 Node、Hermes 与服务端实现各自容错产生不同签名正文。 Server 的update-service/src/test/resources/rn-release-signature-vector.json是 唯一规范源。RN 测试只读明确标记 GENERATED/DO NOT EDIT 的仓内生成副本,保证独立 Git/Jenkins checkout 可运行;scripts/sync-server-signature-vector.mjs --check|--write负责跨仓字节级同步。相邻 Server 缺失时常规单仓 validate 跳过跨仓 比较,发布前必须提供 Server checkout 并执行--check。测试会逐字节比较 canonical UTF-8 正文,并以同一 keyId、原始公钥和 Base64URL 签名完成验签。 - release-set 检查已强制携带 appVersion、nativeApiLevel、nativeBaselineId;缺少
baseline 在发请求前失败。发布 Token 只读取 Jenkins 注入的 XUQM_API_TOKEN,
release.apiToken配置会被构建校验拒绝。 xuqm.modules.json使用packageName保存 Android applicationId、使用iosBundleId保存 iOS Bundle Identifier;相应字段仅在目标平台 build/package/release 时必填。唯一resolveHostPackageId(config, platform)被 构建、在线配置验证、ZIP 期望身份和发布上传共同复用。wire 仍使用packageName,但不会再把 Android 身份写入 iOS ZIP。- 插件 ZIP v1 协议限制已与 Server 对齐:归档 50 MiB、单 entry 100 MiB、总解压
100 MiB、最多 4096 entries。Android stager 不再保留 5000 上限,4096/4097 和单
entry 100 MiB 边界已有原生单测;CLI
zipSync不生成目录 entry,Server 与 stager 均明确拒绝目录 entry。 - Debug 的
XuqmRuntime.start()不做远程整包或插件检查;开发页仍可显式调用公开 check/install API 做一次性验证。 - 插件构建清单已从
xuqm.config.json更名为xuqm.modules.json;租户平台签发的.xuqmconfig仍是唯一初始化源。Metro 使用src/assets/config/内唯一文件, 保留平台下载文件名;零个保持 common-only,多个构建失败。Android/iOS 生成目录 中的构建副本才固定命名为config.xuqmconfig。 - Metro 只接受严格
XUQM-CONFIG-V2:使用内置keyId公钥先做 Ed25519 验签,再 解密并校验 canonical JSON、Schema、UUID、revision 和有效期。V1、未知 keyId 与 签名失败在构建期阻断。当前同时信任开发公钥xuqm-config-dev-2026-07与生产公钥xuqm-config-prod-2026-07;私钥只保存在 Jenkins 凭据库和服务端运行环境,不进入源码或制品。 - Release 每个模块始终生成独立 Source Map,删除
sourcesContent并清理绝对路径。--bugcollect=disabled只归档不上传;启用时按完整 Bundle 身份上传,失败阻断发布。 上传契约固定为POST /bugcollect/v1/artifacts/upload且artifactType=RN_SOURCEMAP;旧 Metro serializer 上传器已删除。发布登记和 Source Map 上传的buildId/moduleId/moduleVersion/bundleHash均从待上传 ZIP 的rn-manifest.json和真实 Bundle 校验后取得,禁止根据环境变量二次推导身份; artifact 上传与插件发布使用同一 Jenkins 发布 Bearer,匿名请求不会发出。 - 整包和插件发布前调用
/api/sdk/build/config/validate。服务不可达、配置过期、 revision 撤销或包名不匹配均阻断新 Release;已安装 App 运行时不查询吊销状态。 - 相同 versionName 的连续 Android Release 自动生成递增 versionCode 和独立 buildId;
- 2026-07-27 本地全量
pnpm validate通过:六个 workspace TypeScript、common 42、 bugcollect 11、xwebview 7、IM 3、update CLI/Metro 28 与 update domain 18 项测试 全部通过;update 发布包内容校验为 51 个文件。common npm dry-run 未包含测试目录及 生成签名向量。Server 相邻仓库存在时签名向量逐字节检查通过,模拟 Server checkout 缺失的单仓 CI 也按契约独立通过。 同一工作区通过.xuqm-cache/release-build.json保证单调递增,跨工作区 CI 通过XUQM_VERSION_CODE和XUQM_BUILD_ID注入全局唯一流水线身份。 - Gradle 内嵌任务把
buildId与bugCollectMode声明为显式@Input并传入 embed 子进程;测试验证 APK 内嵌 manifest 和模块 ZIP 使用同一 Release identity。package与publish共用唯一--bugcollect参数解析器,等号和空格写法一致。 - Android 相同模块版本使用 SHA-256 识别新版 APK 内容;真正更高且兼容 native baseline 的远程插件继续保留。新 release 允许两次进程启动握手,失败 releaseId 本机隔离,服务端内容未变化前不重复安装。
- 原生最终恢复入口只删除 SDK 私有
files/rn-bundles,并递增 reset generation; common/app 初始化后仅清除xuqm_update_*状态并确认该 generation,重试不会误清 宿主、BugCollect 或签名 SDK 数据。 - 已执行
pnpm validate:全部包类型检查、common 42 项、bugcollect 11 项、update CLI 28 项、update 领域 18 项、xwebview 7 项和 IM 3 项测试均通过;update 包内容 校验通过,发布包为 51 个文件;Prettier 和git diff --check通过。 独立native-test的系统 Gradle 仍在任务配置前因本机libnative-platform.dylib无法加载;改用 App4 Gradle 9.3.1 wrapper 后,:xuqm_rn-update:testDebugUnitTest --tests com.xuqm.update.XuqmPluginPackageStagerTest共 25 tasks 构建并测试成功。 尚未执行完整宿主 Android 构建、设备运行、开发环境接口和真实 Source Map 上传; 这些结果不得从当前门禁推断。 - License 离线激活 SDK 已审计:RNSDK 不存在对应包、API、依赖、脚本、文档或空目录;
npm 的
license: UNLICENSED元数据和 RN 插件事务activation不属于离线授权。 - 配置中的
signingKey明确是客户端可提取的请求完整性/缓存派生材料,不是 License、 用户授权或服务端秘密;敏感 API 仍依赖登录accessToken,构建制品上传依赖独立 Jenkins Bearer,并由服务端执行授权。
1. 本轮目标
rn-common可以完全独立使用公共工具,不要求初始化或登录。- 使用 bugcollect、update、xwebview 等扩展时,只执行一次共享 SDK 初始化和一次共享登录。
- 配置文件放入约定位置后由构建工具自动接入初始化,不要求宿主逐个初始化子 SDK。
- common、update、bugcollect、xwebview 之间只保留一份网络、文件、时间、配置、会话和错误定义。
- update SDK 统一承担插件 manifest、兼容性、原子激活、启动确认、崩溃回滚和内嵌恢复;宿主不得再实现平行版本管理器。
- Android 整包更新必须具备应用内下载、SHA-256 校验、安装权限处理、进度、取消、重试和确定性错误码。
- 宿主通过最少配置完成插件创建、开发运行、打包、随 APK 内嵌、发布和回滚。
- XWebView 收敛为
XWebViewHost + openWebView的 SDK 自管页面栈;宿主不再注册路由或传 navigate 回调。
0. 2026-07-26 / XWebView 1.0 实施状态
- 已取得用户实施授权,目标为
@xuqm/rn-xwebview@1.0.0。 - 旧
openXWebView(navigate, config)、common 内全局_config/_controller和公开XWebViewScreen已删除,不保留转发兼容层;迁移规则已写入包 README。 - 新公开入口固定为根部一次挂载
XWebViewHost、业务直接调用openWebView(config),并返回页面级句柄和closedPromise。 - 配置改为
source/navigationBar/statusBar/behavior/permissions/downloads/bridge分组强类型结构;URL 与 HTML 互斥。 - 页面栈、Host 等待/卸载、页面级动态导航、系统返回、外链、下载、权限和 Bridge 异常已收口到 xwebview;common 中错误归属的 WebView 状态与业务 Bridge 已删除。
- H5 媒体权限由页面白名单、可选宿主决策和 Android 系统权限三层控制;SDK 不向 Manifest 注入摄像头或麦克风权限。
- 下载自动复用 URI 首屏鉴权 headers;Bridge 原始 payload 不写日志。
react-native-svg已收敛为 peer;宿主必须直接声明这一原生依赖以参与 autolink, 禁止由 xwebview 私自安装第二份。App4 运行验收曾据此捕获并修复RNSVGSvgViewAndroid未注册问题。- xwebview 类型检查和 7 项独立测试已通过。App4 在 Android 36.1
emulator-5554通过“移动报销”真实 H5 页面验证:页面打开、SDK 初始化、userInfo、右上角菜单和关闭返回均正常,窗口日志无 Java/React/Fabric FATAL。
2. 已冻结的设计约束
startup是内嵌恢复入口,只随完整安装包更新。common、app、buz可以作为插件版本管理对象;common/app 更新必须冷启动生效。- 插件声明
appVersionRange、commonVersionRange和minNativeApiLevel;完整包登记nativeBaselineId,插件记录builtAgainstNativeBaselineId。不能只靠一个最大 App 版本或最低 common 字段推断兼容性;配置 schema 已统一为 v3。 - 一次依赖更新必须作为一个 release set:全部下载、全部校验、全部 staging、原子激活、整组确认或整组回滚。
- common 同一主版本遵守向后兼容;破坏性 API 变更必须提升主版本。
- 插件版本比较必须使用 SemVer;“不相等”不能等价为“需要升级”。
- 远程 Bundle 和 manifest 使用 SHA-256,并预留签名 manifest;MD5 不作为最终安全校验。
- 现阶段不扩展
@xuqm/rn-push,医网信宿主继续使用腾讯 Push。 - 差分 APK 本轮只保留协议扩展位,不实现差分生成与合并。
- 启动更新顺序固定为:准备/恢复未确认 release set → 整包检查 → 无整包更新时检查
app + common依赖闭包。 - buz 只在进入前检查“当前 buz + common”依赖闭包,不扫描或顺带更新其它 buz;common 不作为业务入口独立检查。
3. 当前可信基线
3.1 质量门禁
- Android SDK Jenkins
sdk-android-publish #152:成功,已发布com.xuqm:sdk-core:1.1.6-SNAPSHOT与com.xuqm:sdk-update:2.0.0-SNAPSHOT。 native-test是 RN update Android Bridge 的唯一 Gradle 编译夹具;Jenkins 发布 update 前必须执行:updateBridge:compileDebugJavaWithJavac。- 本地已使用 JDK 21 + Gradle 9.3.1 编译通过;RN Bridge 明确输出 Java 17 字节码,不再隐式回落到 Java 8。
- RN 包不再内置第二份 AGP buildscript;宿主负责插件版本,独立夹具使用与 Android SDK 一致的 AGP 9.1.0。
pnpm validate:通过。- common:20 个测试通过。
- bugcollect:5 个独立测试通过。
- xwebview:7 个独立测试通过。
- update CLI/Metro:11 个测试通过;release-set:6 个测试通过。
- IM 现有测试:3 个通过;IM 不在本轮开发范围。
- 所有 workspace TypeScript typecheck:通过。
3.2 已存在能力
- common 已提供配置、共享会话、HTTP、日期、文件、加密和 XWebView bridge。
- common 已新增统一流式下载、SHA-256、RFC 文件名解析和 SemVer/版本范围能力;update/xwebview 后续必须复用,不再保留私有实现。
- common-only 宿主缺少配置文件时不会触发自动初始化,已有测试覆盖。
- 配置文件自动初始化遇到临时网络失败时会清理失败 Promise;扩展下一次等待初始化时使用同一加密配置重试,不要求宿主重新传 appKey/URL,也不会产生未处理 Promise 或重复错误日志。
- bugcollect、update、xwebview 通过
@xuqm/rn-common/internal触发一次自动初始化入口。 - update CLI 已能从 schema v3
xuqm.modules.json构建 startup/common/app/buz,生成携带 SemVer 兼容范围和原生 API 等级的内嵌 manifest。 - update 的
withXuqmModuleConfig()是多 Bundle 模块编号的唯一实现:日常 Metro 不变,CLI 构建时自动先生成 startup/common 共享模块表,并按配置序号为每个 app/buz 分配独立区间;宿主不再维护多份 Metro 配置或业务名硬编码 offset。 - Android bundle 引擎不在
xuqm.modules.json重复声明:CLI 直接读取宿主android/gradle.properties的hermesEnabled。启用时所有插件统一编译为 Hermes bytecode、组合 source map,并在 manifest/上传表单记录bundleFormat。 - common 的唯一 XWebView 契约新增实时导航状态;全屏与内嵌容器统一提供
canGoBack、canGoForward、当前标题和 URL,并支持宿主配置回调。Bridge 不再重复声明第二份 controller 类型。 - RN update 已有 release-set 纯领域规划器;Android 原生模块已改为整组 staging/激活/确认/回滚,并从 APK assets 恢复内嵌基线。
3.3 已确认缺口
- RN update 已编码
XuqmAppUpdateModule,只桥接 XuqmGroup Androidsdk-update:2.0.0-SNAPSHOT;Android Snapshot、Bridge 编译和 App4 完整 debug 构建已通过,模拟器安装事务仍待验证。 - release-set 已统一使用 SHA-256 和 Ed25519 签名 manifest;服务端仍需按同一
canonical 字段契约签发
keyId/signature并完成联调。 - 原生 state 已成为 Bundle 版本与事务状态唯一真相;App 更新提示缓存仍可使用 AsyncStorage,但不保存 Bundle 版本。
- 客户端已改为
/api/v1/rn/release-set/check单次请求目标入口依赖闭包;租户平台服务端接口尚待同步实现。 nativeBaselineId已自动计算并进入内嵌 manifest/插件上传:覆盖 Android 原生源码、Gradle 配置、RN 与含原生代码的 npm 依赖,普通业务 JS 不影响指纹;Jenkins/服务端登记校验尚待实现。- 插件 API 已拆分为纯检查
checkPluginRelease、确认后安装installPluginRelease和自动场景checkAndInstallPlugin;检查阶段不下载、不写本地状态。 - bugcollect 的采样、限频、fatal 绕过采样和 fatal/error 持久化策略已有纯逻辑测试覆盖。
- xwebview 的相册保存仍是可选宿主能力;其余文件下载能力已经下沉到 common。
- Jenkins 发布参数已收敛到 common、update、bugcollect、xwebview;common/xwebview/update 新 alpha 已发布,仍需增加依赖版本存在性与发布顺序硬校验。
4. 实施进度
| 工作项 | 状态 | 说明 |
|---|---|---|
| 基线审计与门禁 | 完成 | 2026-07-17 本地 validate 全通过 |
| 实时接管文档 | 进行中 | 本文件为唯一实施状态入口 |
| common 公共上下文收敛 | 完成 | 公共基础、共享生命周期与安全 API 诊断 19 测试 |
| bugcollect 依赖 common 与测试 | 完成 | 自动初始化、SHA、版本、策略与 HTTP 脱敏已统一,5 测试 |
| xwebview 1.0 Host/权限/下载 | 完成 | 页面栈、分组配置、7 项测试及 App4 Android 运行通过 |
| update release set 与原生事务 | 进行中 | Android Snapshot、Bridge、App4 构建通过;待事务 E2E |
| package 内容校验 | 完成 | update 包 42 个发布文件已校验 |
| Jenkins alpha 发布 | 完成 | #59/#60 已发布 common、xwebview、update |
| App4 接入 | 完成 | V5 Host、8 模块、Debug APK 与真实 H5 Android 链路通过 |
5. 下一步操作
- 在网络正常的 Android 设备验证自动初始化、登录及扩展共享会话。
- 在 Android 宿主补充 release-set 安装、冷启动确认和崩溃回滚仪器测试。
- 收敛 Jenkins 四包依赖发布顺序和 package 内容检查。
- 后续租户平台实现
/api/v1/rn/release-set/check,服务端只返回目标入口与 common 的兼容闭包。 - App4 当前使用相邻源码联调本轮未发布变更;验证完成后必须由 Jenkins 发布新 alpha,再恢复 Nexus 精确版本。禁止手改
node_modules或本地发布正式制品。
6. 常用验证命令
pnpm validate
pnpm --dir packages/update pack:check
pnpm --dir packages/common test
pnpm --dir packages/update test
不得通过忽略错误、|| true 或跳过测试让 Jenkins 变绿。
7. 本轮变更记录
2026-07-18 / 网络诊断安全收敛
rn-common不再打印完整 Axios 响应、请求配置、headers 或完整 URL。- 网络诊断的唯一实现位于
packages/common/src/api/diagnostics.ts,只保留 method、相对 path、HTTP 状态、错误码和 Zod 字段路径。 - 新增测试使用带手机号、sessionId、userId、token 的伪响应,强制验证 序列化后的诊断结果不包含这些敏感值。
2026-07-19 / common Bundle 模块过滤修复
- App4 模拟器首次加载内嵌插件时出现
Requiring unknown module "726"。定位结果不是宿主页面问题,而是 Metro 的模块编号工厂把本轮首次发现的 common 模块写入共享缓存后,过滤器又读取同一份可变缓存并把该模块从当前 Bundle 删除。 withXuqmModuleConfig()现在只使用构建开始前的共享模块快照做去重:common 本轮新分配的模块保留在 common Bundle;后续 app/buz 仍过滤 startup/common 已有模块。宿主不增加补丁、模块白名单或第二套编号逻辑。- Metro 测试新增“common 本轮新模块必须保留”断言;格式、全部 workspace 类型检查及 48 项测试通过。
- 根工作区脚本统一通过 Corepack 调用锁定的 pnpm,校验不再依赖开发机预装全局 pnpm。
- 当前下一步:刷新 App4 的
file:SDK 联调副本,重建并安装 debug APK;确认六个 Hermes Bundle 可连续加载后继续双模拟器像素校准。修复尚未通过 Jenkins 发布,不得把相邻源码依赖作为正式发版基线。
2026-07-19 / Android 插件图片资源恢复
- App4 common/app 连续加载成功后,登录 logo 和单选框仍为空。根因是 Metro 生成的
drawable-*仅位于assets/rn-bundles,同时原生恢复只复制active.bundle;动态loadBundle(file)会相对当前 Bundle 文件目录解析图片。 - Gradle 生成任务现在公开 assets 与 res 两个独立
DirectoryProperty:Bundle/manifest 进入 APK assets,drawable 同时进入 aapt2 资源表,符合 AGP 生成源 API 的类型约束。 XuqmBundleModule恢复内嵌 Bundle 时同步读取该模块 manifest 的assetFiles,校验路径只允许标准drawable-*/resource_name.ext,再原子写入同一模块目录;图片恢复不由宿主页面逐个处理。- App4 arm64 debug 已真实编译该 Java 实现并安装验证;app 模块私有目录共恢复 289 个 Bundle/状态/资源文件,登录 logo 与单选框显示正常。
- 当前只取得内嵌基线恢复证据;远程 release set 的二进制 Bundle 与资源下载、校验、事务激活仍需作为同一组实现和验证,不能把本次结果扩大为 OTA 资源已完成。
- 全局 API 错误回调不再交付带 Axios cause 的
RequestError,只交付不可逆的安全诊断报告;宿主无法误把请求体、headers 或响应上传到采集平台。 - bugcollect 的全局 fetch 拦截器只上报 method、相对 path 和 HTTP status;完整 host、query、请求体、headers 及原始网络异常对象全部丢弃,测试覆盖敏感查询参数和鉴权头。
2026-07-18 / 多 Bundle Metro 能力下沉
- 新增公开入口
@xuqm/rn-update/metro,withXuqmModuleConfig()内部复用 common 的withXuqmConfig(),宿主只保留一份 Metro 配置。 xuqm-rn build/embed/publish为每个模块注入 id、type、配置序号和共享缓存位置;模块区间不再依赖szyx/miniapp等业务目录名称。- 独立构建 app/buz 时 CLI 自动先构建 startup/common 依赖以重建共享模块表,但仍只发布用户选择的模块,适用于全新 Jenkins 工作区。
- 测试覆盖 0 号模块存在性、startup/common 去重、app/buz 唯一区间,以及单独构建 buz 的依赖顺序;update CLI/Metro 11 项、release-set 6 项和 42 文件包内容校验通过。
2026-07-18 / Jenkins #58—#60 与 App4 精确版本接入
sdk-rn-publish #58被 Windows Hermes 测试正确阻断:测试曾把文本写成hermesc.exe,WindowsspawnSync无法执行;该构建未发布任何包。- CLI 测试改为复制并执行 React Native 实际依赖的 Hermes 编译器,同一测试覆盖 Windows 可执行文件规则和真实字节码输出,不保留伪编译器兼容分支。
sdk-rn-publish #59成功发布@xuqm/rn-common@0.6.0-alpha.15与@xuqm/rn-xwebview@0.3.0-alpha.11。sdk-rn-publish #60成功发布包含 Hermes CLI 改造的@xuqm/rn-update@0.5.0-alpha.13。- App4 已使用上述精确版本;startup/common/app/szyx/miniapp/workbench 六模块均生成为 Hermes bytecode version 98,Gradle 自动嵌入后 debug APK 构建成功。
- 本仓库代码提交
aacfbf0完成宿主运行时/XWebView 协议收敛,04fc964修复 Windows 真实 Hermes 门禁;发布与 App4 构建证据均已取得,剩余仅为设备端 release-set 事务与网络场景验证。
2026-07-18 / Android Hermes 插件产物
xuqm-rn从宿主android/gradle.properties读取唯一hermesEnabled,不要求用户再维护插件引擎字段。- Android Hermes 宿主在 Metro bundle 后统一调用与 React Native 版本匹配的
hermes-compiler;source map 使用 RN 官方组合脚本合并 Metro 与 Hermes 映射。 - 内嵌 manifest 与上传表单新增
bundleFormat,便于服务端和诊断工具识别 JavaScript/Hermes 产物。 - 新增独立 fixture,验证普通宿主保持 JavaScript、Hermes 宿主生成字节码;update CLI 9 测试、release-set 6 测试、typecheck、package 内容检查全部通过。
- App4 arm64 内嵌构建已真实生成六个 Hermes bytecode bundle 并安装启动;ARM64 软件模拟器启动仍慢,必须在真实 Android 设备补性能验收。
2026-07-18 / XWebView 鉴权 H5 首屏请求头
XWebViewConfig新增可选headers: Record<string, string>;全屏与内联两种 XWebView 都只在 URL 首次加载的source上使用同一配置,不新增 App 专属桥接。- App4 的签章详情使用该能力携带当前平台 userId/sessionId/currentClientId 和签名头;SDK 不理解也不保存医网信平台状态。
- common/xwebview 类型检查、4 项 xwebview 测试及整个 RN SDK
pnpm validate已通过。
2026-07-18 / common 自动初始化恢复
- Metro pre-main 自动初始化只负责提前发起任务并消费拒绝,不在 SDK 内重复打印宿主会处理的错误。
- common 保存构建期加密配置请求;临时失败会同时清理初始化 Promise 和配置初始化 Promise,下一次
awaitInitialization()自动重试。 - 重试仍复用
startInitialization的单 Promise 和配置一致性约束,没有增加第二套初始化入口或参数透传。 - 单元测试覆盖“第一次远程配置失败、第二次等待初始化成功”,common 16 个测试与 TypeScript 检查通过。
- 新增
formatNumericDateTime作为 API 固定时间格式和跨项目数字日期布局的唯一通用实现;App4 已删除公告、消息、通知、日程和反馈中的重复年月日拼接。
2026-07-18 / 空目录收敛约束
- 删除无效文件时必须同步删除空父目录,不允许用
.gitkeep维持没有职责的源码结构。 - 已删除 bugcollect 遗留的空
specs、ios、Androidlog包以及根src/shims;依赖和 Gradle 生成目录不属于源码结构。 - 该规则已写入仓库
AGENTS.md,后续文件迁移、模块删除和脚手架调整必须在同一次变更中完成目录收尾。 - 清理后
pnpm validate通过:格式、六个 workspace 类型检查以及 common/bugcollect/update/im/xwebview 全部测试无回归。
2026-07-17 / Jenkins #48 失败修复
sdk-rn-publish #48在 Windows 棡出后因 8 个文件换行不一致被 Prettier 正确阻断,未发布任何包。- 新增
.gitattributes,源码统一以 LF 检出;仅.bat保持 CRLF。 - alpha 版本号改为取源码现有序号与 Nexus 远端序号的最大值后加一,禁止版本倒退和重复发布。
#49被 Jenkins CPS 的不可序列化正则 Matcher 阻断;算法改为只保留整数,并从 Nexus group 读标签、向 hosted 写制品。#50证明旧 Jenkins 工作树仍保留 CRLF;主检出由CleanBeforeCheckout改为WipeWorkspace,确保.gitattributes在全新工作树生效。XuqmRuntime.activate增加显式reloadBundle:buz-only release 可替换旧定义并热加载;含 common 的 release 仍由宿主冷启动。#51通过换行、格式和类型门禁后,暴露 pack 校验脚本硬编码 Unixnpm;现改为fileURLToPath与 Windowscmd.exe/npm.cmd分支。#52通过 pack/typecheck 后发现 Metro 测试只接受 POSIX 路径分隔符;断言改为同时接受 Windows 与 POSIX 路径。
2026-07-17 / common 第一轮
- 引入
semver@7.8.5与@types/semver@7.7.1,不自行重复实现版本算法。 - 新增
downloadBytes、downloadText、DownloadError和统一下载进度结构。 - 新增
sha256Hex,作为后续 Bundle/APK 校验的公共实现。 - 新增纯 JS 文件名模块,Node/CI 测试不会加载
react-native原生模块。 - 新增格式化硬门禁,范围限定为本轮四个 SDK 包,避免改动不在范围内的 IM/Push。
- 验证:common typecheck、16 个测试、Prettier 全部通过。
2026-07-17 / bugcollect 与 xwebview 第一轮
- common 增加扩展初始化订阅;所有扩展共享同一次配置初始化。
- bugcollect 在远程配置启用后自动启动采集,不要求宿主第二次初始化或手工启动。
- bugcollect 删除私有 SHA-256 实现并复用 common;SDK 版本改为读取发布包版本。
- xwebview 删除重复的 Content-Disposition/URL 文件名实现并复用 common。
- xwebview 删除直接的 blob-util 依赖,大文件下载、进度、取消和 Android 下载登记统一下沉 common。
- bugcollect 的采样/限频窗口、fatal 绕过采样和 fatal/error 持久化策略抽成纯领域逻辑,避免采集器与队列各自重复判断。
- 验证:bugcollect typecheck + 4 测试、xwebview typecheck + 2 测试通过。
2026-07-17 / update release-set 第一轮
- 删除 Bundle 版本的 AsyncStorage 副本和 MD5 实现,原生 state 为唯一版本真相,远程 Bundle 强制 SHA-256。
- 新增 release-set 规划器,验证 SemVer 升级、common 范围、原生 API 等级和最终已安装集合兼容性。
- Android 原生模块使用单一事务日志完成整组 staging/激活/确认/回滚;首次运行可从 APK
assets/rn-bundles恢复内嵌版本。 - 未确认 release set 首次启动获得一次确认机会;再次启动仍未确认才整组回滚,避免冷启动更新在加载前被误回滚。
- 更新检查改为按入口依赖闭包:启动时整包优先,其后 app+common;buz 进入前只检查当前 buz+common。
- SDK 不决定宿主 UI:整包与插件均提供独立检查/安装 API;App4 进入 buz 使用
checkAndInstallPlugin,需要弹窗的宿主使用checkPluginRelease后再调用installPluginRelease。 - release-set 记录检查时的全部本地基线版本;弹窗停留期间状态变化会触发
StaleReleaseSetError,不会安装过期计划。 xuqm.modules.json统一使用 schema v3:commonVersionRange+minNativeApiLevel,删除minCommonVersion/minNativeVersion双重语义。- 验证:update typecheck、CLI 6 测试、release-set 6 测试通过;Android 原生代码尚待宿主工程编译验证。
2026-07-17 / Android 整包安装桥接
- 新增
XuqmAppUpdateModule,桥接 AndroidSDK 的唯一 APK 更新实现,不在 RN 包重复下载、哈希或 FileProvider 逻辑。 - 原生事件提供下载字节数、总字节数和百分比;支持 AbortSignal 取消、有限重试及确定错误码。
- SHA-256 为安装硬门禁;缺失哈希直接拒绝,不降级为未校验安装。
- 增加
openInstallPermissionSettings(),宿主收到INSTALL_PERMISSION_REQUIRED后可自行展示 UI 并跳转授权。 - Android SDK Jenkins
#152已发布com.xuqm:sdk-update:2.0.0-SNAPSHOT。 - 新增
native-test最小 Gradle 工程;Jenkins 发布 update 前必须真实编译 Java Bridge,不允许只做 TypeScript/打包校验。 - 首次门禁发现独立工程未启用 AndroidX,补充
native-test/gradle.properties后编译通过;该失败不得通过关闭检查规避。 - Jenkins Windows 节点直接访问外部 Android 仓库会出现无输出的长时间依赖等待;
native-test的 plugin management 已与 AndroidSDK 对齐,统一优先使用 Nexusandroid聚合仓库,再回退官方仓库。 - Windows CLI 测试路径统一使用
fileURLToPath,禁止把file:URL 的 pathname 直接作为本机路径。 - native baseline 现在按 Android/iOS 分别计算,并覆盖全部运行时依赖的实际安装版本、平台原生源码/资源、
src/assets内会随安装包打入的图片、字体和媒体文件;这些内容变化后必须先发布完整 App,不能只发布 JS 插件。
2026-07-19 / 同版本内嵌基线覆盖修复
- App4 覆盖安装新 debug APK 后仍加载手机内旧
active.bundle。根因是ensureEmbeddedBundle()只判断文件存在,插件版本仍为1.0.0时无法识别整包内的代码已经变化。 xuqm-rn embed现在为每个模块记录实际 bundle 的 SHA-256;Android state 同步记录activeHash。状态仍为embedded且摘要变化时,SDK 原子替换 bundle、清理该模块旧 drawable 目录并按 manifest 恢复新资源。- 状态为
active或事务中的远程插件不会被覆盖安装改写;线上更新仍只能经过 stage/activate/confirm/rollback。该分支避免以开发便利破坏生产事务边界。 - RN SDK 全量门禁通过。App4 重新编译 Java Bridge 与六模块共 450 tasks 成功;第一次不清
rn-bundles覆盖安装把旧 state 自动写入新 manifest 摘要,第二次相同 APK 覆盖后 bundle mtime 未变化,证明变化替换和相同复用均生效。下一步为 Jenkins 发布新 alpha 后恢复 App4 精确 Nexus 版本。
2026-07-19 / 平台地址与更新检查超时收敛
XuqmConfig新增职责明确的platformUrl;配置文件serverUrl/baseUrl只在解密入口归一为该字段。租户配置、整包和插件更新统一访问platformUrl,远程apiUrl只表示业务扩展服务,禁止两者混用。- common HTTP 增加唯一 30 秒默认超时,并将调用方
AbortSignal与内部超时合并;定时器在成功、失败和取消后统一清理,不要求每个 SDK 复制Promise.race。 checkPluginRelease()支持signal/timeoutMs;checkAndInstallPlugin()支持signal/checkTimeoutMs,宿主可为“进入插件前检查”设置更短交互边界,同时保留纯检查、确认后安装和自动检查安装三种既有 API 语义。- App4 使用 5 秒检查边界:平台暂时不可达且本地 Bundle 健康时继续进入本地插件,网络异常不被误报为 Bundle 崩溃;真实
szyx/active.bundle已在 Android 模拟器加载成功。 - common 新增停滞请求超时测试,并扩展生命周期/初始化测试覆盖
platformUrl与apiUrl分离;全量pnpm validate再次通过:六个 workspace 类型检查、common 20、bugcollect 5、xwebview 4、IM 3、update CLI/Metro 11 与 release-set 6 项测试全部无回归。
2026-07-20 / 启动壳轻量原生分包入口
@xuqm/rn-update新增公开子路径@xuqm/rn-update/native-bundle,只导出原生 Bundle 状态与路径桥,不加载 AsyncStorage、HTTP、SemVer、整包更新或 release-set 编排。- App4 startup 已改用
NativeBundle.preparePendingRelease()/getLaunchPath();完整UpdateSDK仍只在 app 更新和插件激活阶段加载,不存在第二套状态实现。 - App4 的 startup Android Hermes bytecode 从此前约 2.2 MB 降至约 1.27 MB。该数据只证明启动入口依赖收敛;common/app 动态装载和模拟器交互首屏仍需独立计时,不能只用 startup 文件大小宣称启动性能完成。
packages/update/package.json的 exports、README 与 App4 实际调用已同步。该变更仍是 main 本地源码联调状态,未通过 Jenkins 发布新 alpha,外部项目不得提前写入一个尚不存在的 Nexus 版本号。
2026-07-20 / common 构建期配置解析与 XWebView 权限收口
- App4 冷启动日志证明 common 请求与 app 请求之间曾固定阻塞约 10.6 秒;直接读取原生 Bundle 仅约 1ms。根因是 common 自动初始化在 Hermes 主线程执行 120,000 次纯 JavaScript PBKDF2,而不是 Bundle IO 或 App 页面渲染。
withXuqmConfig()现在使用 Nodecrypto在 Metro 构建期完成 PBKDF2、AES-256-GCM 解密和 Schema 校验,虚拟模块只导出解析后的只读配置。设备端自动初始化不再执行解密;临时网络失败重试复用同一份解析结果,不恢复第二套初始化入口。- App4 重新生成六模块并安装后,common 请求到 app 请求的间隔由约 10.6 秒降至约 405ms;一次 Android 冷启动
Displayed为 783ms。该结果是 API 34 ARM64 软件模拟器观测值,只作为本轮相对回归证据,不替代真机性能验收。 - XWebView 默认权限策略只接受摄像头和麦克风两类已知 WebView 资源,并逐项核对 Android 运行时授权;未知资源明确拒绝。单测覆盖摄像头、麦克风、混合资源、拒绝和未知资源场景。
- common 18 项 TypeScript 测试、2 项 Metro 测试、类型检查,以及 xwebview 4 项测试和类型检查均通过。App4 当前使用相邻
file:源码联调;完成设备 H5 权限闭环后仍需由 Jenkins 发布新 alpha,再恢复精确 Nexus 版本。
2026-07-20 / 多 Bundle 插件注册表单例收口
- App4 内嵌
miniapp设备验证暴露[XuqmRuntime] Plugin did not call definePlugin()。bundle 摘要与内嵌 manifest 完全一致,插件入口也确实调用definePlugin();根因是 app/buz 模块区间隔离后,各自复制的PluginRuntime创建了不同definitionsMap。 - update SDK 将插件定义 Map 拆到轻量
PluginRegistry.ts,并导出@xuqm/rn-update/plugin-registry子路径。宿主 common 入口必须副作用导入该子路径,使 app 与所有 buz 通过共享模块编号读写同一个注册表;不得在 App 内写兼容 Map 或改成全局变量。 - 新增注册、读取、删除和重复定义测试;RNSDK 完整
pnpm validate已通过:common 20、bugcollect 5、xwebview 4、IM 3、update CLI/Metro 11 与 update domain 8 项测试全部通过。 - App4 重建六模块并进入真实“医信课堂”后,注册表错误消失;设备随后进一步暴露并修复两类相同边界缺陷:app/miniapp 重复执行
BVLinearGradient原生 View 注册,以及 miniapp 反向导入 host 后复制UpdateContext。宿主 common 现统一持有跨 Bundle 原生依赖;插件通过 common 更新命令端口调用 host 实现,不再导入宿主 Context,也未增加全局变量兼容层。 - 最终
emulator-5556的 common/app/miniapp 均加载成功,日志无插件注册、重复 View、Context 或 Java/React FATAL;XWebView 容器已显示真实服务标题和 DNS 错误页。该结果只证明多 Bundle 与容器运行时通过,远端 H5 内容及摄像头/麦克风授权仍需网络正常的开发环境设备验收。
2026-07-20 / XWebView 浏览器内核与错误态唯一实现
- 设备 DNS 失败复测发现 Android 系统英文错误页会在
onError后再次触发加载事件,旧实现因此清空自定义错误状态;同时错误分支卸载 WebView,按钮持有的 ref 已为空,重试实际无效。 XWebViewView现在始终保留 WebView,并以白底中文错误层覆盖系统页;刷新、前进、后退和重试统一先清理错误状态再操作同一控制器。错误页不再由原生事件先后顺序随机决定。- 删除
XWebViewScreen内 600 余行重复的 WebView、下载、Bridge、权限和错误处理, 并最终删除该公开入口。全屏页面由XWebViewHost组合统一导航栏、系统返回与XWebViewView;全屏和内嵌场景共享同一个浏览器内核。 - 当时的 xwebview 类型检查与 4 项下载/权限测试、RNSDK 全量门禁和 App4 457 tasks 构建均通过;该历史结果不能替代 1.0.0 当前实现的最终验证。当前 1.0.0 已扩展为 7 项独立测试,Android 运行验证仍待执行。
2026-07-20 / Android 内嵌 Bundle 启动短路
- 审计确认旧
ensureEmbeddedBundle()每次查询模块路径或状态都会先从 APK assets 读取整份 Bundle,再用摘要判断是否需要覆盖;虽然不会每次写盘,但六模块冷启动仍产生无效的大文件读取和摘要对象创建。 - Android 原生模块现将 APK
manifest.json按进程缓存,并先读取本地state.json:下载版本 SemVer 大于等于内嵌版本、原生 baseline/API 等级兼容且记录长度正常时直接加载;APK 自有 embedded 状态则使用 manifest SHA-256 短路,同版本新开发构建仍能正确替换。 - 恢复 API 始终按传入的单个 moduleId 工作,不预装 manifest 中的全部模块。宿主冷启动只请求 common、app;buz 必须在用户进入相应入口后,通过目标插件的检查/安装与
XuqmRuntime.activate()按需恢复和执行。 - 设备清数据复核进一步发现,启动期 app/common 更新检查会收集全部已登记模块版本,而旧
getBundleState()内部错误调用ensureEmbeddedBundle(),导致“查询状态”顺带把三个 buz 全部释放到私有目录。该副作用已删除:状态存在时只读 state,未访问模块从 manifest 构造只读内嵌状态;只有getLaunchBundlePath(moduleId)能触发恢复。 - manifest 新增
byteLength;远程 staging 同步记录 pending/active/rollback 长度。首次安装、本地落后、baseline 不匹配、长度异常或摘要变化时才读取内嵌 Bundle,且写盘前强制校验 manifest SHA-256,再原子恢复 Bundle 与 drawable 资源。 - release-set 规划器新增
NATIVE_BASELINE_INCOMPATIBLE,候选缺失或不匹配当前builtAgainstNativeBaselineId时拒绝安装,避免修改原生依赖后仍向旧完整包发布 JS 插件。 - RNSDK 全量格式、六 workspace TypeScript、common 20、bugcollect 5、xwebview 4、IM 3、update CLI/Metro 11 与 update domain 9 项测试通过;App4 宿主真实执行
:xuqm_rn-update:compileDebugJavaWithJavac,19 tasks 构建成功,完整六模块 Debug APK 457 tasks 构建成功。 emulator-5556覆盖安装后的第一次启动只为旧状态补写activeByteLength等小型元数据,未重写已有 commonactive.bundle;第二次force-stop冷启动前后,common/app 的active.bundle与state.jsonmtime、长度均完全不变,日志确认两者直接从应用私有目录rn-bundles/*/active.bundle装载,common 到 app 请求间隔约 15ms,且无 Java/React FATAL。两次am start -WTotalTime 分别为 1052ms、1085ms,只作为模拟器回归记录;系统首帧耗时不能单独归因于 Bundle 短路,也不替代真机性能验收。- 修复状态查询副作用后重新构建 457 tasks APK,并在
emulator-5556清除数据验证:首次启动私有目录只有rn-bundles/common、rn-bundles/app,不再出现 szyx/miniapp/workbench;第二次冷启动仍只有这两个目录,四个 bundle/state 文件的 mtime 与长度完全一致。两次清数据/二次启动 TotalTime 分别为 1137ms、1028ms,只作为正确性和相对回归记录。
2026-07-20 / 本地原生依赖 baseline 与原生 SemVer 收口
XuqmBundleModule不再内嵌一套 80 余行 SemVer 算法。Android 启动门禁统一调用包内XuqmSemanticVersion;原生单测覆盖 SemVer 官方预发布顺序、构建元数据、超大数字标识和非法旧状态,非法状态固定返回“不可信”并恢复 APK 基线。- 完整包 baseline 原先只记录宿主 Android/iOS 源码和依赖版本;相邻
file:SDK 在版本号未变时修改 Java/Kotlin 会被漏掉。computeNativeBaseline()现在额外哈希每个file:运行时依赖的对应平台原生源码与资源,registry 依赖仍由不可变安装版本标识,不扫描整个node_modules。 - Gradle
prepareXuqmEmbeddedBundles同步把所有file:依赖的 Android/iOS 原生源码、资源、podspec 与 package manifest 声明为输入,并排除 build/.cxx/.gradle/generated。baseline 计算和 Gradle 增量使用同一边界,不再出现脚本认为变化而 Gradle 跳过、或 Gradle 重建但 baseline 不变的分裂状态。 - 新增 Node fixture 证明本地依赖版本不变、只修改原生源码也会改变 Android baseline;RNSDK 全量格式、六 workspace 类型检查与全部测试通过。update CLI/Metro 测试增至 14 项,domain 仍为 9 项。
- App4 刷新本地依赖后,旧 baseline
android-sha256:4567…7501正确触发六模块重建,新 baseline 为android-sha256:eae4…99df;紧接着复跑 998ms,11 tasks 全部UP-TO-DATE。原生 SemVer 单测、update Java 编译与 App4 457 tasks Debug 构建均通过。 - 新 APK 在
emulator-5556不清用户数据覆盖安装后,common/app 状态都原子刷新为 1.0.0、native API 2 和新 baseline;私有目录仍只有 common/app,无 buz,也无 Java/React FATAL。宿主同时运行 DevEco Studio/Harmony 模拟器导致本轮三次冷启动约 2.27–2.47s、fully-drawn 约 3.28–3.55s;该受竞争负载样本只保留为功能回归证据,不覆盖独立性能基准。
2026-07-20 / Android 插件包暂存与存储职责拆分
XuqmBundleModule不再同时承担 RN Bridge、发布事务、ZIP 解压、manifest 校验、摘要和文件系统实现。下载包大小/SHA-256、ZIP 条目与解压上限、manifest/候选版本一致性、Bundle/资源完整性统一归入XuqmPluginPackageStager;桥接模块只编排 stage/activate/confirm/rollback。XuqmBundleStorage成为插件更新原生层文件读取、安全相对路径、SHA-256、原子替换和递归删除的唯一实现;内嵌 Bundle 恢复与远端插件暂存共用同一摘要和写盘语义,没有保留旧私有方法或补丁兼容层。XuqmBundleModule从 1081 行降至 853 行。新增原生单测覆盖标准 SHA-256、目录穿越拒绝、Android 资源路径白名单,并与既有 SemVer 测试一起在 App4 宿主执行:3 个测试类、6 项测试、0 failure/error。- App4 刷新相邻
file:依赖后,原生源码变化按设计触发六模块重建,native baseline 更新为android-sha256:1a95…5cf0;紧接着复跑:app:prepareXuqmEmbeddedBundles为 11 tasks 全部UP-TO-DATE。完整:app:assembleDebug与:xuqm_rn-update:testDebugUnitTest同轮构建成功。
2026-07-20 / Gradle 9.3.1 宿主兼容复核
- update Android 仓库声明已改为 Gradle 9 持续支持的
url = uri(...)赋值形式,不再由 Xuqm 自有脚本产生旧 Groovy property-space assignment warning;不在 SDK 内覆盖宿主 AGP、Kotlin、Gradle 或 React Native 版本。 - App4 按 RN 0.86 官方模板切换到 Gradle 9.3.1 后,真实执行
:xuqm_rn-update:testDebugUnitTest成功,并完成 451 tasks 六模块 Debug APK 构建;原生存储、暂存、SemVer 与 Bridge 拆分均进入宿主编译,不只是独立源码测试。 - 本轮 SDK 定向复核结果:common 21 tests、update CLI/Metro/native-baseline 14 tests、release-set/plugin-registry 9 tests、bugcollect 5 tests、xwebview 4 tests;根工作区及各 package TypeScript、Prettier 和 update 发布包 35 文件校验均通过。App4 完整门禁同步达到 20 suites / 87 tests。
- Gradle 9 构建仍报告的弃用项来自 React Native/三方插件,不通过 SDK 关闭 warning。后续升级必须继续以宿主完整构建和原生单测为门禁,不能只验证 TypeScript 或 npm 打包。
2026-07-27 / Metro Debug 与原生配置统一
- App4 使用 Nexus 精确版本执行
pnpm start+pnpm android时,JS 能通过 Metro 虚拟模块解析 V2 配置,但 Android 原生 common 报告未找到配置。根因是USE_METRO=true同时排除了插件 Bundle 和签名配置 assets,破坏了“一份配置、 JS/原生一次初始化”的契约。 xuqm-bundles.gradle将签名配置复制拆成独立CopyXuqmConfigTask,所有 Android variant 都从宿主唯一src/assets/config/*.xuqmconfig生成assets/config/config.xuqmconfig。Metro Debug 不生成插件 Bundle;Release 或USE_METRO=false才继续执行完整 Bundle/资源任务。- update 定向测试 46 项通过(CLI/打包 28,领域 18),Prettier 通过。尚需 Jenkins 发布新的 update alpha,并在 App4 改用该 Nexus 版本后执行 Android Debug/Release 宿主构建和模拟器日志复核。