From 1d2ca67104bb0a07029f249f84d0147a2a0c4ce2 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 26 Aug 2026 14:08:38 +0200 Subject: [PATCH 1/5] fix(ios): Force-load the Sentry static archive to keep ObjC category methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RN links sentry-cocoa as a prebuilt static xcframework with no whole-archive linker flag. Objective-C category methods (Swift `@objc extension`s, e.g. `SentryReplayNetworkDetails+Capture` in cocoa 9.25/9.26) are therefore dead-stripped at the app's final link and crash at runtime with `unrecognized selector`. Add per-SDK `-force_load` of the Sentry binary to `user_target_xcconfig` (the app target, where the stripping link happens). Scoped to the Sentry archive — unlike whole-link `-ObjC`/`-all_load` — and, unlike `-ObjC`, also retains Swift-only metadata, so it hardens against future valid-but-strippable upstream changes rather than only the current category case. Apple QA1490 documents category stripping as the consumer's responsibility. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 1 + packages/core/RNSentry.podspec | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2637f4883b..ef1d9af4ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Fixes +- Fix iOS `unrecognized selector` crash when Session Replay captures network request/response details, caused by Objective-C category methods in the Sentry static framework being stripped at link time ([#6615](https://github.com/getsentry/sentry-react-native/pull/6615)) - Fix time to display spans causing transactions to be dropped by Relay ([#6608](https://github.com/getsentry/sentry-react-native/pull/6608)) - Fix Expo iOS build failing when the project path contains spaces ([#6604](https://github.com/getsentry/sentry-react-native/pull/6604)) - Fix Android fragment memory leak in `RNSentryReactFragmentLifecycleTracer` ([#6599](https://github.com/getsentry/sentry-react-native/pull/6599)) diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index bc48e15f9c..7979f613d1 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -150,8 +150,34 @@ Pod::Spec.new do |s| acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ') end + # Force-load the whole Sentry static archive on the *app* link. We link + # Sentry statically (see the `vendored_frameworks` note above) with no + # whole-archive flag, so any symbol reachable only through an Objective-C + # category — a Swift `@objc extension`, e.g. + # `SentryReplayNetworkDetails+Capture` in sentry-cocoa 9.25/9.26 + # (getsentry/sentry-react-native#6609) — or through Swift-only metadata is + # dead-stripped at the final link and crashes at runtime with + # "unrecognized selector". Apple documents this as the *consumer's* + # responsibility (QA1490: https://developer.apple.com/library/archive/qa/qa1490/_index.html). + # + # `-force_load` on the Sentry binary is preferred over `-ObjC`/`-all_load`: + # it is scoped to the Sentry archive (those flags force-load every static + # lib in the app — size bloat + duplicate-symbol risk), and, unlike + # `-ObjC`, it also retains Swift-only metadata. So this hardens us against + # future valid-but-strippable upstream changes, not only the current + # category case — independent of any producer-side fix in sentry-cocoa. + # + # Lives on `user_target_xcconfig` (the app target) because that is where + # the link that strips happens; `pod_target_xcconfig` would be too early. + force_load_flags = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| + loads = slice_ids.map do |slice| + %(-force_load "#{File.join(sentry_xcframework_ref, slice, 'Sentry.framework', 'Sentry')}") + end + acc["OTHER_LDFLAGS[sdk=#{sdk}*]"] = (['$(inherited)'] + loads).join(' ') + end + pod_target_xcconfig.merge!(xcframework_search_paths) - s.user_target_xcconfig = xcframework_search_paths + s.user_target_xcconfig = xcframework_search_paths.merge(force_load_flags) else raise <<~MSG [Sentry] SENTRY_USE_XCFRAMEWORK=0 is no longer supported. From 8c1a078f37c318ce06ab897c42f3855f68ba6822 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 26 Aug 2026 14:51:54 +0200 Subject: [PATCH 2/5] fix(ios): Place Sentry -force_load on the target whose link strips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under `use_frameworks! :linkage => :dynamic`, `@import Sentry` pulls the static Sentry archive into the RNSentry dylib, so RNSentry's own link is what dead-strips the `SentryReplayNetworkDetails+Capture` ObjC category — not the app link. Placing `-force_load` only on `user_target_xcconfig` missed that link, and additionally risked forcing a second copy of Sentry into the app binary (duplicate ObjC classes, two SentrySDK singletons). Detect linkage via `ENV['USE_FRAMEWORKS']` (the signal RN's Podfile setup and our samples already use) and put `-force_load` on exactly one target: `pod_target_xcconfig` (RNSentry dylib link) for dynamic, otherwise `user_target_xcconfig` (app link) for the static default. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 1 - packages/core/RNSentry.podspec | 43 +++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1d9af4ee..2637f4883b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,6 @@ ### Fixes -- Fix iOS `unrecognized selector` crash when Session Replay captures network request/response details, caused by Objective-C category methods in the Sentry static framework being stripped at link time ([#6615](https://github.com/getsentry/sentry-react-native/pull/6615)) - Fix time to display spans causing transactions to be dropped by Relay ([#6608](https://github.com/getsentry/sentry-react-native/pull/6608)) - Fix Expo iOS build failing when the project path contains spaces ([#6604](https://github.com/getsentry/sentry-react-native/pull/6604)) - Fix Android fragment memory leak in `RNSentryReactFragmentLifecycleTracer` ([#6599](https://github.com/getsentry/sentry-react-native/pull/6599)) diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 7979f613d1..89fa1b1aec 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -150,25 +150,24 @@ Pod::Spec.new do |s| acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ') end - # Force-load the whole Sentry static archive on the *app* link. We link - # Sentry statically (see the `vendored_frameworks` note above) with no - # whole-archive flag, so any symbol reachable only through an Objective-C - # category — a Swift `@objc extension`, e.g. - # `SentryReplayNetworkDetails+Capture` in sentry-cocoa 9.25/9.26 - # (getsentry/sentry-react-native#6609) — or through Swift-only metadata is - # dead-stripped at the final link and crashes at runtime with - # "unrecognized selector". Apple documents this as the *consumer's* - # responsibility (QA1490: https://developer.apple.com/library/archive/qa/qa1490/_index.html). + # Force-load the Sentry static archive so its ObjC category methods survive + # linking. We link Sentry statically with no whole-archive flag, so symbols + # reachable only through an ObjC category (what a Swift `@objc extension` + # compiles to, e.g. `SentryReplayNetworkDetails+Capture` in sentry-cocoa + # 9.25/9.26, #6609) or through Swift-only metadata get dead-stripped and + # crash at runtime with "unrecognized selector" — the consumer's job to fix + # at link time, per Apple QA1490 + # (https://developer.apple.com/library/archive/qa/qa1490/_index.html). + # `-force_load` beats `-ObjC`/`-all_load`: it is scoped to Sentry and also + # keeps Swift-only metadata, guarding against future strippable upstream + # changes, not just today's category. # - # `-force_load` on the Sentry binary is preferred over `-ObjC`/`-all_load`: - # it is scoped to the Sentry archive (those flags force-load every static - # lib in the app — size bloat + duplicate-symbol risk), and, unlike - # `-ObjC`, it also retains Swift-only metadata. So this hardens us against - # future valid-but-strippable upstream changes, not only the current - # category case — independent of any producer-side fix in sentry-cocoa. - # - # Lives on `user_target_xcconfig` (the app target) because that is where - # the link that strips happens; `pod_target_xcconfig` would be too early. + # The flag must ride whichever target's link does the stripping, which + # depends on linkage: static libs (the default) absorb Sentry into the app + # binary → app link → `user_target_xcconfig`; `:linkage => :dynamic` absorbs + # it into the RNSentry dylib → that link → `pod_target_xcconfig`. Never + # both, or a second copy of Sentry lands in the app. Detected via + # `ENV['USE_FRAMEWORKS']`. force_load_flags = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| loads = slice_ids.map do |slice| %(-force_load "#{File.join(sentry_xcframework_ref, slice, 'Sentry.framework', 'Sentry')}") @@ -177,7 +176,13 @@ Pod::Spec.new do |s| end pod_target_xcconfig.merge!(xcframework_search_paths) - s.user_target_xcconfig = xcframework_search_paths.merge(force_load_flags) + user_target_xcconfig = xcframework_search_paths.dup + if ENV['USE_FRAMEWORKS'] == 'dynamic' + pod_target_xcconfig.merge!(force_load_flags) + else + user_target_xcconfig.merge!(force_load_flags) + end + s.user_target_xcconfig = user_target_xcconfig else raise <<~MSG [Sentry] SENTRY_USE_XCFRAMEWORK=0 is no longer supported. From dc780c5a6fb03a99e34d3804ea919c61fb880133 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 27 Aug 2026 11:24:25 +0200 Subject: [PATCH 3/5] fix(ios): Use -ObjC instead of -force_load for Sentry categories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the link-time fix for the stripped `SentryReplayNetworkDetails` ObjC category from `-force_load ` to `-ObjC`: - `-ObjC` names no archive, so it only affects static libs actually in the current link — the same flag is correct on both the app target (static linkage) and the RNSentry pod target (dynamic linkage) with no risk of pulling a second copy of Sentry into the app. This removes the need to detect linkage via `ENV['USE_FRAMEWORKS']`, closing the gap where a bare `use_frameworks!` (env var unset) mis-placed the flag. - It is Apple's documented fix for this exact problem (QA1490). - It only retains ObjC class/category objects (not the whole archive) and needs no per-slice binary paths, simplifying the podspec. Co-Authored-By: Claude Opus 4.8 --- packages/core/RNSentry.podspec | 46 ++++++++++------------------------ 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 89fa1b1aec..56049c48e8 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -150,39 +150,19 @@ Pod::Spec.new do |s| acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ') end - # Force-load the Sentry static archive so its ObjC category methods survive - # linking. We link Sentry statically with no whole-archive flag, so symbols - # reachable only through an ObjC category (what a Swift `@objc extension` - # compiles to, e.g. `SentryReplayNetworkDetails+Capture` in sentry-cocoa - # 9.25/9.26, #6609) or through Swift-only metadata get dead-stripped and - # crash at runtime with "unrecognized selector" — the consumer's job to fix - # at link time, per Apple QA1490 - # (https://developer.apple.com/library/archive/qa/qa1490/_index.html). - # `-force_load` beats `-ObjC`/`-all_load`: it is scoped to Sentry and also - # keeps Swift-only metadata, guarding against future strippable upstream - # changes, not just today's category. - # - # The flag must ride whichever target's link does the stripping, which - # depends on linkage: static libs (the default) absorb Sentry into the app - # binary → app link → `user_target_xcconfig`; `:linkage => :dynamic` absorbs - # it into the RNSentry dylib → that link → `pod_target_xcconfig`. Never - # both, or a second copy of Sentry lands in the app. Detected via - # `ENV['USE_FRAMEWORKS']`. - force_load_flags = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| - loads = slice_ids.map do |slice| - %(-force_load "#{File.join(sentry_xcframework_ref, slice, 'Sentry.framework', 'Sentry')}") - end - acc["OTHER_LDFLAGS[sdk=#{sdk}*]"] = (['$(inherited)'] + loads).join(' ') - end - - pod_target_xcconfig.merge!(xcframework_search_paths) - user_target_xcconfig = xcframework_search_paths.dup - if ENV['USE_FRAMEWORKS'] == 'dynamic' - pod_target_xcconfig.merge!(force_load_flags) - else - user_target_xcconfig.merge!(force_load_flags) - end - s.user_target_xcconfig = user_target_xcconfig + # Keep Sentry's ObjC category methods from being dead-stripped at link. + # We link Sentry statically with no whole-archive flag, so a method living + # only in an ObjC category (what a Swift `@objc extension` compiles to, e.g. + # `SentryReplayNetworkDetails+Capture` in sentry-cocoa 9.25/9.26, #6609) is + # dropped and crashes at runtime with "unrecognized selector". `-ObjC` is + # Apple's documented fix (QA1490). Unlike `-force_load` it names no archive + # — it only affects static libs in the current link — so the same flag is + # safe on both targets whatever the linkage (app link under static, RNSentry + # dylib link under dynamic), pulling no second Sentry copy and needing no + # linkage detection. + objc_ldflags = { 'OTHER_LDFLAGS' => '$(inherited) -ObjC' } + pod_target_xcconfig.merge!(xcframework_search_paths).merge!(objc_ldflags) + s.user_target_xcconfig = xcframework_search_paths.merge(objc_ldflags) else raise <<~MSG [Sentry] SENTRY_USE_XCFRAMEWORK=0 is no longer supported. From d082a3af0ea6dbf5d0c8cfa3ed2b57856c0e7301 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 27 Aug 2026 12:41:11 +0200 Subject: [PATCH 4/5] fix(ios): Revert to -force_load for Sentry categories (-ObjC regressed) The -ObjC swap (dc780c5a) regressed the "Test ios production REV2" job: captureSpaceflightNewsScreenTransaction fails with the #6609 crash ("No visible element found: Load More Articles") because the app crashes on the replay network-detail path. -force_load (8c1a078f) passes the same test (19/19). Verified directly from CI logs of both runs. Root cause confirmed against the checksum-verified released 9.26.0 slice: -setRequestWithSize:bodyData:contentType:allHeaders:configuredHeaders: lives only in the category-only object SentryReplayNetworkDetails+Capture.o (no class of its own), so a plain static link dead-strips it. -force_load loads the whole archive unconditionally; -ObjC does not rescue it in the real production build. Co-Authored-By: Claude Opus 4.8 --- packages/core/RNSentry.podspec | 46 ++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 56049c48e8..89fa1b1aec 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -150,19 +150,39 @@ Pod::Spec.new do |s| acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ') end - # Keep Sentry's ObjC category methods from being dead-stripped at link. - # We link Sentry statically with no whole-archive flag, so a method living - # only in an ObjC category (what a Swift `@objc extension` compiles to, e.g. - # `SentryReplayNetworkDetails+Capture` in sentry-cocoa 9.25/9.26, #6609) is - # dropped and crashes at runtime with "unrecognized selector". `-ObjC` is - # Apple's documented fix (QA1490). Unlike `-force_load` it names no archive - # — it only affects static libs in the current link — so the same flag is - # safe on both targets whatever the linkage (app link under static, RNSentry - # dylib link under dynamic), pulling no second Sentry copy and needing no - # linkage detection. - objc_ldflags = { 'OTHER_LDFLAGS' => '$(inherited) -ObjC' } - pod_target_xcconfig.merge!(xcframework_search_paths).merge!(objc_ldflags) - s.user_target_xcconfig = xcframework_search_paths.merge(objc_ldflags) + # Force-load the Sentry static archive so its ObjC category methods survive + # linking. We link Sentry statically with no whole-archive flag, so symbols + # reachable only through an ObjC category (what a Swift `@objc extension` + # compiles to, e.g. `SentryReplayNetworkDetails+Capture` in sentry-cocoa + # 9.25/9.26, #6609) or through Swift-only metadata get dead-stripped and + # crash at runtime with "unrecognized selector" — the consumer's job to fix + # at link time, per Apple QA1490 + # (https://developer.apple.com/library/archive/qa/qa1490/_index.html). + # `-force_load` beats `-ObjC`/`-all_load`: it is scoped to Sentry and also + # keeps Swift-only metadata, guarding against future strippable upstream + # changes, not just today's category. + # + # The flag must ride whichever target's link does the stripping, which + # depends on linkage: static libs (the default) absorb Sentry into the app + # binary → app link → `user_target_xcconfig`; `:linkage => :dynamic` absorbs + # it into the RNSentry dylib → that link → `pod_target_xcconfig`. Never + # both, or a second copy of Sentry lands in the app. Detected via + # `ENV['USE_FRAMEWORKS']`. + force_load_flags = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| + loads = slice_ids.map do |slice| + %(-force_load "#{File.join(sentry_xcframework_ref, slice, 'Sentry.framework', 'Sentry')}") + end + acc["OTHER_LDFLAGS[sdk=#{sdk}*]"] = (['$(inherited)'] + loads).join(' ') + end + + pod_target_xcconfig.merge!(xcframework_search_paths) + user_target_xcconfig = xcframework_search_paths.dup + if ENV['USE_FRAMEWORKS'] == 'dynamic' + pod_target_xcconfig.merge!(force_load_flags) + else + user_target_xcconfig.merge!(force_load_flags) + end + s.user_target_xcconfig = user_target_xcconfig else raise <<~MSG [Sentry] SENTRY_USE_XCFRAMEWORK=0 is no longer supported. From 2a2fb0d24c4eb92f31c9c57c7b9b5301bf39f6e8 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 27 Aug 2026 12:55:50 +0200 Subject: [PATCH 5/5] fix(ios): Detect dynamic linkage from the Podfile when USE_FRAMEWORKS is unset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `-force_load` flag for the Sentry static archive must ride whichever target's link does the ObjC-category stripping: the app link under static linkage (`user_target_xcconfig`), or the RNSentry dylib link under dynamic frameworks (`pod_target_xcconfig`). Previously this was decided solely by `ENV['USE_FRAMEWORKS'] == 'dynamic'`. CocoaPods does not export that env var for a bare `use_frameworks!` / `use_frameworks! :linkage => :dynamic` in a consumer's Podfile, so such a setup wrongly took the static path — force-loading Sentry into the app while RNSentry is really a dylib (a second Sentry copy in the app, and the framework link still strips the replay category, #6609). Add `sentry_uses_dynamic_linkage`: honor `USE_FRAMEWORKS` as an explicit override when set, otherwise read the declared linkage off the Podfile CocoaPods has already loaded. Behavior is unchanged for this repo's CI and both samples (which set the env var, or don't use frameworks at all); it only newly covers the bare-`use_frameworks!` consumer that the env-only check missed. Falls back to the static default outside a real `pod install` (`pod ipc spec`, `pod lib lint`), where no Podfile is available. Co-Authored-By: Claude Opus 4.8 --- packages/core/RNSentry.podspec | 12 ++++++--- packages/core/scripts/sentry_utils.rb | 37 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 89fa1b1aec..ffa9b28346 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -164,10 +164,14 @@ Pod::Spec.new do |s| # # The flag must ride whichever target's link does the stripping, which # depends on linkage: static libs (the default) absorb Sentry into the app - # binary → app link → `user_target_xcconfig`; `:linkage => :dynamic` absorbs + # binary → app link → `user_target_xcconfig`; a dynamic framework absorbs # it into the RNSentry dylib → that link → `pod_target_xcconfig`. Never - # both, or a second copy of Sentry lands in the app. Detected via - # `ENV['USE_FRAMEWORKS']`. + # both, or a second copy of Sentry lands in the app. + # + # Linkage is resolved by `sentry_uses_dynamic_linkage` (see sentry_utils): + # `ENV['USE_FRAMEWORKS']` when set (this repo's CI + the RN/Expo samples), + # otherwise read off the consumer's Podfile so a bare `use_frameworks!` + # without that env var still lands on the right target. force_load_flags = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| loads = slice_ids.map do |slice| %(-force_load "#{File.join(sentry_xcframework_ref, slice, 'Sentry.framework', 'Sentry')}") @@ -177,7 +181,7 @@ Pod::Spec.new do |s| pod_target_xcconfig.merge!(xcframework_search_paths) user_target_xcconfig = xcframework_search_paths.dup - if ENV['USE_FRAMEWORKS'] == 'dynamic' + if sentry_uses_dynamic_linkage pod_target_xcconfig.merge!(force_load_flags) else user_target_xcconfig.merge!(force_load_flags) diff --git a/packages/core/scripts/sentry_utils.rb b/packages/core/scripts/sentry_utils.rb index 32c430acdc..a1a8e59b64 100644 --- a/packages/core/scripts/sentry_utils.rb +++ b/packages/core/scripts/sentry_utils.rb @@ -233,3 +233,40 @@ def stage_sentry_xcframework_in_pods(xcframework_dir, version, product = 'Sentry end nil end + +# Whether RNSentry (and thus the Sentry static archive it absorbs) is linked +# into a dynamic framework rather than statically into the app. This decides +# which target's link the `-force_load` flag must ride — see the call site in +# `RNSentry.podspec`. +# +# `ENV['USE_FRAMEWORKS']` is an explicit override (the convention the RN and +# Expo sample Podfiles and this repo's CI already use): `dynamic` forces the +# dynamic path, any other value forces static. When it is unset we read the +# actual linkage off the Podfile CocoaPods has already loaded, because a bare +# `use_frameworks!` / `use_frameworks! :linkage => :dynamic` in a consumer's +# Podfile does NOT export that env var — trusting the env var alone would take +# the static path and force-load Sentry into the app while RNSentry is really a +# dylib (a second Sentry copy in the app, and the framework link still strips +# the category). Reading the Podfile closes that gap. +# +# This is a best-effort proxy: the linkage that ultimately governs is +# RNSentry's own pod `build_type`, which the installer only computes after +# `pre_install` hooks run and which isn't available at podspec-eval time. We +# therefore read the declared target linkage, matching (and widening) what the +# env var proxied. Guarded like `stage_sentry_xcframework_in_pods`: outside a +# real `pod install` (`pod ipc spec`, `pod lib lint`) there is no Podfile, so +# we fall back to the static default, which is correct for the RN default. +def sentry_uses_dynamic_linkage + env = ENV['USE_FRAMEWORKS'] + return true if env == 'dynamic' + return false unless env.nil? || env.empty? + + podfile = (Pod::Config.instance.podfile if defined?(Pod::Config)) rescue nil + return false unless podfile + + podfile.target_definition_list.any? do |td| + !td.root? && (td.build_type.dynamic_framework? rescue false) + end +rescue StandardError, NotImplementedError + false +end