Fix package exclusion by moving App Clip target to top level#84
Fix package exclusion by moving App Clip target to top level#84trentrand wants to merge 3 commits intobndkt:mainfrom
Conversation
Previously, the App Clip target was generated nested inside the main app target in the Podfile. This caused it to inherit all pods from the parent, rendering `excludedPackages` completely ineffective. This change moves the App Clip target to the top level as a sibling of the main target, preventing implicit dependency inheritance. However, even with the target un-nested, CocoaPods still emits linker flags for all resolved pods into the generated `.xcconfig` files. This is especially problematic under new architecture + static frameworks, where Codegen headers are expected to exist for any linked package — causing "file not found" build failures. To address this, a `post_install` hook is injected that: 1. Removes excluded packages from the App Clip target's dependency graph 2. Strips all corresponding linker flags (`-l"Pkg"`, `-framework "Pkg"`) directly from the generated xcconfig files via `Xcodeproj::Config` This two-pronged approach ensures excluded packages are absent from both the build graph and the linker invocation, regardless of project settings. Fixes bndkt#81, bndkt#79
|
@nathan-ahn, one last change (hopefully) to the package to fix the This one fixes @changhwan0813's issue #81 and my own #71. Both are essentially the same issue. A lot of the line changes are just indentation to get the resulting Podfile correctly formatted, so make sure to turn on 'Hide whitespace': Without this change, on version 0.7.1, using |
There was a problem hiding this comment.
Pull request overview
This PR updates the Expo config plugin’s Podfile generation to make the App Clip target a top-level sibling (so excludedPackages can take effect) and adds a post_install patch intended to remove excluded pods and strip their linker flags from generated .xcconfig files.
Changes:
- Move the generated App Clip
target ... doblock to be inserted at the Podfile top level (anchored afterprepare_react_native_project!), avoiding nested-target pod inheritance. - Add a
post_installinjection that attempts to remove excluded dependencies from the App Clip Pods target and strip matching entries fromOTHER_LDFLAGSin xcconfig files. - Adjust the App Clip autolinking command and related Podfile generation logic.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # \`react-native-app-clip\` resolves to react-native-app-clip/build/index.js | ||
| clip_command = [ | ||
| 'node', | ||
| '--no-warnings', | ||
| '--eval', | ||
| 'require(require.resolve(\\'react-native-app-clip\\')+\\'/../../plugin/build/cliPlugin.js\\').run(' + json + ', [])' | ||
| ] |
There was a problem hiding this comment.
clip_command now calls cliPlugin.run(..., []), which prevents cliPlugin.ts from deleting excluded packages from the autolinking config (it deletes keys based on the exclude array). This looks like a regression: excludedPackages will no longer be excluded from use_native_modules! resolution for the App Clip target. Pass the actual excluded package list through to the CLI plugin again (and ensure it stays in sync with excludedPackages).
There was a problem hiding this comment.
Passing the exclude list to cliPlugin is what originally caused #79 — when excluded from use_native_modules!, Codegen does not generate spec headers for those packages, but the pod source files still #import them (e.g. NativeNfcManagerSpec.h), causing a compile failure under New Architecture. The [] is intentional: we keep packages in the autolinking config so Codegen generates their specs, then strip them from the linker in post_install. This is the two-pronged approach described in the PR.
…esting) Once the App Clip target is a sibling rather than nested inside the main target, `use_expo_modules!(exclude:)` fully prevents excluded packages from being installed or linked. The `post_install` hook that manually stripped OTHER_LDFLAGS was compensating for inherited linker flags that no longer exist.
|
@trentrand The theory here makes sense at an initial glance. It'll take me a bit to do some testing to ensure there's no regressions here. Considering the significant restructuring of the targets, I worry there may be some niche regressions. I'm going to do some local testing first today, then I'll create a beta version to use this in production over the next week. |
There was a problem hiding this comment.
From my local testing, seems to be working! Here's what I've tried:
- Clip builds and runs on simulator
- Excluding a required native package (
expo-image) causes the Clip to break (as expected)
Just one comment for a cleaner Podfile for future maintainability. Once that's sorted, I'll merge this into a beta version branch and start testing in TestFlight and production.
| ); | ||
| } | ||
|
|
||
| podfileContent = mergeContents({ |
There was a problem hiding this comment.
Now that the App Clip target is a sibling, can we move it to the end of the Podfile rather than being above the main app? This'll be easier for future maintainability in case the anchor disappears in a future Expo version (and remove the requirement for Expo 53+ project structure). We use this approach in react-native-widget-extension and it works quite well for sibling targets.


Previously, the App Clip target was generated nested inside the main app
target in the Podfile. CocoaPods treats nested targets as inheriting all
pods from their parent, which caused
excludedPackagesto be completelyineffective — excluded packages were still installed and linked.
This change moves the App Clip target to the top level as a sibling of the
main target. With no dependency inheritance,
use_expo_modules!(exclude:)works correctly and excluded packages are fully absent from the App Clip
build.
Also clarifies in the README that
excludedPackagestakes npm package names.Fixes #81, #79