diff --git a/plugins/withWebRTCFrameworkFix.js b/plugins/withWebRTCFrameworkFix.js index be2645b..81bc27e 100644 --- a/plugins/withWebRTCFrameworkFix.js +++ b/plugins/withWebRTCFrameworkFix.js @@ -3,16 +3,15 @@ const fs = require('fs'); const path = require('path'); /** - * Config plugin that patches the Podfile to allow non-modular header includes - * inside framework modules for all pod targets. + * Config plugin that patches the Podfile for Xcode 26+ compatibility with + * use_frameworks! :linkage => :static (required by @react-native-firebase). * - * Fixes Xcode 26+ build errors like: - * include of non-modular header inside framework module 'RNFBApp.RNFBAppModule' - * [-Werror,-Wnon-modular-include-in-framework-module] - * - * Several pods (livekit-react-native-webrtc, @react-native-firebase, etc.) - * import React Native headers inside their framework modules, which Xcode 26 - * treats as an error. This relaxes that check for all pod targets. + * Fixes two classes of errors: + * 1. "include of non-modular header inside framework module" — sets + * CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES for all pods. + * 2. "declaration of 'X' must be imported from module 'Y' before it is required" + * — adds use_modular_headers! so #import statements resolve correctly across + * framework module boundaries. */ const withWebRTCFrameworkFix = (config) => { return withDangerousMod(config, [ @@ -21,12 +20,22 @@ const withWebRTCFrameworkFix = (config) => { const podfilePath = path.join(config.modRequest.platformProjectRoot, 'Podfile'); let contents = fs.readFileSync(podfilePath, 'utf-8'); - const marker = 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'; - if (contents.includes(marker)) { - return config; + // 1. Add use_modular_headers! after use_frameworks! if not already present. + if (!contents.includes('use_modular_headers!')) { + const useFrameworksPattern = /use_frameworks!.*\n/g; + const allMatches = [...contents.matchAll(useFrameworksPattern)]; + if (allMatches.length > 0) { + const lastMatch = allMatches[allMatches.length - 1]; + const lastIdx = lastMatch.index + lastMatch[0].length; + contents = + contents.slice(0, lastIdx) + 'use_modular_headers!\n' + contents.slice(lastIdx); + } } - const hook = ` + // 2. Add CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES to post_install. + const marker = 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'; + if (!contents.includes(marker)) { + const hook = ` # Fix non-modular header includes for Xcode 26+ # Pods like livekit-react-native-webrtc and @react-native-firebase import # React Native headers inside their framework modules, which Xcode 26 @@ -37,38 +46,36 @@ const withWebRTCFrameworkFix = (config) => { end end`; - // Insert after the react_native_post_install call, which is the last - // significant line inside the post_install block. - const anchor = 'react_native_post_install('; - const anchorIdx = contents.lastIndexOf(anchor); - if (anchorIdx === -1) { - throw new Error('[withWebRTCFrameworkFix] Could not find react_native_post_install in Podfile'); - } + const anchor = 'react_native_post_install('; + const anchorIdx = contents.lastIndexOf(anchor); + if (anchorIdx === -1) { + throw new Error('[withWebRTCFrameworkFix] Could not find react_native_post_install in Podfile'); + } - // Find the closing `)` of the react_native_post_install call (may span multiple lines). - let depth = 0; - let insertAfter = anchorIdx; - for (let i = anchorIdx; i < contents.length; i++) { - if (contents[i] === '(') depth++; - if (contents[i] === ')') { - depth--; - if (depth === 0) { - insertAfter = i + 1; - break; + let depth = 0; + let insertAfter = anchorIdx; + for (let i = anchorIdx; i < contents.length; i++) { + if (contents[i] === '(') depth++; + if (contents[i] === ')') { + depth--; + if (depth === 0) { + insertAfter = i + 1; + break; + } } } - } - if (insertAfter === anchorIdx || depth !== 0) { - throw new Error( - '[withWebRTCFrameworkFix] Unclosed parenthesis in react_native_post_install call — ' + - 'could not locate closing ")". Aborting to avoid corrupting the Podfile.' - ); + if (insertAfter === anchorIdx || depth !== 0) { + throw new Error( + '[withWebRTCFrameworkFix] Unclosed parenthesis in react_native_post_install call — ' + + 'could not locate closing ")". Aborting to avoid corrupting the Podfile.' + ); + } + + contents = contents.slice(0, insertAfter) + hook + contents.slice(insertAfter); } - contents = contents.slice(0, insertAfter) + hook + contents.slice(insertAfter); fs.writeFileSync(podfilePath, contents); - return config; }, ]);