From ea8b35c6823aa8463a5c43e4d435fa578ed055dc Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sun, 18 Oct 2026 14:16:01 -0700 Subject: [PATCH] fix(react-native): keep metadata.android when writing nativescript.react-native.json The config plugin and nativescript-rn configure replaced the whole reactNative.metadata block, so every prebuild or configure run deleted a hand-written metadata.android.include. That list is what keeps classes, including autolinked module packages, in filtered Android release metadata. Merge into the existing metadata instead, accept metadata.android.include in the plugin options, and write the file on Android-only prebuilds too. --- .../plugin/withNativeScriptReactNative.js | 42 ++++++++++++------- .../react-native/test/config-plugin.test.js | 40 ++++++++++++++++++ 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/packages/react-native/plugin/withNativeScriptReactNative.js b/packages/react-native/plugin/withNativeScriptReactNative.js index e74cc5e22..af50bdd00 100644 --- a/packages/react-native/plugin/withNativeScriptReactNative.js +++ b/packages/react-native/plugin/withNativeScriptReactNative.js @@ -17,16 +17,23 @@ function readBoolean(value, fallback) { return typeof value === 'boolean' ? value : fallback; } +function stringList(value) { + return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : undefined; +} + function normalizeMetadataOptions(options = {}) { const metadata = options.metadata || {}; - return { - includePods: Array.isArray(metadata.includePods) - ? metadata.includePods.filter((value) => typeof value === 'string') - : [], - includeSystemFrameworks: Array.isArray(metadata.includeSystemFrameworks) - ? metadata.includeSystemFrameworks.filter((value) => typeof value === 'string') - : [], + const normalized = { + includePods: stringList(metadata.includePods) || [], + includeSystemFrameworks: stringList(metadata.includeSystemFrameworks) || [], }; + // Omitted unless given, so ensureMetadataConfig keeps an `android` block + // written by hand into nativescript.react-native.json. + const androidInclude = stringList(metadata.android && metadata.android.include); + if (androidInclude) { + normalized.android = {include: androidInclude}; + } + return normalized; } function normalizeOptions(options = {}) { @@ -60,11 +67,16 @@ function ensureMetadataConfig(projectRoot, metadataOptions) { } } + const existingReactNative = existing.reactNative || {}; + const existingMetadata = + existingReactNative.metadata && typeof existingReactNative.metadata === 'object' + ? existingReactNative.metadata + : {}; const merged = { ...existing, reactNative: { - ...(existing.reactNative || {}), - metadata: metadataOptions, + ...existingReactNative, + metadata: {...existingMetadata, ...metadataOptions}, }, }; const nextSource = `${JSON.stringify(merged, null, 2)}\n`; @@ -158,13 +170,11 @@ function withNativeScriptMetadata(config, metadataOptions) { return config; } - return withDangerousMod(config, [ - 'ios', - async (modConfig) => { - ensureMetadataConfig(modConfig.modRequest.projectRoot, metadataOptions); - return modConfig; - }, - ]); + const mod = async (modConfig) => { + ensureMetadataConfig(modConfig.modRequest.projectRoot, metadataOptions); + return modConfig; + }; + return withDangerousMod(withDangerousMod(config, ['ios', mod]), ['android', mod]); } /** diff --git a/packages/react-native/test/config-plugin.test.js b/packages/react-native/test/config-plugin.test.js index 3346c0f61..7a4d82a7f 100644 --- a/packages/react-native/test/config-plugin.test.js +++ b/packages/react-native/test/config-plugin.test.js @@ -98,4 +98,44 @@ withTempProject((projectRoot) => { }); }); +withTempProject((projectRoot) => { + const configPath = path.join(projectRoot, 'nativescript.react-native.json'); + fs.writeFileSync( + configPath, + JSON.stringify({ + reactNative: { + metadata: { + includePods: ['StalePod'], + android: {include: ['com.example.Worker']}, + }, + }, + }), + ); + ensureMetadataConfig(projectRoot, normalizeMetadataOptions({})); + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + assert.deepStrictEqual(config.reactNative.metadata, { + includePods: [], + includeSystemFrameworks: [], + android: {include: ['com.example.Worker']}, + }); +}); + +withTempProject((projectRoot) => { + const configPath = path.join(projectRoot, 'nativescript.react-native.json'); + fs.writeFileSync( + configPath, + JSON.stringify({reactNative: {metadata: {android: {include: ['com.example.Old']}}}}), + ); + ensureMetadataConfig( + projectRoot, + normalizeMetadataOptions({ + metadata: {android: {include: ['com.example.Worker', 7, 'com.example.views.*']}}, + }), + ); + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + assert.deepStrictEqual(config.reactNative.metadata.android, { + include: ['com.example.Worker', 'com.example.views.*'], + }); +}); + console.log('config plugin tests passed');