react-native 0.74.1-rc.0 → 0.74.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/Libraries/Components/Touchable/TouchableBounce.js +1 -0
  2. package/Libraries/Components/Touchable/TouchableOpacity.js +1 -0
  3. package/Libraries/Core/ReactNativeVersion.js +1 -1
  4. package/React/Base/RCTUtils.m +28 -8
  5. package/React/Base/RCTVersion.m +1 -1
  6. package/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +0 -3
  7. package/React/Fabric/Mounting/ComponentViews/Root/RCTRootComponentView.mm +22 -1
  8. package/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +5 -1
  9. package/React/Modules/RCTUIManager.m +8 -9
  10. package/React/Views/RCTComponentData.m +14 -1
  11. package/ReactAndroid/api/ReactAndroid.api +1 -2
  12. package/ReactAndroid/gradle.properties +1 -1
  13. package/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +2 -2
  14. package/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java +24 -9
  15. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java +1 -1
  16. package/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessCatalystInstance.kt +11 -18
  17. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java +10 -0
  18. package/ReactCommon/ReactCommon.podspec +1 -0
  19. package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
  20. package/ReactCommon/jsc/JSCRuntime.cpp +2 -0
  21. package/ReactCommon/jsinspector-modern/React-jsinspector.podspec +2 -1
  22. package/package.json +11 -11
  23. package/scripts/cocoapods/privacy_manifest_utils.rb +172 -0
  24. package/scripts/cocoapods/utils.rb +1 -38
  25. package/scripts/react_native_pods.rb +12 -3
  26. package/sdks/hermesc/osx-bin/hermes +0 -0
  27. package/sdks/hermesc/osx-bin/hermesc +0 -0
  28. package/sdks/hermesc/win64-bin/hermesc.exe +0 -0
  29. package/template/package.json +5 -5
  30. package/third-party-podspecs/RCT-Folly.podspec +1 -0
@@ -209,6 +209,7 @@ class TouchableBounce extends React.Component<Props, State> {
209
209
 
210
210
  componentWillUnmount(): void {
211
211
  this.state.pressability.reset();
212
+ this.state.scale.resetAnimation();
212
213
  }
213
214
  }
214
215
 
@@ -320,6 +320,7 @@ class TouchableOpacity extends React.Component<Props, State> {
320
320
 
321
321
  componentWillUnmount(): void {
322
322
  this.state.pressability.reset();
323
+ this.state.anim.resetAnimation();
323
324
  }
324
325
  }
325
326
 
@@ -17,7 +17,7 @@ const version: $ReadOnly<{
17
17
  major: 0,
18
18
  minor: 74,
19
19
  patch: 1,
20
- prerelease: 'rc.0',
20
+ prerelease: null,
21
21
  };
22
22
 
23
23
  module.exports = {version};
@@ -562,17 +562,37 @@ UIWindow *__nullable RCTKeyWindow(void)
562
562
  return nil;
563
563
  }
564
564
 
565
- for (UIScene *scene in RCTSharedApplication().connectedScenes) {
566
- if (scene.activationState != UISceneActivationStateForegroundActive ||
567
- ![scene isKindOfClass:[UIWindowScene class]]) {
565
+ NSSet<UIScene *> *connectedScenes = RCTSharedApplication().connectedScenes;
566
+
567
+ UIScene *foregroundActiveScene;
568
+ UIScene *foregroundInactiveScene;
569
+
570
+ for (UIScene *scene in connectedScenes) {
571
+ if (![scene isKindOfClass:[UIWindowScene class]]) {
568
572
  continue;
569
573
  }
570
- UIWindowScene *windowScene = (UIWindowScene *)scene;
571
574
 
572
- for (UIWindow *window in windowScene.windows) {
573
- if (window.isKeyWindow) {
574
- return window;
575
- }
575
+ if (scene.activationState == UISceneActivationStateForegroundActive) {
576
+ foregroundActiveScene = scene;
577
+ break;
578
+ }
579
+
580
+ if (!foregroundInactiveScene && scene.activationState == UISceneActivationStateForegroundInactive) {
581
+ foregroundInactiveScene = scene;
582
+ // no break, we can have the active scene later in the set.
583
+ }
584
+ }
585
+
586
+ UIScene *sceneToUse = foregroundActiveScene ? foregroundActiveScene : foregroundInactiveScene;
587
+ UIWindowScene *windowScene = (UIWindowScene *)sceneToUse;
588
+
589
+ if (@available(iOS 15.0, *)) {
590
+ return windowScene.keyWindow;
591
+ }
592
+
593
+ for (UIWindow *window in windowScene.windows) {
594
+ if (window.isKeyWindow) {
595
+ return window;
576
596
  }
577
597
  }
578
598
 
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(74),
26
26
  RCTVersionPatch: @(1),
27
- RCTVersionPrerelease: @"rc.0",
27
+ RCTVersionPrerelease: [NSNull null],
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -125,9 +125,6 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
125
125
  [super surface:surface didChangeStage:stage];
126
126
  if (RCTSurfaceStageIsRunning(stage)) {
127
127
  [_bridge.performanceLogger markStopForTag:RCTPLTTI];
128
- dispatch_async(dispatch_get_main_queue(), ^{
129
- [[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self];
130
- });
131
128
  }
132
129
  }
133
130
 
@@ -7,18 +7,22 @@
7
7
 
8
8
  #import "RCTRootComponentView.h"
9
9
 
10
+ #import <React/RCTRootView.h>
10
11
  #import <react/renderer/components/root/RootComponentDescriptor.h>
11
12
  #import <react/renderer/components/root/RootProps.h>
12
13
  #import "RCTConversions.h"
13
14
 
14
15
  using namespace facebook::react;
15
16
 
16
- @implementation RCTRootComponentView
17
+ @implementation RCTRootComponentView {
18
+ BOOL _contentHasAppeared;
19
+ }
17
20
 
18
21
  - (instancetype)initWithFrame:(CGRect)frame
19
22
  {
20
23
  if (self = [super initWithFrame:frame]) {
21
24
  _props = RootShadowNode::defaultSharedProps();
25
+ _contentHasAppeared = NO;
22
26
  }
23
27
 
24
28
  return self;
@@ -26,6 +30,23 @@ using namespace facebook::react;
26
30
 
27
31
  #pragma mark - RCTComponentViewProtocol
28
32
 
33
+ - (void)prepareForRecycle
34
+ {
35
+ [super prepareForRecycle];
36
+ _contentHasAppeared = NO;
37
+ }
38
+
39
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
40
+ {
41
+ [super mountChildComponentView:childComponentView index:index];
42
+ if (!self->_contentHasAppeared) {
43
+ self->_contentHasAppeared = YES;
44
+ dispatch_async(dispatch_get_main_queue(), ^{
45
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self];
46
+ });
47
+ }
48
+ }
49
+
29
50
  + (ComponentDescriptorProvider)componentDescriptorProvider
30
51
  {
31
52
  return concreteComponentDescriptorProvider<RootComponentDescriptor>();
@@ -420,6 +420,11 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
420
420
 
421
421
  - (void)prepareForRecycle
422
422
  {
423
+ [super prepareForRecycle];
424
+ // Must invalidate state before setting contentOffset on ScrollView.
425
+ // Otherwise the state will be propagated to shadow tree.
426
+ _state.reset();
427
+
423
428
  const auto &props = static_cast<const ScrollViewProps &>(*_props);
424
429
  _scrollView.contentOffset = RCTCGPointFromPoint(props.contentOffset);
425
430
  // We set the default behavior to "never" so that iOS
@@ -427,7 +432,6 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol
427
432
  // and keeps it as an opt-in behavior.
428
433
  _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
429
434
  _shouldUpdateContentInsetAdjustmentBehavior = YES;
430
- _state.reset();
431
435
  _isUserTriggeredScrolling = NO;
432
436
  CGRect oldFrame = self.frame;
433
437
  self.frame = CGRectZero;
@@ -1674,8 +1674,8 @@ static UIView *_jsResponder;
1674
1674
  {
1675
1675
  self = [super init];
1676
1676
  if (self) {
1677
- self->_uiManager = uiManager;
1678
- self->_registry = registry;
1677
+ _uiManager = uiManager;
1678
+ _registry = registry;
1679
1679
  }
1680
1680
  return self;
1681
1681
  }
@@ -1693,26 +1693,27 @@ static UIView *_jsResponder;
1693
1693
  - (id)objectForKey:(id)key
1694
1694
  {
1695
1695
  if (![key isKindOfClass:[NSNumber class]]) {
1696
- return [super objectForKeyedSubscript:key];
1696
+ return NULL;
1697
1697
  }
1698
1698
 
1699
1699
  NSNumber *index = (NSNumber *)key;
1700
- UIView *view = [_uiManager viewForReactTag:index];
1700
+ UIView *view = _registry[index];
1701
1701
  if (view) {
1702
1702
  return [RCTUIManager paperViewOrCurrentView:view];
1703
1703
  }
1704
- view = _registry[index];
1704
+ view = [_uiManager viewForReactTag:index];
1705
1705
  if (view) {
1706
1706
  return [RCTUIManager paperViewOrCurrentView:view];
1707
1707
  }
1708
- return [super objectForKeyedSubscript:key];
1708
+ return NULL;
1709
1709
  }
1710
1710
 
1711
1711
  - (void)removeObjectForKey:(id)key
1712
1712
  {
1713
1713
  if (![key isKindOfClass:[NSNumber class]]) {
1714
- return [super removeObjectForKey:key];
1714
+ return;
1715
1715
  }
1716
+
1716
1717
  NSNumber *tag = (NSNumber *)key;
1717
1718
 
1718
1719
  if (_registry[key]) {
@@ -1720,8 +1721,6 @@ static UIView *_jsResponder;
1720
1721
  [mutableRegistry removeObjectForKey:tag];
1721
1722
  } else if ([_uiManager viewForReactTag:tag]) {
1722
1723
  [_uiManager removeViewFromRegistry:tag];
1723
- } else {
1724
- [super removeObjectForKey:key];
1725
1724
  }
1726
1725
  }
1727
1726
 
@@ -416,7 +416,20 @@ static RCTPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, S
416
416
  + (NSDictionary<NSString *, id> *)constantsForViewMangerClass:(Class)managerClass
417
417
  {
418
418
  if ([managerClass instancesRespondToSelector:@selector(constantsToExport)]) {
419
- return [[managerClass new] constantsToExport];
419
+ BOOL shouldRunOnMainThread = NO;
420
+
421
+ if ([managerClass respondsToSelector:@selector(requiresMainQueueSetup)]) {
422
+ shouldRunOnMainThread = [managerClass requiresMainQueueSetup];
423
+ }
424
+ if (shouldRunOnMainThread) {
425
+ __block NSDictionary<NSString *, id> *constants;
426
+ RCTUnsafeExecuteOnMainQueueSync(^{
427
+ constants = [[managerClass new] constantsToExport];
428
+ });
429
+ return constants;
430
+ } else {
431
+ return [[managerClass new] constantsToExport];
432
+ }
420
433
  }
421
434
  return @{};
422
435
  }
@@ -92,7 +92,7 @@ public abstract class com/facebook/react/ReactActivity : androidx/appcompat/app/
92
92
  protected fun <init> ()V
93
93
  protected fun createReactActivityDelegate ()Lcom/facebook/react/ReactActivityDelegate;
94
94
  protected fun getMainComponentName ()Ljava/lang/String;
95
- public fun getReactDelegate ()V
95
+ public fun getReactDelegate ()Lcom/facebook/react/ReactDelegate;
96
96
  protected final fun getReactInstanceManager ()Lcom/facebook/react/ReactInstanceManager;
97
97
  protected final fun getReactNativeHost ()Lcom/facebook/react/ReactNativeHost;
98
98
  public fun invokeDefaultOnBackPressed ()V
@@ -7697,4 +7697,3 @@ public class com/facebook/react/views/view/ViewGroupClickEvent : com/facebook/re
7697
7697
  protected fun getEventData ()Lcom/facebook/react/bridge/WritableMap;
7698
7698
  public fun getEventName ()Ljava/lang/String;
7699
7699
  }
7700
-
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.74.1-rc.0
1
+ VERSION_NAME=0.74.1
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
 
4
4
  android.useAndroidX=true
@@ -65,8 +65,8 @@ public abstract class ReactActivity extends AppCompatActivity
65
65
  mDelegate.onDestroy();
66
66
  }
67
67
 
68
- public void getReactDelegate() {
69
- mDelegate.getReactDelegate();
68
+ public @Nullable ReactDelegate getReactDelegate() {
69
+ return mDelegate.getReactDelegate();
70
70
  }
71
71
 
72
72
  @Override
@@ -15,6 +15,7 @@ import android.view.KeyEvent;
15
15
  import androidx.annotation.NonNull;
16
16
  import androidx.annotation.Nullable;
17
17
  import com.facebook.infer.annotation.Assertions;
18
+ import com.facebook.react.bridge.UiThreadUtil;
18
19
  import com.facebook.react.config.ReactFeatureFlags;
19
20
  import com.facebook.react.devsupport.DisabledDevSupportManager;
20
21
  import com.facebook.react.devsupport.DoubleTapReloadRecognizer;
@@ -99,7 +100,7 @@ public class ReactDelegate {
99
100
  && mReactHost.getDevSupportManager() != null) {
100
101
  return mReactHost.getDevSupportManager();
101
102
  } else if (getReactNativeHost().hasInstance()
102
- && getReactNativeHost().getUseDeveloperSupport()) {
103
+ && getReactNativeHost().getReactInstanceManager() != null) {
103
104
  return getReactNativeHost().getReactInstanceManager().getDevSupportManager();
104
105
  } else {
105
106
  return null;
@@ -241,17 +242,31 @@ public class ReactDelegate {
241
242
 
242
243
  public void reload() {
243
244
  DevSupportManager devSupportManager = getDevSupportManager();
244
- if (devSupportManager != null) {
245
- // With Bridgeless enabled, reload in RELEASE mode
246
- if (devSupportManager instanceof DisabledDevSupportManager
247
- && ReactFeatureFlags.enableBridgelessArchitecture
248
- && mReactHost != null) {
249
- // Do not reload the bundle from JS as there is no bundler running in release mode.
250
- mReactHost.reload("ReactDelegate.reload()");
245
+ if (devSupportManager == null) {
246
+ return;
247
+ }
248
+
249
+ // Reload in RELEASE mode
250
+ if (devSupportManager instanceof DisabledDevSupportManager) {
251
+ // Do not reload the bundle from JS as there is no bundler running in release mode.
252
+ if (ReactFeatureFlags.enableBridgelessArchitecture) {
253
+ if (mReactHost != null) {
254
+ mReactHost.reload("ReactDelegate.reload()");
255
+ }
251
256
  } else {
252
- devSupportManager.handleReloadJS();
257
+ UiThreadUtil.runOnUiThread(
258
+ () -> {
259
+ if (mReactNativeHost.hasInstance()
260
+ && mReactNativeHost.getReactInstanceManager() != null) {
261
+ mReactNativeHost.getReactInstanceManager().recreateReactContextInBackground();
262
+ }
263
+ });
253
264
  }
265
+ return;
254
266
  }
267
+
268
+ // Reload in DEBUG mode
269
+ devSupportManager.handleReloadJS();
255
270
  }
256
271
 
257
272
  public void loadApp() {
@@ -18,5 +18,5 @@ public class ReactNativeVersion {
18
18
  "major", 0,
19
19
  "minor", 74,
20
20
  "patch", 1,
21
- "prerelease", "rc.0");
21
+ "prerelease", null);
22
22
  }
@@ -92,25 +92,20 @@ public class BridgelessCatalystInstance(private val reactHost: ReactHostImpl) :
92
92
  throw UnsupportedOperationException("Unimplemented method 'initialize'")
93
93
  }
94
94
 
95
- override fun getReactQueueConfiguration(): ReactQueueConfiguration {
96
- throw UnsupportedOperationException("Unimplemented method 'getReactQueueConfiguration'")
97
- }
95
+ override fun getReactQueueConfiguration(): ReactQueueConfiguration =
96
+ reactHost.reactQueueConfiguration!!
98
97
 
99
- override fun <T : JavaScriptModule> getJSModule(jsInterface: Class<T>): T {
100
- throw UnsupportedOperationException("Unimplemented method 'getJSModule'")
101
- }
98
+ override fun <T : JavaScriptModule> getJSModule(jsInterface: Class<T>): T =
99
+ reactHost.currentReactContext?.getJSModule(jsInterface)!!
102
100
 
103
- override fun <T : NativeModule> hasNativeModule(nativeModuleInterface: Class<T>): Boolean {
104
- throw UnsupportedOperationException("Unimplemented method 'hasNativeModule'")
105
- }
101
+ override fun <T : NativeModule> hasNativeModule(nativeModuleInterface: Class<T>): Boolean =
102
+ reactHost.hasNativeModule(nativeModuleInterface)
106
103
 
107
- override fun <T : NativeModule> getNativeModule(nativeModuleInterface: Class<T>): T? {
108
- throw UnsupportedOperationException("Unimplemented method 'getNativeModule'")
109
- }
104
+ override fun <T : NativeModule> getNativeModule(nativeModuleInterface: Class<T>): T? =
105
+ reactHost.getNativeModule(nativeModuleInterface)
110
106
 
111
- override fun getNativeModule(moduleName: String): NativeModule? {
112
- throw UnsupportedOperationException("Unimplemented method 'getNativeModule'")
113
- }
107
+ override fun getNativeModule(moduleName: String): NativeModule? =
108
+ reactHost.getNativeModule(moduleName)
114
109
 
115
110
  @Deprecated(
116
111
  message =
@@ -119,9 +114,7 @@ public class BridgelessCatalystInstance(private val reactHost: ReactHostImpl) :
119
114
  throw UnsupportedOperationException("Unimplemented method 'getJSIModule'")
120
115
  }
121
116
 
122
- override fun getNativeModules(): Collection<NativeModule> {
123
- throw UnsupportedOperationException("Unimplemented method 'getNativeModules'")
124
- }
117
+ override fun getNativeModules(): Collection<NativeModule> = reactHost.getNativeModules()
125
118
 
126
119
  override fun extendNativeModules(modules: NativeModuleRegistry) {
127
120
  throw UnsupportedOperationException("Unimplemented method 'extendNativeModules'")
@@ -592,6 +592,16 @@ public class ReactHostImpl implements ReactHost {
592
592
  return null;
593
593
  }
594
594
 
595
+ /* package */
596
+ @Nullable
597
+ NativeModule getNativeModule(String nativeModuleName) {
598
+ final ReactInstance reactInstance = mReactInstanceTaskRef.get().getResult();
599
+ if (reactInstance != null) {
600
+ return reactInstance.getNativeModule(nativeModuleName);
601
+ }
602
+ return null;
603
+ }
604
+
595
605
  /* package */
596
606
  @Nullable
597
607
  RuntimeExecutor getRuntimeExecutor() {
@@ -36,6 +36,7 @@ Pod::Spec.new do |s|
36
36
  s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
37
37
  s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\" \"$(PODS_ROOT)/Headers/Private/React-Core\"",
38
38
  "USE_HEADERMAP" => "YES",
39
+ "DEFINES_MODULE" => "YES",
39
40
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
40
41
  "GCC_WARN_PEDANTIC" => "YES" }
41
42
  if ENV['USE_FRAMEWORKS']
@@ -18,7 +18,7 @@ constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 74;
20
20
  int32_t Patch = 1;
21
- std::string_view Prerelease = "rc.0";
21
+ std::string_view Prerelease = "";
22
22
  } ReactNativeVersion;
23
23
 
24
24
  } // namespace facebook::react
@@ -370,11 +370,13 @@ JSCRuntime::JSCRuntime(JSGlobalContextRef ctx)
370
370
  {
371
371
  #ifndef NDEBUG
372
372
  #ifdef _JSC_HAS_INSPECTABLE
373
+ #if (__OSX_AVAILABLE_STARTING(MAC_NA, IPHONE_16_4))
373
374
  if (__builtin_available(macOS 13.3, iOS 16.4, tvOS 16.4, *)) {
374
375
  JSGlobalContextSetInspectable(ctx_, true);
375
376
  }
376
377
  #endif
377
378
  #endif
379
+ #endif
378
380
  }
379
381
 
380
382
  JSCRuntime::~JSCRuntime() {
@@ -38,7 +38,8 @@ Pod::Spec.new do |s|
38
38
  s.compiler_flags = folly_compiler_flags
39
39
  s.pod_target_xcconfig = {
40
40
  "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/..\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\"",
41
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++20"
41
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
42
+ "DEFINES_MODULE" => "YES"
42
43
  }.merge!(use_frameworks ? {
43
44
  "PUBLIC_HEADERS_FOLDER_PATH" => "#{module_name}.framework/Headers/#{header_dir}"
44
45
  } : {})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.74.1-rc.0",
3
+ "version": "0.74.1",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -107,16 +107,16 @@
107
107
  },
108
108
  "dependencies": {
109
109
  "@jest/create-cache-key-function": "^29.6.3",
110
- "@react-native-community/cli": "13.6.4",
111
- "@react-native-community/cli-platform-android": "13.6.4",
112
- "@react-native-community/cli-platform-ios": "13.6.4",
113
- "@react-native/assets-registry": "0.74.82",
114
- "@react-native/codegen": "0.74.82",
115
- "@react-native/community-cli-plugin": "0.74.82",
116
- "@react-native/gradle-plugin": "0.74.82",
117
- "@react-native/js-polyfills": "0.74.82",
118
- "@react-native/normalize-colors": "0.74.82",
119
- "@react-native/virtualized-lists": "0.74.82",
110
+ "@react-native-community/cli": "13.6.6",
111
+ "@react-native-community/cli-platform-android": "13.6.6",
112
+ "@react-native-community/cli-platform-ios": "13.6.6",
113
+ "@react-native/assets-registry": "0.74.83",
114
+ "@react-native/codegen": "0.74.83",
115
+ "@react-native/community-cli-plugin": "0.74.83",
116
+ "@react-native/gradle-plugin": "0.74.83",
117
+ "@react-native/js-polyfills": "0.74.83",
118
+ "@react-native/normalize-colors": "0.74.83",
119
+ "@react-native/virtualized-lists": "0.74.83",
120
120
  "abort-controller": "^3.0.0",
121
121
  "anser": "^1.4.9",
122
122
  "ansi-regex": "^5.0.0",
@@ -0,0 +1,172 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ module PrivacyManifestUtils
7
+ def self.add_aggregated_privacy_manifest(installer)
8
+ user_project = get_user_project_from(installer)
9
+ targets = get_application_targets(user_project)
10
+ file_path = get_privacyinfo_file_path(user_project, targets)
11
+
12
+ privacy_info = read_privacyinfo_file(file_path) || {
13
+ "NSPrivacyCollectedDataTypes" => [],
14
+ "NSPrivacyTracking" => false
15
+ }
16
+
17
+ # Get all required reason APIs defined in current pods
18
+ required_reason_apis = get_used_required_reason_apis(installer)
19
+
20
+ # Add the Required Reason APIs from React Native core
21
+ get_core_accessed_apis.each do |accessed_api|
22
+ api_type = accessed_api["NSPrivacyAccessedAPIType"]
23
+ reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
24
+ required_reason_apis[api_type] ||= []
25
+ required_reason_apis[api_type] += reasons
26
+ end
27
+
28
+ # Merge the Required Reason APIs from pods with the ones from the existing PrivacyInfo file
29
+ (privacy_info["NSPrivacyAccessedAPITypes"] || []).each do |accessed_api|
30
+ api_type = accessed_api["NSPrivacyAccessedAPIType"]
31
+ reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
32
+ # Add reasons from existing PrivacyInfo file to the ones from pods
33
+ required_reason_apis[api_type] ||= []
34
+ required_reason_apis[api_type] += reasons
35
+ end
36
+
37
+ # Update the existing PrivacyInfo file with the new aggregated data
38
+ privacy_info["NSPrivacyAccessedAPITypes"] = required_reason_apis.map { |api_type, reasons|
39
+ {
40
+ "NSPrivacyAccessedAPIType" => api_type,
41
+ "NSPrivacyAccessedAPITypeReasons" => reasons.uniq
42
+ }
43
+ }
44
+
45
+ Xcodeproj::Plist.write_to_path(privacy_info, file_path)
46
+
47
+ targets.each do |target|
48
+ ensure_reference(file_path, user_project, target)
49
+ end
50
+ end
51
+
52
+ def self.get_application_targets(user_project)
53
+ return user_project.targets.filter { |t| t.symbol_type == :application }
54
+ end
55
+
56
+ def self.read_privacyinfo_file(file_path)
57
+ # Maybe add missing default NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, but this works without those keys
58
+ source_data = nil
59
+ # Try to read an existing PrivacyInfo.xcprivacy file
60
+ begin
61
+ source_data = Xcodeproj::Plist.read_from_path(file_path)
62
+ Pod::UI.puts "[Privacy Manifest Aggregation] Appending aggregated reasons to existing PrivacyInfo.xcprivacy file."
63
+ rescue => e
64
+ Pod::UI.puts "[Privacy Manifest Aggregation] No existing PrivacyInfo.xcprivacy file found, creating a new one."
65
+ end
66
+ return source_data
67
+ end
68
+
69
+ def self.ensure_reference(file_path, user_project, target)
70
+ reference_exists = target.resources_build_phase.files_references.any? { |file_ref| file_ref.path.end_with? "PrivacyInfo.xcprivacy" }
71
+ unless reference_exists
72
+ # We try to find the main group, but if it doesn't exist, we default to adding the file to the project root – both work
73
+ file_root = user_project.root_object.main_group.children.find { |group|
74
+ group.class == Xcodeproj::Project::Object::PBXGroup && (group.name == target.name || group.path == target.name)
75
+ } || user_project
76
+ file_ref = file_root.new_file(file_path)
77
+ build_file = target.resources_build_phase.add_file_reference(file_ref, true)
78
+ end
79
+ end
80
+
81
+ def self.get_privacyinfo_file_path(user_project, targets)
82
+ file_refs = targets.flat_map { |target| target.resources_build_phase.files_references }
83
+ existing_file = file_refs.find { |file_ref| file_ref.path.end_with? "PrivacyInfo.xcprivacy" }
84
+ if existing_file
85
+ return existing_file.real_path
86
+ end
87
+
88
+ # We try to find a file we know exists in the project to get the path to the main group directory
89
+ info_plist_path = user_project.files.find { |file_ref| file_ref.name == "Info.plist" }
90
+ if info_plist_path.nil?
91
+ # return path that is sibling to .xcodeproj
92
+ path = user_project.path
93
+ return File.join(File.dirname(path), "PrivacyInfo.xcprivacy")
94
+ end
95
+ return File.join(File.dirname(info_plist_path.real_path),"PrivacyInfo.xcprivacy")
96
+ end
97
+
98
+ def self.get_used_required_reason_apis(installer)
99
+ # A dictionary with keys of type string (NSPrivacyAccessedAPIType) and values of type string[] (NSPrivacyAccessedAPITypeReasons[])
100
+ used_apis = {}
101
+ Pod::UI.puts "[Privacy Manifest Aggregation] Reading .xcprivacy files to aggregate all used Required Reason APIs."
102
+ installer.pod_targets.each do |pod_target|
103
+ # puts pod_target
104
+ pod_target.file_accessors.each do |file_accessor|
105
+ file_accessor.resource_bundles.each do |bundle_name, bundle_files|
106
+ bundle_files.each do |file_path|
107
+ # This needs to be named like that due to apple requirements
108
+ if File.basename(file_path) == 'PrivacyInfo.xcprivacy'
109
+ content = Xcodeproj::Plist.read_from_path(file_path)
110
+ accessed_api_types = content["NSPrivacyAccessedAPITypes"]
111
+ accessed_api_types.each do |accessed_api|
112
+ api_type = accessed_api["NSPrivacyAccessedAPIType"]
113
+ reasons = accessed_api["NSPrivacyAccessedAPITypeReasons"]
114
+ used_apis[api_type] ||= []
115
+ used_apis[api_type] += reasons
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ return used_apis
123
+ end
124
+
125
+ def self.get_privacy_manifest_paths_from(user_project)
126
+ privacy_manifests = user_project
127
+ .files
128
+ .select { |p|
129
+ p.path&.end_with?('PrivacyInfo.xcprivacy')
130
+ }
131
+ return privacy_manifests
132
+ end
133
+
134
+ def self.get_core_accessed_apis()
135
+ file_timestamp_accessed_api = {
136
+ "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryFileTimestamp",
137
+ "NSPrivacyAccessedAPITypeReasons" => ["C617.1"],
138
+ }
139
+ user_defaults_accessed_api = {
140
+ "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryUserDefaults",
141
+ "NSPrivacyAccessedAPITypeReasons" => ["CA92.1"],
142
+ }
143
+ boot_time_accessed_api = {
144
+ "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategorySystemBootTime",
145
+ "NSPrivacyAccessedAPITypeReasons" => ["35F9.1"],
146
+ }
147
+ return [file_timestamp_accessed_api, user_defaults_accessed_api, boot_time_accessed_api]
148
+ end
149
+
150
+
151
+ def self.get_user_project_from(installer)
152
+ user_project = installer.aggregate_targets
153
+ .map{ |t| t.user_project }
154
+ .first
155
+ return user_project
156
+ end
157
+
158
+ def self.add_privacy_manifest_if_needed(installer)
159
+ user_project = get_user_project_from(installer)
160
+ privacy_manifest = self.get_privacy_manifest_paths_from(user_project).first
161
+ if privacy_manifest.nil?
162
+ privacy_manifest = {
163
+ "NSPrivacyCollectedDataTypes" => [],
164
+ "NSPrivacyTracking" => false,
165
+ "NSPrivacyAccessedAPITypes" => get_core_accessed_apis
166
+ }
167
+ path = File.join(user_project.path.parent, "PrivacyInfo.xcprivacy")
168
+ Xcodeproj::Plist.write_to_path(privacy_manifest, path)
169
+ Pod::UI.puts "Your app does not have a privacy manifest! A template has been generated containing Required Reasons API usage in the core React Native library. Please add the PrivacyInfo.xcprivacy file to your project and complete data use, tracking and any additional required reasons your app is using according to Apple's guidance: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files. Then, you will need to manually add this file to your project in Xcode.".red
170
+ end
171
+ end
172
+ end
@@ -44,6 +44,7 @@ class ReactNativePodsUtils
44
44
  def self.set_gcc_preprocessor_definition_for_React_hermes(installer)
45
45
  self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "React-hermes", "Debug")
46
46
  self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "hermes-engine", "Debug")
47
+ self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "React-RuntimeHermes", "Debug")
47
48
  end
48
49
 
49
50
  def self.turn_off_resource_bundle_react_core(installer)
@@ -591,44 +592,6 @@ class ReactNativePodsUtils
591
592
  ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "React-ImageManager", header_search_paths)
592
593
  end
593
594
 
594
- def self.get_privacy_manifest_paths_from(user_project)
595
- privacy_manifests = user_project
596
- .files
597
- .select { |p|
598
- p.path&.end_with?('PrivacyInfo.xcprivacy')
599
- }
600
- return privacy_manifests
601
- end
602
-
603
- def self.add_privacy_manifest_if_needed(installer)
604
- user_project = installer.aggregate_targets
605
- .map{ |t| t.user_project }
606
- .first
607
- privacy_manifest = self.get_privacy_manifest_paths_from(user_project).first
608
- if privacy_manifest.nil?
609
- file_timestamp_reason = {
610
- "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryFileTimestamp",
611
- "NSPrivacyAccessedAPITypeReasons" => ["C617.1"],
612
- }
613
- user_defaults_reason = {
614
- "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategoryUserDefaults",
615
- "NSPrivacyAccessedAPITypeReasons" => ["CA92.1"],
616
- }
617
- boot_time_reason = {
618
- "NSPrivacyAccessedAPIType" => "NSPrivacyAccessedAPICategorySystemBootTime",
619
- "NSPrivacyAccessedAPITypeReasons" => ["35F9.1"],
620
- }
621
- privacy_manifest = {
622
- "NSPrivacyCollectedDataTypes" => [],
623
- "NSPrivacyTracking" => false,
624
- "NSPrivacyAccessedAPITypes" => [file_timestamp_reason, user_defaults_reason, boot_time_reason]
625
- }
626
- path = File.join(user_project.path.parent, "PrivacyInfo.xcprivacy")
627
- Xcodeproj::Plist.write_to_path(privacy_manifest, path)
628
- Pod::UI.puts "Your app does not have a privacy manifest! A template has been generated containing Required Reasons API usage in the core React Native library. Please add the PrivacyInfo.xcprivacy file to your project and complete data use, tracking and any additional required reasons your app is using according to Apple's guidance: https://developer.apple.com/.../privacy_manifest_files. Then, you will need to manually add this file to your project in Xcode.".red
629
- end
630
- end
631
-
632
595
  def self.react_native_pods
633
596
  return [
634
597
  "DoubleConversion",
@@ -16,6 +16,7 @@ require_relative './cocoapods/new_architecture.rb'
16
16
  require_relative './cocoapods/local_podspec_patch.rb'
17
17
  require_relative './cocoapods/runtime.rb'
18
18
  require_relative './cocoapods/helpers.rb'
19
+ require_relative './cocoapods/privacy_manifest_utils.rb'
19
20
 
20
21
  $CODEGEN_OUTPUT_DIR = 'build/generated/ios'
21
22
  $CODEGEN_COMPONENT_DIR = 'react/renderer/components'
@@ -73,7 +74,8 @@ def use_react_native! (
73
74
  production: false, # deprecated
74
75
  hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true,
75
76
  app_path: '..',
76
- config_file_dir: ''
77
+ config_file_dir: '',
78
+ privacy_file_aggregation_enabled: true
77
79
  )
78
80
 
79
81
  # Set the app_path as env variable so the podspecs can access it.
@@ -97,6 +99,7 @@ def use_react_native! (
97
99
 
98
100
  ENV['RCT_FABRIC_ENABLED'] = fabric_enabled ? "1" : "0"
99
101
  ENV['USE_HERMES'] = hermes_enabled ? "1" : "0"
102
+ ENV['RCT_AGGREGATE_PRIVACY_FILES'] = privacy_file_aggregation_enabled ? "1" : "0"
100
103
 
101
104
  prefix = path
102
105
 
@@ -278,6 +281,7 @@ def react_native_post_install(
278
281
 
279
282
  fabric_enabled = ENV['RCT_FABRIC_ENABLED'] == '1'
280
283
  hermes_enabled = ENV['USE_HERMES'] == '1'
284
+ privacy_file_aggregation_enabled = ENV['RCT_AGGREGATE_PRIVACY_FILES'] == '1'
281
285
 
282
286
  if hermes_enabled
283
287
  ReactNativePodsUtils.set_gcc_preprocessor_definition_for_React_hermes(installer)
@@ -288,11 +292,16 @@ def react_native_post_install(
288
292
  ReactNativePodsUtils.set_use_hermes_build_setting(installer, hermes_enabled)
289
293
  ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)
290
294
  ReactNativePodsUtils.set_ccache_compiler_and_linker_build_settings(installer, react_native_path, ccache_enabled)
291
- ReactNativePodsUtils.apply_xcode_15_patch(installer)
295
+ ReactNativePodsUtils.apply_xcode_15_patch(installer)
292
296
  ReactNativePodsUtils.updateOSDeploymentTarget(installer)
293
297
  ReactNativePodsUtils.set_dynamic_frameworks_flags(installer)
294
298
  ReactNativePodsUtils.add_ndebug_flag_to_pods_in_release(installer)
295
- ReactNativePodsUtils.add_privacy_manifest_if_needed(installer)
299
+
300
+ if privacy_file_aggregation_enabled
301
+ PrivacyManifestUtils.add_aggregated_privacy_manifest(installer)
302
+ else
303
+ PrivacyManifestUtils.add_privacy_manifest_if_needed(installer)
304
+ end
296
305
 
297
306
  NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer)
298
307
  NewArchitectureHelper.modify_flags_for_new_architecture(installer, NewArchitectureHelper.new_arch_enabled)
Binary file
Binary file
Binary file
@@ -11,16 +11,16 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "react": "18.2.0",
14
- "react-native": "0.74.1-rc.0"
14
+ "react-native": "0.74.1"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@babel/core": "^7.20.0",
18
18
  "@babel/preset-env": "^7.20.0",
19
19
  "@babel/runtime": "^7.20.0",
20
- "@react-native/babel-preset": "0.74.82",
21
- "@react-native/eslint-config": "0.74.82",
22
- "@react-native/metro-config": "0.74.82",
23
- "@react-native/typescript-config": "0.74.82",
20
+ "@react-native/babel-preset": "0.74.83",
21
+ "@react-native/eslint-config": "0.74.83",
22
+ "@react-native/metro-config": "0.74.83",
23
+ "@react-native/typescript-config": "0.74.83",
24
24
  "@types/react": "^18.2.6",
25
25
  "@types/react-test-renderer": "^18.0.0",
26
26
  "babel-jest": "^29.6.3",
@@ -81,6 +81,7 @@ Pod::Spec.new do |spec|
81
81
  'folly/system/*.h',
82
82
  spec.libraries = "c++abi" # NOTE Apple-only: Keep c++abi here due to https://github.com/react-native-community/releases/issues/251
83
83
  spec.pod_target_xcconfig = { "USE_HEADERMAP" => "NO",
84
+ "DEFINES_MODULE" => "YES",
84
85
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
85
86
  "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\"",
86
87
  # In dynamic framework (use_frameworks!) mode, ignore the unused and undefined boost symbols when generating the library.