feat(common/metro): .xuqmconfig 单点放置——自动同步到原生 Android/iOS

宿主只需在 RN 侧放置一份 .xuqmconfig;构建/运行时 withXuqmConfig 自动比对并
复制到 android assets/config(供 XuqmMergedProvider 自动初始化)及 iOS 资源目录,
缺失或内容不一致才写入(幂等)。免去 RN/Android/iOS 三处分别放置。

Co-Authored-By: Claude <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-06-25 18:45:17 +08:00
父节点 4d5adf447a
当前提交 d51d3c934d

查看文件

@ -58,6 +58,58 @@ function applyBugCollect(metroConfig) {
} }
} }
/** 写入目标文件(仅在缺失或内容不一致时),返回是否发生写入。 */
function syncFile(content, destPath, label) {
try {
if (fs.existsSync(destPath) && fs.readFileSync(destPath, 'utf-8').trim() === content) {
return false;
}
fs.mkdirSync(path.dirname(destPath), { recursive: true });
fs.writeFileSync(destPath, content, 'utf-8');
console.log(`[XuqmConfig] 已同步 .xuqmconfig → ${label}`);
return true;
} catch (e) {
console.warn(`[XuqmConfig] 同步 .xuqmconfig 到 ${label} 失败:${e.message}`);
return false;
}
}
/**
* 单点放置宿主只在 RN 侧放置一份 .xuqmconfig构建/运行时自动同步到
* 原生位置Android assets/config XuqmMergedProvider 自动初始化iOS 资源目录
* 缺失或内容不一致才复制幂等
*/
function syncNativeConfig(projectRoot, content) {
const fileName = 'config.xuqmconfig';
// Android原生 ContentProvider 扫描 assets/config 下的 .xuqmconfig
if (fs.existsSync(path.resolve(projectRoot, 'android'))) {
syncFile(
content,
path.resolve(projectRoot, 'android/app/src/main/assets/config', fileName),
'android assets/config',
);
}
// iOS复制到 app 资源目录(需在 Xcode「Copy Bundle Resources」中引用一次
const iosDir = path.resolve(projectRoot, 'ios');
if (fs.existsSync(iosDir)) {
try {
const appDir = fs
.readdirSync(iosDir, { withFileTypes: true })
.filter(
(d) => d.isDirectory() && fs.existsSync(path.join(iosDir, d.name, 'Info.plist')),
)
.map((d) => d.name)[0];
if (appDir) {
syncFile(content, path.join(iosDir, appDir, 'config', fileName), `ios ${appDir}/config`);
}
} catch {
// 忽略 iOS 同步异常,不阻断打包
}
}
}
function withXuqmConfig(metroConfig) { function withXuqmConfig(metroConfig) {
const projectRoot = metroConfig.projectRoot ?? process.cwd(); const projectRoot = metroConfig.projectRoot ?? process.cwd();
const configFile = findConfigFile(projectRoot); const configFile = findConfigFile(projectRoot);
@ -70,6 +122,9 @@ function withXuqmConfig(metroConfig) {
// 读取加密配置内容 // 读取加密配置内容
const encryptedContent = fs.readFileSync(configFile, 'utf-8').trim(); const encryptedContent = fs.readFileSync(configFile, 'utf-8').trim();
// 单点放置:自动同步到原生 Android/iOS缺失或不一致才复制
syncNativeConfig(projectRoot, encryptedContent);
// 生成临时 TS 文件作为虚拟模块 // 生成临时 TS 文件作为虚拟模块
const tmpDir = path.join(os.tmpdir(), 'xuqm-sdk-config'); const tmpDir = path.join(os.tmpdir(), 'xuqm-sdk-config');
fs.mkdirSync(tmpDir, { recursive: true }); fs.mkdirSync(tmpDir, { recursive: true });