fix(update): embed signed config in Metro debug
这个提交包含在:
父节点
198574546b
当前提交
78721ee2f0
@ -449,3 +449,17 @@ pnpm --dir packages/update test
|
||||
- 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
|
||||
宿主构建和模拟器日志复核。
|
||||
|
||||
@ -40,10 +40,6 @@ abstract class GenerateXuqmBundlesTask extends DefaultTask {
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract RegularFileProperty getPackageFile()
|
||||
|
||||
@InputFile
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract RegularFileProperty getSignedConfigFile()
|
||||
|
||||
/**
|
||||
* RN/原生源码与打包配置共同决定 bundle、资源和 native baseline。
|
||||
* 显式建模后 Gradle 才能安全复用上次输出,禁止用永久 out-of-date 代替依赖声明。
|
||||
@ -92,12 +88,6 @@ abstract class GenerateXuqmBundlesTask extends DefaultTask {
|
||||
appVersion.get(),
|
||||
)
|
||||
}.assertNormalExitValue()
|
||||
project.copy {
|
||||
from(signedConfigFile.get().asFile)
|
||||
into(assetsOutputDirectory.get().dir("config"))
|
||||
rename { "config.xuqmconfig" }
|
||||
}
|
||||
|
||||
// Android 内嵌 Bundle 通过 AssetManager 读取,但 require() 图片必须同时进入
|
||||
// aapt2 的 drawable 资源表。只把 drawable-* 放进 assets 会导致图片静默为空。
|
||||
project.delete(resources)
|
||||
@ -112,6 +102,31 @@ abstract class GenerateXuqmBundlesTask extends DefaultTask {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有变体都只复制同一份签名配置。Debug 使用 Metro 时不得生成插件 Bundle,
|
||||
* 但 Android 原生 SDK 仍必须从 assets 完成与 JS 相同的一次自动初始化。
|
||||
*/
|
||||
@DisableCachingByDefault(because = "Signed config is a small immutable build input")
|
||||
abstract class CopyXuqmConfigTask extends DefaultTask {
|
||||
@InputFile
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract RegularFileProperty getSignedConfigFile()
|
||||
|
||||
@OutputDirectory
|
||||
abstract DirectoryProperty getAssetsOutputDirectory()
|
||||
|
||||
@TaskAction
|
||||
void copyConfig() {
|
||||
def output = assetsOutputDirectory.get().asFile
|
||||
project.delete(output)
|
||||
project.copy {
|
||||
from(signedConfigFile.get().asFile)
|
||||
into(new File(output, "config"))
|
||||
rename { "config.xuqmconfig" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!plugins.hasPlugin("com.android.application")) {
|
||||
throw new GradleException("xuqm-bundles.gradle must be applied to an Android application module")
|
||||
}
|
||||
@ -165,11 +180,6 @@ def prepareXuqmBundles = tasks.register(
|
||||
cliFile.set(new File(xuqmProjectRoot, "node_modules/@xuqm/rn-update/scripts/xuqm-rn.mjs"))
|
||||
configFile.set(new File(xuqmProjectRoot, "xuqm.modules.json"))
|
||||
packageFile.set(new File(xuqmProjectRoot, "package.json"))
|
||||
signedConfigFile.set(
|
||||
xuqmSignedConfigCandidates
|
||||
? xuqmSignedConfigCandidates.first()
|
||||
: new File(xuqmSignedConfigDirectory, "config.xuqmconfig")
|
||||
)
|
||||
sourceFiles.from(project.fileTree(xuqmProjectRoot) {
|
||||
include("src/**")
|
||||
include("assets/**")
|
||||
@ -223,7 +233,25 @@ def prepareXuqmBundles = tasks.register(
|
||||
resourcesOutputDirectory.set(layout.buildDirectory.dir("generated/xuqm/res"))
|
||||
}
|
||||
|
||||
def prepareXuqmConfig = tasks.register(
|
||||
"prepareXuqmConfigAssets",
|
||||
CopyXuqmConfigTask,
|
||||
) {
|
||||
group = "xuqm"
|
||||
description = "Copies the single signed Xuqm config into Android assets."
|
||||
signedConfigFile.set(
|
||||
xuqmSignedConfigCandidates
|
||||
? xuqmSignedConfigCandidates.first()
|
||||
: new File(xuqmSignedConfigDirectory, "config.xuqmconfig")
|
||||
)
|
||||
assetsOutputDirectory.set(layout.buildDirectory.dir("generated/xuqm/config-assets"))
|
||||
}
|
||||
|
||||
androidComponents.onVariants(androidComponents.selector().all()) { variant ->
|
||||
variant.sources.assets?.addGeneratedSourceDirectory(
|
||||
prepareXuqmConfig,
|
||||
{ task -> task.assetsOutputDirectory },
|
||||
)
|
||||
if (variant.buildType == "release" || !xuqmUseMetro.get()) {
|
||||
variant.sources.assets?.addGeneratedSourceDirectory(
|
||||
prepareXuqmBundles,
|
||||
|
||||
@ -31,6 +31,16 @@ test('Gradle models and forwards the exact embedded release identity', () => {
|
||||
assert.match(gradle, /@Input\s+abstract Property<String> getBugCollectMode\(\)/)
|
||||
assert.match(gradle, /environment\("XUQM_BUILD_ID", buildId\.get\(\)\)/)
|
||||
assert.match(gradle, /environment\("XUQM_BUGCOLLECT_MODE", bugCollectMode\.get\(\)\)/)
|
||||
assert.match(gradle, /abstract class CopyXuqmConfigTask extends DefaultTask/)
|
||||
assert.match(
|
||||
gradle,
|
||||
/variant\.sources\.assets\?\.addGeneratedSourceDirectory\(\s*prepareXuqmConfig/,
|
||||
)
|
||||
const bundleTask = gradle.slice(
|
||||
gradle.indexOf('abstract class GenerateXuqmBundlesTask'),
|
||||
gradle.indexOf('abstract class CopyXuqmConfigTask'),
|
||||
)
|
||||
assert.doesNotMatch(bundleTask, /getSignedConfigFile\(\)/)
|
||||
})
|
||||
|
||||
test('embed creates a complete versioned manifest from a host fixture', () => {
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户