diff --git a/package.json b/package.json index 93710179ed..edfec97c0f 100644 --- a/package.json +++ b/package.json @@ -184,7 +184,7 @@ "expo-media-library": "~18.2.1", "expo-notifications": "~0.32.17", "expo-paste-input": "^0.2.1", - "expo-privacy-sensitive": "^0.1.0", + "expo-privacy-sensitive": "^0.2.0", "expo-screen-orientation": "~9.0.8", "expo-sharing": "~14.0.8", "expo-sms": "^14.0.7", diff --git a/patches/expo-privacy-sensitive@0.1.0.patch b/patches/expo-privacy-sensitive@0.1.0.patch deleted file mode 100644 index 5c5a4ca2c7..0000000000 --- a/patches/expo-privacy-sensitive@0.1.0.patch +++ /dev/null @@ -1,66 +0,0 @@ -diff --git a/ios/ExpoPrivacySensitive.podspec b/ios/ExpoPrivacySensitive.podspec -index fa9a44c2668571bb22da7d817960c89d84b37266..ff415bfac2885ed3029b3440c2eb3859f60c0e05 100644 ---- a/ios/ExpoPrivacySensitive.podspec -+++ b/ios/ExpoPrivacySensitive.podspec -@@ -2,6 +2,9 @@ require 'json' - - package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json'))) - -+new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' -+new_arch_compiler_flags = '-DRCT_NEW_ARCH_ENABLED' -+ - Pod::Spec.new do |s| - s.name = 'ExpoPrivacySensitive' - s.version = package['version'] -@@ -23,6 +26,7 @@ Pod::Spec.new do |s| - # Swift/Objective-C compatibility - s.pod_target_xcconfig = { - 'DEFINES_MODULE' => 'YES', -+ 'OTHER_SWIFT_FLAGS' => "$(inherited) #{new_arch_enabled ? new_arch_compiler_flags : ''}", - } - - s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}" -diff --git a/ios/ExpoPrivacySensitiveView.swift b/ios/ExpoPrivacySensitiveView.swift -index 499b9b4764894a7ccf7dac2ccee6b09bf14d78cc..424ca9109c32e4cc96faed0a8b8204685899355b 100644 ---- a/ios/ExpoPrivacySensitiveView.swift -+++ b/ios/ExpoPrivacySensitiveView.swift -@@ -26,6 +26,31 @@ class ExpoPrivacySensitiveView: ExpoView { - isSettingUp = false - } - -+#if RCT_NEW_ARCH_ENABLED -+ // On the new architecture (Fabric), `ExpoView` is an `RCTViewComponentView` -+ // subclass and React children are mounted/unmounted via these methods rather -+ // than `addSubview`/`insertSubview`. We reparent the children into the secure -+ // container here so they stay hidden in screenshots. Crucially, unmount must -+ // not fall through to `super`, whose assertion requires the child to be a -+ // direct subview of `self`; ours live inside `secureContainer`, so unmounting -+ // that way would crash with "Attempt to unmount a view which is mounted inside -+ // different view". -+ override func mountChildComponentView(_ childComponentView: UIView, index: Int) { -+ if let container = secureContainer { -+ container.insertSubview(childComponentView, at: index) -+ } else { -+ super.mountChildComponentView(childComponentView, index: index) -+ } -+ } -+ -+ override func unmountChildComponentView(_ childComponentView: UIView, index: Int) { -+ if secureContainer != nil { -+ childComponentView.removeFromSuperview() -+ } else { -+ super.unmountChildComponentView(childComponentView, index: index) -+ } -+ } -+#else - override func addSubview(_ view: UIView) { - if isSettingUp || view === secureContainer { - super.addSubview(view) -@@ -77,6 +102,7 @@ class ExpoPrivacySensitiveView: ExpoView { - super.insertSubview(view, belowSubview: siblingSubview) - } - } -+#endif - - override func layoutSubviews() { - super.layoutSubviews() diff --git a/patches/expo-privacy-sensitive@0.1.0.patch.md b/patches/expo-privacy-sensitive@0.1.0.patch.md deleted file mode 100644 index 188755e2f4..0000000000 --- a/patches/expo-privacy-sensitive@0.1.0.patch.md +++ /dev/null @@ -1,46 +0,0 @@ -# `expo-privacy-sensitive` patch - -Makes the native iOS view compatible with the React Native new architecture (Fabric). - -## Problem - -`ExpoPrivacySensitiveView` hides its content from screenshots by reparenting its -children into a secure `UITextField` container view. It did this by overriding -`addSubview`/`insertSubview`. - -On the new architecture, `ExpoView` is an `RCTViewComponentView` subclass, and -Fabric mounts/unmounts React children by calling `mountChildComponentView` / -`unmountChildComponentView` directly on the component view. The mount path went -through the overridden `insertSubview` and reparented the child into the secure -container, but `RCTViewComponentView.unmountChildComponentView` asserts that the -child is a direct subview of `self`. That assertion failed, crashing the app: - -``` -NSInternalInconsistencyException: Attempt to unmount a view which is mounted -inside different view. (parent: ExpoPrivacySensitive.ExpoPrivacySensitiveView, -child: RCTViewComponentView, index: 0) -``` - -It reproduced reliably when navigating back from the post thread screen (the -`GrowthHack` component is the only consumer). - -## Fix - -Two parts, mirroring how `expo-splash-screen` supports both architectures: - -1. `ExpoPrivacySensitive.podspec` now adds `-DRCT_NEW_ARCH_ENABLED` to - `OTHER_SWIFT_FLAGS` when `ENV['RCT_NEW_ARCH_ENABLED'] == '1'`. Without this, - the flag is never defined for this pod's Swift, so the `#if` below would - always be false. -2. `ExpoPrivacySensitiveView.swift` gates its implementation on - `#if RCT_NEW_ARCH_ENABLED`: on the new architecture it overrides - `mountChildComponentView` / `unmountChildComponentView` (reparenting on mount, - plain removal on unmount to avoid the superview assertion); the old - `addSubview`/`insertSubview` overrides are kept for the old architecture. - -## Important: requires `RCT_NEW_ARCH_ENABLED=1` at install - -The podspec opt-in is gated on `ENV['RCT_NEW_ARCH_ENABLED'] == '1'` at -`pod install` time (same as `expo-splash-screen` and `ExpoModulesCore`). - -Should be upstreamed to https://github.com/mozzius/expo-privacy-sensitive. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e350329fae..face60e04b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -224,7 +224,6 @@ patchedDependencies: expo-media-library@18.2.1: 2b84c17999bb0c977eaef7fa8ac297f7074d91c94fb63726b42d2a277b26b39a expo-modules-core@3.0.30: 952fb1c8cb6dc8a0d8ef4e1114942a341d89b025e011f1acfff788929997346e expo-notifications@0.32.17: a45a8dcf3d8c4b5df4ee0e62bc79b755fcf9d28ca51a6f685b85830bf4afc2e5 - expo-privacy-sensitive@0.1.0: 8f369eafd4ca69611b422861462b11fe2258694161b54531a2a10cf4eaf4ce57 expo-updates@29.0.17: 04f28cb005b770e9ae8f0065eab96e43cbb1e58107f5f6ad1bdd18f6deb66487 react-native-compressor@1.13.0: 58379dfaace6ced8590cb341c77f2ca8099dfa8f7df6297032ec51de767a9925 react-native-date-picker@5.0.13: 92943fb79d17d7342a29bbb12b0d8ee3cf6f7bca12ed322dc8d124a3e9fb75bd @@ -507,8 +506,8 @@ importers: specifier: ^0.2.1 version: 0.2.1(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo-privacy-sensitive: - specifier: ^0.1.0 - version: 0.1.0(patch_hash=8f369eafd4ca69611b422861462b11fe2258694161b54531a2a10cf4eaf4ce57)(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + specifier: ^0.2.0 + version: 0.2.0(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo-screen-orientation: specifier: ~9.0.8 version: 9.0.9(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)) @@ -5420,8 +5419,8 @@ packages: react: '*' react-native: '*' - expo-privacy-sensitive@0.1.0: - resolution: {integrity: sha512-N0xa8yz+u7HvGY5CqZeo5cwtTOyFQxOxxt15jeW1eAjLKZAcNrtrDGGJP18TX2eh5TfJ3I6OtmECJg9Q8+Yorw==} + expo-privacy-sensitive@0.2.0: + resolution: {integrity: sha512-vHCpDJ7/VGMAGBobxslWemZxTpD3MfpAU6xvyIze+1LoTxdeYbGzUs0JeH1d8D+lrV9gV4cuFfvTmV1tHy9o9w==} peerDependencies: expo: '*' react: '*' @@ -14694,7 +14693,7 @@ snapshots: react: 19.1.0 react-native: 0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) - expo-privacy-sensitive@0.1.0(patch_hash=8f369eafd4ca69611b422861462b11fe2258694161b54531a2a10cf4eaf4ce57)(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + expo-privacy-sensitive@0.2.0(expo@54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: expo: 54.0.35(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=0a4b515f22d157816048e3181dd18fb83b1679a90fca50f715c55483aabdced4)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react: 19.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6779296934..1afb2a5b75 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -21,19 +21,18 @@ allowBuilds: 'unrs-resolver': true patchedDependencies: '@sentry/expo-upload-sourcemaps@8.18.0': patches/@sentry__expo-upload-sourcemaps@8.18.0.patch - expo-age-range@0.2.18: patches/expo-age-range@0.2.18.patch + 'expo-age-range@0.2.18': patches/expo-age-range@0.2.18.patch 'expo-haptics@15.0.8': patches/expo-haptics@15.0.8.patch 'expo-image-picker@17.0.11': patches/expo-image-picker@17.0.11.patch 'expo-image@3.0.11': patches/expo-image@3.0.11.patch 'expo-media-library@18.2.1': patches/expo-media-library@18.2.1.patch 'expo-modules-core@3.0.30': patches/expo-modules-core@3.0.30.patch 'expo-notifications@0.32.17': patches/expo-notifications@0.32.17.patch - 'expo-privacy-sensitive@0.1.0': patches/expo-privacy-sensitive@0.1.0.patch 'expo-updates@29.0.17': patches/expo-updates@29.0.17.patch 'react-native-compressor@1.13.0': patches/react-native-compressor@1.13.0.patch 'react-native-date-picker@5.0.13': patches/react-native-date-picker@5.0.13.patch 'react-native-drawer-layout@4.2.3': patches/react-native-drawer-layout@4.2.3.patch - react-native-gesture-handler: patches/react-native-gesture-handler.patch + 'react-native-gesture-handler': patches/react-native-gesture-handler.patch 'react-native-keyboard-controller@1.21.8': patches/react-native-keyboard-controller@1.21.8.patch 'react-native-pager-view@6.8.0': patches/react-native-pager-view@6.8.0.patch 'react-native-reanimated@4.3.2': patches/react-native-reanimated@4.3.2.patch