@callstack/react-native-brownfield 3.0.0-rc.1 → 3.0.0-rc.2

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 (58) hide show
  1. package/ReactBrownfield.podspec +4 -0
  2. package/ios/BrownfieldBundlePathResolver.swift +21 -0
  3. package/ios/ExpoHostRuntime.swift +140 -0
  4. package/ios/JSBundleLoadObserver.swift +38 -0
  5. package/ios/Notification+Brownfield.swift +12 -0
  6. package/ios/ReactNativeBrownfield.swift +78 -112
  7. package/ios/ReactNativeHostRuntime.swift +138 -0
  8. package/lib/commonjs/expo-config-plugin/android/constants.js +1 -1
  9. package/lib/commonjs/expo-config-plugin/ios/podfileHelpers.js +3 -26
  10. package/lib/commonjs/expo-config-plugin/ios/podfileHelpers.js.map +1 -1
  11. package/lib/commonjs/expo-config-plugin/ios/withBrownfieldIos.js +1 -1
  12. package/lib/commonjs/expo-config-plugin/ios/withBrownfieldIos.js.map +1 -1
  13. package/lib/commonjs/expo-config-plugin/ios/withIosFrameworkFiles.js +1 -1
  14. package/lib/commonjs/expo-config-plugin/ios/withIosFrameworkFiles.js.map +1 -1
  15. package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js +1 -1
  16. package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
  17. package/lib/commonjs/expo-config-plugin/template/ios/FrameworkInterface.swift +8 -3
  18. package/lib/commonjs/expo-config-plugin/template/ios/PodfileTargetBlock.rb +1 -0
  19. package/lib/commonjs/expo-config-plugin/template/ios/patchExpoPre55.sh +1 -1
  20. package/lib/commonjs/scripts/brownfield.js +0 -0
  21. package/lib/module/expo-config-plugin/android/constants.js +1 -1
  22. package/lib/module/expo-config-plugin/ios/podfileHelpers.js +3 -26
  23. package/lib/module/expo-config-plugin/ios/podfileHelpers.js.map +1 -1
  24. package/lib/module/expo-config-plugin/ios/withBrownfieldIos.js +1 -1
  25. package/lib/module/expo-config-plugin/ios/withBrownfieldIos.js.map +1 -1
  26. package/lib/module/expo-config-plugin/ios/withIosFrameworkFiles.js +1 -1
  27. package/lib/module/expo-config-plugin/ios/withIosFrameworkFiles.js.map +1 -1
  28. package/lib/module/expo-config-plugin/ios/xcodeHelpers.js +1 -1
  29. package/lib/module/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
  30. package/lib/module/expo-config-plugin/template/ios/FrameworkInterface.swift +8 -3
  31. package/lib/module/expo-config-plugin/template/ios/PodfileTargetBlock.rb +1 -0
  32. package/lib/module/expo-config-plugin/template/ios/patchExpoPre55.sh +1 -1
  33. package/lib/typescript/commonjs/src/expo-config-plugin/android/constants.d.ts +2 -2
  34. package/lib/typescript/commonjs/src/expo-config-plugin/ios/podfileHelpers.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/src/expo-config-plugin/ios/withBrownfieldIos.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/src/expo-config-plugin/ios/withIosFrameworkFiles.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts +2 -2
  38. package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
  39. package/lib/typescript/module/src/expo-config-plugin/android/constants.d.ts +2 -2
  40. package/lib/typescript/module/src/expo-config-plugin/ios/podfileHelpers.d.ts.map +1 -1
  41. package/lib/typescript/module/src/expo-config-plugin/ios/withBrownfieldIos.d.ts.map +1 -1
  42. package/lib/typescript/module/src/expo-config-plugin/ios/withIosFrameworkFiles.d.ts.map +1 -1
  43. package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts +2 -2
  44. package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
  45. package/package.json +7 -6
  46. package/scripts/react_native_brownfield_post_integrate.rb +22 -0
  47. package/src/expo-config-plugin/android/constants.ts +1 -1
  48. package/src/expo-config-plugin/ios/podfileHelpers.ts +30 -27
  49. package/src/expo-config-plugin/ios/withBrownfieldIos.ts +1 -2
  50. package/src/expo-config-plugin/ios/withIosFrameworkFiles.ts +0 -4
  51. package/src/expo-config-plugin/ios/xcodeHelpers.ts +75 -1
  52. package/src/expo-config-plugin/template/ios/FrameworkInterface.swift +8 -3
  53. package/src/expo-config-plugin/template/ios/PodfileTargetBlock.rb +1 -0
  54. package/src/expo-config-plugin/template/ios/patchExpoPre55.sh +1 -1
  55. package/CHANGELOG.md +0 -41
  56. package/lib/commonjs/expo-config-plugin/template/ios/ReactNativeHostManager.swift +0 -63
  57. package/lib/module/expo-config-plugin/template/ios/ReactNativeHostManager.swift +0 -63
  58. package/src/expo-config-plugin/template/ios/ReactNativeHostManager.swift +0 -63
@@ -22,6 +22,10 @@ Pod::Spec.new do |spec|
22
22
 
23
23
  spec.dependency 'ReactAppDependencyProvider'
24
24
  add_dependency(spec, "React-RCTAppDelegate")
25
+
26
+ if ENV['REACT_NATIVE_BROWNFIELD_USE_EXPO_HOST'] == '1'
27
+ spec.dependency 'Expo'
28
+ end
25
29
 
26
30
  install_modules_dependencies(spec)
27
31
  end
@@ -0,0 +1,21 @@
1
+ import Foundation
2
+
3
+ enum BrownfieldBundlePathResolver {
4
+ enum Error: Swift.Error {
5
+ case invalidBundlePath(String)
6
+ }
7
+
8
+ static func resourceComponents(from bundlePath: String) throws -> (
9
+ resourceName: String,
10
+ fileExtension: String
11
+ ) {
12
+ let fileExtension = (bundlePath as NSString).pathExtension
13
+ let resourceName = (bundlePath as NSString).deletingPathExtension
14
+
15
+ guard !fileExtension.isEmpty, !resourceName.isEmpty else {
16
+ throw Error.invalidBundlePath(bundlePath)
17
+ }
18
+
19
+ return (resourceName, fileExtension)
20
+ }
21
+ }
@@ -0,0 +1,140 @@
1
+ import UIKit
2
+ internal import React
3
+ internal import React_RCTAppDelegate
4
+ internal import ReactAppDependencyProvider
5
+
6
+ #if canImport(Expo)
7
+ internal import Expo
8
+
9
+ final class ExpoHostRuntime {
10
+ static let shared = ExpoHostRuntime()
11
+
12
+ private let jsBundleLoadObserver = JSBundleLoadObserver()
13
+ private var delegate = ExpoHostRuntimeDelegate()
14
+ private var reactNativeFactory: RCTReactNativeFactory?
15
+ private var expoDelegate: ExpoAppDelegate?
16
+
17
+ /**
18
+ * Starts React Native with default parameters.
19
+ */
20
+ public func startReactNative() {
21
+ startReactNative(onBundleLoaded: nil)
22
+ }
23
+ /**
24
+ * Starts React Native with optional callback when bundle is loaded.
25
+ *
26
+ * @param onBundleLoaded Optional callback invoked after JS bundle is fully loaded.
27
+ */
28
+ public func startReactNative(onBundleLoaded: (() -> Void)?) {
29
+ guard reactNativeFactory == nil else { return }
30
+
31
+ let factory = ExpoReactNativeFactory(delegate: delegate)
32
+ delegate.dependencyProvider = RCTAppDependencyProvider()
33
+
34
+ reactNativeFactory = factory
35
+
36
+ let appDelegate = ExpoAppDelegate()
37
+ appDelegate.bindReactNativeFactory(factory)
38
+ expoDelegate = appDelegate
39
+
40
+ if let onBundleLoaded {
41
+ jsBundleLoadObserver.observeOnce(onBundleLoaded: onBundleLoaded)
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Path to JavaScript root.
47
+ * Default value: ".expo/.virtual-metro-entry"
48
+ */
49
+ public var entryFile: String = ".expo/.virtual-metro-entry" {
50
+ didSet {
51
+ delegate.entryFile = entryFile
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Path to JavaScript bundle file.
57
+ * Default value: "main.jsbundle"
58
+ */
59
+ public var bundlePath: String = "main.jsbundle" {
60
+ didSet {
61
+ delegate.bundlePath = bundlePath
62
+ }
63
+ }
64
+ /**
65
+ * Bundle instance to lookup the JavaScript bundle.
66
+ * Default value: Bundle.main
67
+ */
68
+ public var bundle: Bundle = Bundle.main {
69
+ didSet {
70
+ delegate.bundle = bundle
71
+ }
72
+ }
73
+ /**
74
+ * Dynamic bundle URL provider called on every bundle load.
75
+ * When set, this overrides the default bundleURL() behavior in the delegate.
76
+ * Returns a URL to load a custom bundle, or nil to use default behavior.
77
+ * Default value: nil
78
+ */
79
+ public var bundleURLOverride: (() -> URL?)? = nil {
80
+ didSet {
81
+ delegate.bundleURLOverride = bundleURLOverride
82
+ }
83
+ }
84
+
85
+ func application(
86
+ _ application: UIApplication,
87
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
88
+ ) -> Bool {
89
+ return expoDelegate?.application(
90
+ application,
91
+ didFinishLaunchingWithOptions: launchOptions
92
+ ) != nil
93
+ }
94
+
95
+ func view(
96
+ moduleName: String,
97
+ initialProps: [AnyHashable: Any]?,
98
+ launchOptions: [AnyHashable: Any]?
99
+ ) -> UIView? {
100
+ let bundleURL = delegate.bundleURL()
101
+
102
+ return expoDelegate?.recreateRootView(
103
+ withBundleURL: bundleURL,
104
+ moduleName: moduleName,
105
+ initialProps: initialProps,
106
+ launchOptions: launchOptions
107
+ )
108
+ }
109
+ }
110
+
111
+ class ExpoHostRuntimeDelegate: ExpoReactNativeFactoryDelegate {
112
+ var entryFile = ".expo/.virtual-metro-entry"
113
+ var bundlePath = "main.jsbundle"
114
+ var bundle = Bundle.main
115
+ var bundleURLOverride: (() -> URL?)? = nil
116
+
117
+ override func sourceURL(for bridge: RCTBridge) -> URL? {
118
+ // needed to return the correct URL for expo-dev-client.
119
+ bridge.bundleURL ?? bundleURL()
120
+ }
121
+
122
+ override func bundleURL() -> URL? {
123
+ if let bundleURLProvider = bundleURLOverride { return bundleURLProvider() }
124
+ #if DEBUG
125
+ return RCTBundleURLProvider.sharedSettings().jsBundleURL(
126
+ forBundleRoot: entryFile)
127
+ #else
128
+ do {
129
+ let (resourceName, fileExtension) = try BrownfieldBundlePathResolver.resourceComponents(
130
+ from: bundlePath
131
+ )
132
+ return bundle.url(forResource: resourceName, withExtension: fileExtension)
133
+ } catch {
134
+ assertionFailure("Invalid bundlePath '\(bundlePath)': \(error)")
135
+ return nil
136
+ }
137
+ #endif
138
+ }
139
+ }
140
+ #endif
@@ -0,0 +1,38 @@
1
+ import Foundation
2
+ internal import React
3
+
4
+ final class JSBundleLoadObserver {
5
+ private var onBundleLoaded: (() -> Void)?
6
+ private var observerToken: NSObjectProtocol?
7
+
8
+ func observeOnce(onBundleLoaded: @escaping () -> Void) {
9
+ removeObserverIfNeeded()
10
+ self.onBundleLoaded = onBundleLoaded
11
+
12
+ observerToken = NotificationCenter.default.addObserver(
13
+ forName: NSNotification.Name("RCTInstanceDidLoadBundle"),
14
+ object: nil,
15
+ queue: nil
16
+ ) { [weak self] _ in
17
+ self?.notifyAndClear()
18
+ }
19
+ }
20
+
21
+ deinit {
22
+ removeObserverIfNeeded()
23
+ }
24
+
25
+ private func notifyAndClear() {
26
+ let callback = onBundleLoaded
27
+ onBundleLoaded = nil
28
+ removeObserverIfNeeded()
29
+ callback?()
30
+ }
31
+
32
+ private func removeObserverIfNeeded() {
33
+ if let observerToken {
34
+ NotificationCenter.default.removeObserver(observerToken)
35
+ self.observerToken = nil
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,12 @@
1
+ import Foundation
2
+
3
+ extension Notification.Name {
4
+ /**
5
+ * Notification sent when React Native wants to navigate back to native screen.
6
+ */
7
+ public static let popToNative = Notification.Name("PopToNativeNotification")
8
+ /**
9
+ * Notification sent to enable/disable the pop gesture recognizer.
10
+ */
11
+ public static let togglePopGestureRecognizer = Notification.Name("TogglePopGestureRecognizerNotification")
12
+ }
@@ -1,74 +1,60 @@
1
1
  import UIKit
2
- internal import React
3
- internal import React_RCTAppDelegate
4
- internal import ReactAppDependencyProvider
5
2
 
6
- class ReactNativeBrownfieldDelegate: RCTDefaultReactNativeFactoryDelegate {
7
- var entryFile = "index"
8
- var bundlePath = "main.jsbundle"
9
- var bundle = Bundle.main
10
- var bundleURLOverride: (() -> URL?)? = nil
11
- // MARK: - RCTReactNativeFactoryDelegate Methods
12
-
13
- override func sourceURL(for bridge: RCTBridge) -> URL? {
14
- return bundleURL()
15
- }
16
-
17
- public override func bundleURL() -> URL? {
18
- if let bundleURLProvider = bundleURLOverride {
19
- return bundleURLProvider()
20
- }
21
-
22
- #if DEBUG
23
- return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: entryFile)
24
- #else
25
- let resourceURLComponents = bundlePath.components(separatedBy: ".")
26
- let withoutLast = resourceURLComponents[..<(resourceURLComponents.count - 1)]
27
- let resourceName = withoutLast.joined()
28
- let fileExtension = resourceURLComponents.last ?? ""
29
-
30
- return bundle.url(forResource: resourceName, withExtension: fileExtension)
3
+ #if canImport(Expo)
4
+ internal import Expo
31
5
  #endif
32
- }
33
- }
34
6
 
35
7
  @objc public class ReactNativeBrownfield: NSObject {
36
8
  public static let shared = ReactNativeBrownfield()
37
- private var onBundleLoaded: (() -> Void)?
38
- private var delegate = ReactNativeBrownfieldDelegate()
39
-
9
+
40
10
  /**
41
11
  * Path to JavaScript root.
42
- * Default value: "index"
12
+ * Default value: "index" for bare React Native, ".expo/.virtual-metro-entry" when built with Expo.
43
13
  */
44
- @objc public var entryFile: String = "index" {
14
+ @objc public var entryFile: String = {
15
+ #if canImport(Expo)
16
+ return ".expo/.virtual-metro-entry"
17
+ #else
18
+ return "index"
19
+ #endif
20
+ }() {
45
21
  didSet {
46
- delegate.entryFile = entryFile
22
+ #if canImport(Expo)
23
+ ExpoHostRuntime.shared.entryFile = entryFile
24
+ #else
25
+ ReactNativeHostRuntime.shared.entryFile = entryFile
26
+ #endif
47
27
  }
48
28
  }
49
- /**
50
- * Path to bundle fallback resource.
51
- * Default value: nil
52
- */
53
- @objc public var fallbackResource: String? = nil
29
+
54
30
  /**
55
31
  * Path to JavaScript bundle file.
56
32
  * Default value: "main.jsbundle"
57
33
  */
58
34
  @objc public var bundlePath: String = "main.jsbundle" {
59
35
  didSet {
60
- delegate.bundlePath = bundlePath
36
+ #if canImport(Expo)
37
+ ExpoHostRuntime.shared.bundlePath = bundlePath
38
+ #else
39
+ ReactNativeHostRuntime.shared.bundlePath = bundlePath
40
+ #endif
61
41
  }
62
42
  }
43
+
63
44
  /**
64
45
  * Bundle instance to lookup the JavaScript bundle.
65
46
  * Default value: Bundle.main
66
47
  */
67
- @objc public var bundle: Bundle = Bundle.main {
48
+ @objc public var bundle: Bundle = .main {
68
49
  didSet {
69
- delegate.bundle = bundle
50
+ #if canImport(Expo)
51
+ ExpoHostRuntime.shared.bundle = bundle
52
+ #else
53
+ ReactNativeHostRuntime.shared.bundle = bundle
54
+ #endif
70
55
  }
71
56
  }
57
+
72
58
  /**
73
59
  * Dynamic bundle URL provider called on every bundle load.
74
60
  * When set, this overrides the default bundleURL() behavior in the delegate.
@@ -77,95 +63,75 @@ class ReactNativeBrownfieldDelegate: RCTDefaultReactNativeFactoryDelegate {
77
63
  */
78
64
  @objc public var bundleURLOverride: (() -> URL?)? = nil {
79
65
  didSet {
80
- delegate.bundleURLOverride = bundleURLOverride
66
+ #if canImport(Expo)
67
+ ExpoHostRuntime.shared.bundleURLOverride = bundleURLOverride
68
+ #else
69
+ ReactNativeHostRuntime.shared.bundleURLOverride = bundleURLOverride
70
+ #endif
81
71
  }
82
72
  }
83
- /**
84
- * React Native factory instance created when starting React Native.
85
- * Default value: nil
86
- */
87
- private var reactNativeFactory: RCTReactNativeFactory? = nil
88
- /**
89
- * Root view factory used to create React Native views.
90
- */
91
- lazy private var rootViewFactory: RCTRootViewFactory? = {
92
- return reactNativeFactory?.rootViewFactory
93
- }()
94
-
73
+
95
74
  /**
96
75
  * Starts React Native with default parameters.
97
76
  */
98
77
  @objc public func startReactNative() {
99
- startReactNative(onBundleLoaded: nil)
78
+ #if canImport(Expo)
79
+ ExpoHostRuntime.shared.startReactNative()
80
+ #else
81
+ ReactNativeHostRuntime.shared.startReactNative()
82
+ #endif
100
83
  }
101
-
84
+
102
85
  @objc public func view(
103
86
  moduleName: String,
104
87
  initialProps: [AnyHashable: Any]?,
105
88
  launchOptions: [AnyHashable: Any]? = nil
106
89
  ) -> UIView? {
107
- rootViewFactory?.view(
108
- withModuleName: moduleName,
109
- initialProperties: initialProps,
90
+ #if canImport(Expo)
91
+ ExpoHostRuntime.shared.view(
92
+ moduleName: moduleName,
93
+ initialProps: initialProps,
94
+ launchOptions: launchOptions
95
+ )
96
+ #else
97
+ ReactNativeHostRuntime.shared.view(
98
+ moduleName: moduleName,
99
+ initialProps: initialProps,
110
100
  launchOptions: launchOptions
111
101
  )
102
+ #endif
112
103
  }
113
-
104
+
114
105
  /**
115
- * Starts React Native with optional callback when bundle is loaded.
116
- *
117
- * @param onBundleLoaded Optional callback invoked after JS bundle is fully loaded.
106
+ * Mirrors the host runtime app delegate API, forwarding to Expo or bare React Native as appropriate.
118
107
  */
119
- @objc public func startReactNative(onBundleLoaded: (() -> Void)?) {
120
- startReactNative(onBundleLoaded: onBundleLoaded, launchOptions: nil)
108
+ @objc public func application(
109
+ _ application: UIApplication,
110
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
111
+ ) -> Bool {
112
+ #if canImport(Expo)
113
+ return ExpoHostRuntime.shared.application(
114
+ application,
115
+ didFinishLaunchingWithOptions: launchOptions
116
+ )
117
+ #else
118
+ return ReactNativeHostRuntime.shared.application(
119
+ application,
120
+ didFinishLaunchingWithOptions: launchOptions
121
+ )
122
+ #endif
121
123
  }
122
-
124
+
123
125
  /**
124
- * Starts React Native with optional callback and launch options.
126
+ * Starts React Native with optional callback when bundle is loaded.
125
127
  *
126
128
  * @param onBundleLoaded Optional callback invoked after JS bundle is fully loaded.
127
- * @param launchOptions Launch options, typically passed from AppDelegate.
128
129
  */
129
- @objc public func startReactNative(onBundleLoaded: (() -> Void)?, launchOptions: [AnyHashable: Any]?) {
130
- guard reactNativeFactory == nil else { return }
131
-
132
- delegate.dependencyProvider = RCTAppDependencyProvider()
133
- self.reactNativeFactory = RCTReactNativeFactory(delegate: delegate)
134
-
135
- if let onBundleLoaded {
136
- self.onBundleLoaded = onBundleLoaded
137
- if RCTIsNewArchEnabled() {
138
- NotificationCenter.default.addObserver(
139
- self,
140
- selector: #selector(jsLoaded),
141
- name: NSNotification.Name("RCTInstanceDidLoadBundle"),
142
- object: nil
143
- )
144
- } else {
145
- NotificationCenter.default.addObserver(
146
- self,
147
- selector: #selector(jsLoaded),
148
- name: NSNotification.Name("RCTJavaScriptDidLoadNotification"),
149
- object: nil
150
- )
151
- }
152
- }
153
- }
154
-
155
- @objc private func jsLoaded(_ notification: Notification) {
156
- onBundleLoaded?()
157
- onBundleLoaded = nil
158
- NotificationCenter.default.removeObserver(self)
130
+ @objc public func startReactNative(onBundleLoaded: (() -> Void)?) {
131
+ #if canImport(Expo)
132
+ ExpoHostRuntime.shared.startReactNative(onBundleLoaded: onBundleLoaded)
133
+ #else
134
+ ReactNativeHostRuntime.shared.startReactNative(onBundleLoaded: onBundleLoaded)
135
+ #endif
159
136
  }
160
137
  }
161
-
162
- extension Notification.Name {
163
- /**
164
- * Notification sent when React Native wants to navigate back to native screen.
165
- */
166
- public static let popToNative = Notification.Name("PopToNativeNotification")
167
- /**
168
- * Notification sent to enable/disable the pop gesture recognizer.
169
- */
170
- public static let togglePopGestureRecognizer = Notification.Name("TogglePopGestureRecognizerNotification")
171
- }
@@ -0,0 +1,138 @@
1
+ import UIKit
2
+ internal import React
3
+ internal import React_RCTAppDelegate
4
+ internal import ReactAppDependencyProvider
5
+
6
+ class ReactNativeBrownfieldDelegate: RCTDefaultReactNativeFactoryDelegate {
7
+ var entryFile = "index"
8
+ var bundlePath = "main.jsbundle"
9
+ var bundle = Bundle.main
10
+ var bundleURLOverride: (() -> URL?)? = nil
11
+ // MARK: - RCTReactNativeFactoryDelegate Methods
12
+
13
+ override func sourceURL(for bridge: RCTBridge) -> URL? {
14
+ return bundleURL()
15
+ }
16
+
17
+ public override func bundleURL() -> URL? {
18
+ if let bundleURLProvider = bundleURLOverride {
19
+ return bundleURLProvider()
20
+ }
21
+
22
+ #if DEBUG
23
+ return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: entryFile)
24
+ #else
25
+ do {
26
+ let (resourceName, fileExtension) = try BrownfieldBundlePathResolver.resourceComponents(
27
+ from: bundlePath
28
+ )
29
+ return bundle.url(forResource: resourceName, withExtension: fileExtension)
30
+ } catch {
31
+ assertionFailure("Invalid bundlePath '\(bundlePath)': \(error)")
32
+ return nil
33
+ }
34
+ #endif
35
+ }
36
+ }
37
+
38
+ final class ReactNativeHostRuntime {
39
+ public static let shared = ReactNativeHostRuntime()
40
+ private let jsBundleLoadObserver = JSBundleLoadObserver()
41
+ private var delegate = ReactNativeBrownfieldDelegate()
42
+
43
+ /**
44
+ * Path to JavaScript root.
45
+ * Default value: "index"
46
+ */
47
+ public var entryFile: String = "index" {
48
+ didSet {
49
+ delegate.entryFile = entryFile
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Path to JavaScript bundle file.
55
+ * Default value: "main.jsbundle"
56
+ */
57
+ public var bundlePath: String = "main.jsbundle" {
58
+ didSet {
59
+ delegate.bundlePath = bundlePath
60
+ }
61
+ }
62
+ /**
63
+ * Bundle instance to lookup the JavaScript bundle.
64
+ * Default value: Bundle.main
65
+ */
66
+ public var bundle: Bundle = Bundle.main {
67
+ didSet {
68
+ delegate.bundle = bundle
69
+ }
70
+ }
71
+ /**
72
+ * Dynamic bundle URL provider called on every bundle load.
73
+ * When set, this overrides the default bundleURL() behavior in the delegate.
74
+ * Returns a URL to load a custom bundle, or nil to use default behavior.
75
+ * Default value: nil
76
+ */
77
+ public var bundleURLOverride: (() -> URL?)? = nil {
78
+ didSet {
79
+ delegate.bundleURLOverride = bundleURLOverride
80
+ }
81
+ }
82
+ /**
83
+ * React Native factory instance created when starting React Native.
84
+ * Default value: nil
85
+ */
86
+ private var reactNativeFactory: RCTReactNativeFactory? = nil
87
+ /**
88
+ * Root view factory used to create React Native views.
89
+ */
90
+ lazy private var rootViewFactory: RCTRootViewFactory? = {
91
+ return reactNativeFactory?.rootViewFactory
92
+ }()
93
+
94
+ /**
95
+ * Starts React Native with default parameters.
96
+ */
97
+ public func startReactNative() {
98
+ startReactNative(onBundleLoaded: nil)
99
+ }
100
+
101
+ public func view(
102
+ moduleName: String,
103
+ initialProps: [AnyHashable: Any]?,
104
+ launchOptions: [AnyHashable: Any]? = nil
105
+ ) -> UIView? {
106
+ rootViewFactory?.view(
107
+ withModuleName: moduleName,
108
+ initialProperties: initialProps,
109
+ launchOptions: launchOptions
110
+ )
111
+ }
112
+
113
+ /**
114
+ * Mirrors host manager app delegate API for bare React Native.
115
+ */
116
+ public func application(
117
+ _ application: UIApplication,
118
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
119
+ ) -> Bool {
120
+ return true
121
+ }
122
+
123
+ /**
124
+ * Starts React Native with optional callback when bundle is loaded.
125
+ *
126
+ * @param onBundleLoaded Optional callback invoked after JS bundle is fully loaded.
127
+ */
128
+ public func startReactNative(onBundleLoaded: (() -> Void)?) {
129
+ guard reactNativeFactory == nil else { return }
130
+
131
+ delegate.dependencyProvider = RCTAppDependencyProvider()
132
+ self.reactNativeFactory = RCTReactNativeFactory(delegate: delegate)
133
+
134
+ if let onBundleLoaded {
135
+ jsBundleLoadObserver.observeOnce(onBundleLoaded: onBundleLoaded)
136
+ }
137
+ }
138
+ }
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,"__esModule",{value:true});exports.brownfieldGradlePluginDependency=exports.BROWNFIELD_PLUGIN_VERSION=void 0;var BROWNFIELD_PLUGIN_VERSION=exports.BROWNFIELD_PLUGIN_VERSION='0.7.3';var brownfieldGradlePluginDependency=exports.brownfieldGradlePluginDependency=`classpath("com.callstack.react:brownfield-gradle-plugin:${BROWNFIELD_PLUGIN_VERSION}")`;
1
+ Object.defineProperty(exports,"__esModule",{value:true});exports.brownfieldGradlePluginDependency=exports.BROWNFIELD_PLUGIN_VERSION=void 0;var BROWNFIELD_PLUGIN_VERSION=exports.BROWNFIELD_PLUGIN_VERSION='1.0.0';var brownfieldGradlePluginDependency=exports.brownfieldGradlePluginDependency=`classpath("com.callstack.react:brownfield-gradle-plugin:${BROWNFIELD_PLUGIN_VERSION}")`;
2
2
  //# sourceMappingURL=constants.js.map
@@ -1,31 +1,8 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.modifyPodfile=modifyPodfile;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));var _SourceModificationError=require("../errors/SourceModificationError");var _logging=require("../logging");var _engine=require("../template/engine");var BROWNFIELD_POD_HOOK_MARKER_START='# >>> react-native-brownfield expo phase ordering >>>';var BROWNFIELD_POD_HOOK_MARKER_END='# <<< react-native-brownfield expo phase ordering <<<';function ensureExpoPhaseOrderingHook(podfile){if(podfile.includes(BROWNFIELD_POD_HOOK_MARKER_START)){return podfile;}var hook=`
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.modifyPodfile=modifyPodfile;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));var _SourceModificationError=require("../errors/SourceModificationError");var _logging=require("../logging");var _engine=require("../template/engine");var BROWNFIELD_POD_HOOK_MARKER_START='# >>> react-native-brownfield expo phase ordering >>>';var BROWNFIELD_POD_HOOK_MARKER_END='# <<< react-native-brownfield expo phase ordering <<<';var BROWNFIELD_POST_INTEGRATE_REQUIRE=`require File.join(File.dirname(\`node --print "require.resolve('@callstack/react-native-brownfield/package.json')"\`), "scripts/react_native_brownfield_post_integrate")`;var REACT_NATIVE_PODS_REQUIRE_REGEX=/^require File\.join\(File\.dirname\(`node --print "require\.resolve\('react-native\/package\.json'\)"`\), "scripts\/react_native_pods"\)\s*$/m;function ensureBrownfieldPostIntegrateRequire(podfile){if(podfile.includes('scripts/react_native_brownfield_post_integrate')){return podfile;}var reactNativePodsRequireMatch=podfile.match(REACT_NATIVE_PODS_REQUIRE_REGEX);if(reactNativePodsRequireMatch){var requireLine=reactNativePodsRequireMatch[0];return podfile.replace(requireLine,`${requireLine}\n${BROWNFIELD_POST_INTEGRATE_REQUIRE}\n`);}return`${BROWNFIELD_POST_INTEGRATE_REQUIRE}\n\n${podfile}`;}function ensureExpoPhaseOrderingHook(podfile){var modifiedPodfile=ensureBrownfieldPostIntegrateRequire(podfile);if(modifiedPodfile.includes(BROWNFIELD_POD_HOOK_MARKER_START)){return modifiedPodfile;}var hook=`
2
2
  ${BROWNFIELD_POD_HOOK_MARKER_START}
3
- def reorder_brownfield_expo_patch_phase!(installer)
4
- projects = installer.aggregate_targets.map(&:user_project).compact.uniq
5
- projects.each do |project|
6
- modified = false
7
-
8
- project.native_targets.each do |target|
9
- phases = target.build_phases
10
- expo_idx = phases.index { |p| p.respond_to?(:name) && p.name == '[Expo] Configure project' }
11
- patch_idx = phases.index { |p| p.respond_to?(:name) && p.name == 'Patch ExpoModulesProvider' }
12
-
13
- next if expo_idx.nil? || patch_idx.nil?
14
- next if patch_idx > expo_idx
15
-
16
- patch = phases.delete_at(patch_idx)
17
- expo_idx = phases.index { |p| p.respond_to?(:name) && p.name == '[Expo] Configure project' }
18
- phases.insert(expo_idx + 1, patch)
19
- modified = true
20
- end
21
-
22
- project.save if modified
23
- end
24
- end
25
-
26
3
  post_integrate do |installer|
27
- reorder_brownfield_expo_patch_phase!(installer)
4
+ react_native_brownfield_post_integrate(installer)
28
5
  end
29
6
  ${BROWNFIELD_POD_HOOK_MARKER_END}
30
- `;return`${podfile.trimEnd()}\n\n${hook}\n`;}function modifyPodfile(podfile,frameworkName,isExpoPre55){if(podfile.includes(`target '${frameworkName}'`)){_logging.Logger.logDebug(`Framework target "${frameworkName}" already in Podfile, skipping modification`);return podfile;}_logging.Logger.logDebug(`Modifying Podfile for framework: ${frameworkName}`);var frameworkTargetBlock=(0,_engine.renderTemplate)('ios','PodfileTargetBlock.rb',{'{{FRAMEWORK_NAME}}':frameworkName});var mainTargetMatch=podfile.match(/(target\s+['"][^'"]+['"]\s+do\s*\n)([\s\S]*?)(^end\s*$)/m);if(!mainTargetMatch){throw new _SourceModificationError.SourceModificationError('Could not find main target in Podfile. Please manually add the framework target.');}var _mainTargetMatch=(0,_slicedToArray2.default)(mainTargetMatch,3),targetStart=_mainTargetMatch[1],targetContent=_mainTargetMatch[2];var insertIndex=podfile.indexOf(mainTargetMatch[0])+targetStart.length+targetContent.length;var modifiedPodfile=podfile.slice(0,insertIndex)+frameworkTargetBlock+podfile.slice(insertIndex);_logging.Logger.logDebug(`Added framework target "${frameworkName}" to Podfile`);if(isExpoPre55){modifiedPodfile=ensureExpoPhaseOrderingHook(modifiedPodfile);}return modifiedPodfile;}
7
+ `;modifiedPodfile=`${modifiedPodfile.trimEnd()}\n\n${hook}\n`;return modifiedPodfile;}function modifyPodfile(podfile,frameworkName,isExpoPre55){if(podfile.includes(`target '${frameworkName}'`)){_logging.Logger.logDebug(`Framework target "${frameworkName}" already in Podfile, skipping modification`);return podfile;}_logging.Logger.logDebug(`Modifying Podfile for framework: ${frameworkName}`);var frameworkTargetBlock=(0,_engine.renderTemplate)('ios','PodfileTargetBlock.rb',{'{{FRAMEWORK_NAME}}':frameworkName});var mainTargetMatch=podfile.match(/(target\s+['"][^'"]+['"]\s+do\s*\n)([\s\S]*?)(^end\s*$)/m);if(!mainTargetMatch){throw new _SourceModificationError.SourceModificationError('Could not find main target in Podfile. Please manually add the framework target.');}var _mainTargetMatch=(0,_slicedToArray2.default)(mainTargetMatch,3),targetStart=_mainTargetMatch[1],targetContent=_mainTargetMatch[2];var insertIndex=podfile.indexOf(mainTargetMatch[0])+targetStart.length+targetContent.length;var modifiedPodfile=podfile.slice(0,insertIndex)+frameworkTargetBlock+podfile.slice(insertIndex);_logging.Logger.logDebug(`Added framework target "${frameworkName}" to Podfile`);if(isExpoPre55){modifiedPodfile=ensureExpoPhaseOrderingHook(modifiedPodfile);}return modifiedPodfile;}
31
8
  //# sourceMappingURL=podfileHelpers.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_SourceModificationError","require","_logging","_engine","BROWNFIELD_POD_HOOK_MARKER_START","BROWNFIELD_POD_HOOK_MARKER_END","ensureExpoPhaseOrderingHook","podfile","includes","hook","trimEnd","modifyPodfile","frameworkName","isExpoPre55","Logger","logDebug","frameworkTargetBlock","renderTemplate","mainTargetMatch","match","SourceModificationError","_mainTargetMatch","_slicedToArray2","default","targetStart","targetContent","insertIndex","indexOf","length","modifiedPodfile","slice"],"sourceRoot":"../../../../src","sources":["expo-config-plugin/ios/podfileHelpers.ts"],"mappings":"4QAAA,IAAAA,wBAAA,CAAAC,OAAA,sCACA,IAAAC,QAAA,CAAAD,OAAA,eACA,IAAAE,OAAA,CAAAF,OAAA,uBAEA,GAAM,CAAAG,gCAAgC,CACpC,uDAAuD,CACzD,GAAM,CAAAC,8BAA8B,CAClC,uDAAuD,CAEzD,QAAS,CAAAC,2BAA2BA,CAACC,OAAe,CAAU,CAC5D,GAAIA,OAAO,CAACC,QAAQ,CAACJ,gCAAgC,CAAC,CAAE,CACtD,MAAO,CAAAG,OAAO,CAChB,CAEA,GAAM,CAAAE,IAAI,CAAG;AACf,EAAEL,gCAAgC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAEC,8BAA8B;AAChC,CAAC,CAEC,MAAO,GAAGE,OAAO,CAACG,OAAO,CAAC,CAAC,OAAOD,IAAI,IAAI,CAC5C,CAQO,QAAS,CAAAE,aAAaA,CAC3BJ,OAAe,CACfK,aAAqB,CACrBC,WAAoB,CACZ,CAER,GAAIN,OAAO,CAACC,QAAQ,CAAC,WAAWI,aAAa,GAAG,CAAC,CAAE,CACjDE,eAAM,CAACC,QAAQ,CACb,qBAAqBH,aAAa,6CACpC,CAAC,CACD,MAAO,CAAAL,OAAO,CAChB,CAEAO,eAAM,CAACC,QAAQ,CAAC,oCAAoCH,aAAa,EAAE,CAAC,CAGpE,GAAM,CAAAI,oBAAoB,CAAG,GAAAC,sBAAc,EAAC,KAAK,CAAE,uBAAuB,CAAE,CAC1E,oBAAoB,CAAEL,aACxB,CAAC,CAAC,CAGF,GAAM,CAAAM,eAAe,CAAGX,OAAO,CAACY,KAAK,CACnC,0DACF,CAAC,CAED,GAAI,CAACD,eAAe,CAAE,CACpB,KAAM,IAAI,CAAAE,gDAAuB,CAC/B,kFACF,CAAC,CACH,CAEA,IAAAC,gBAAA,IAAAC,eAAA,CAAAC,OAAA,EAAuCL,eAAe,IAA7CM,WAAW,CAAAH,gBAAA,IAAEI,aAAa,CAAAJ,gBAAA,IACnC,GAAM,CAAAK,WAAW,CACfnB,OAAO,CAACoB,OAAO,CAACT,eAAe,CAAC,CAAC,CAAC,CAAC,CACnCM,WAAW,CAACI,MAAM,CAClBH,aAAa,CAACG,MAAM,CAEtB,GAAI,CAAAC,eAAe,CACjBtB,OAAO,CAACuB,KAAK,CAAC,CAAC,CAAEJ,WAAW,CAAC,CAC7BV,oBAAoB,CACpBT,OAAO,CAACuB,KAAK,CAACJ,WAAW,CAAC,CAE5BZ,eAAM,CAACC,QAAQ,CAAC,2BAA2BH,aAAa,cAAc,CAAC,CAEvE,GAAIC,WAAW,CAAE,CACfgB,eAAe,CAAGvB,2BAA2B,CAACuB,eAAe,CAAC,CAChE,CAEA,MAAO,CAAAA,eAAe,CACxB","ignoreList":[]}
1
+ {"version":3,"names":["_SourceModificationError","require","_logging","_engine","BROWNFIELD_POD_HOOK_MARKER_START","BROWNFIELD_POD_HOOK_MARKER_END","BROWNFIELD_POST_INTEGRATE_REQUIRE","REACT_NATIVE_PODS_REQUIRE_REGEX","ensureBrownfieldPostIntegrateRequire","podfile","includes","reactNativePodsRequireMatch","match","requireLine","replace","ensureExpoPhaseOrderingHook","modifiedPodfile","hook","trimEnd","modifyPodfile","frameworkName","isExpoPre55","Logger","logDebug","frameworkTargetBlock","renderTemplate","mainTargetMatch","SourceModificationError","_mainTargetMatch","_slicedToArray2","default","targetStart","targetContent","insertIndex","indexOf","length","slice"],"sourceRoot":"../../../../src","sources":["expo-config-plugin/ios/podfileHelpers.ts"],"mappings":"4QAAA,IAAAA,wBAAA,CAAAC,OAAA,sCACA,IAAAC,QAAA,CAAAD,OAAA,eACA,IAAAE,OAAA,CAAAF,OAAA,uBAEA,GAAM,CAAAG,gCAAgC,CACpC,uDAAuD,CACzD,GAAM,CAAAC,8BAA8B,CAClC,uDAAuD,CACzD,GAAM,CAAAC,iCAAiC,CAAG,0KAA0K,CACpN,GAAM,CAAAC,+BAA+B,CACnC,+IAA+I,CAEjJ,QAAS,CAAAC,oCAAoCA,CAACC,OAAe,CAAU,CACrE,GAAIA,OAAO,CAACC,QAAQ,CAAC,gDAAgD,CAAC,CAAE,CACtE,MAAO,CAAAD,OAAO,CAChB,CAEA,GAAM,CAAAE,2BAA2B,CAAGF,OAAO,CAACG,KAAK,CAC/CL,+BACF,CAAC,CACD,GAAII,2BAA2B,CAAE,CAC/B,GAAM,CAAAE,WAAW,CAAGF,2BAA2B,CAAC,CAAC,CAAC,CAClD,MAAO,CAAAF,OAAO,CAACK,OAAO,CACpBD,WAAW,CACX,GAAGA,WAAW,KAAKP,iCAAiC,IACtD,CAAC,CACH,CAEA,MAAO,GAAGA,iCAAiC,OAAOG,OAAO,EAAE,CAC7D,CAEA,QAAS,CAAAM,2BAA2BA,CAACN,OAAe,CAAU,CAC5D,GAAI,CAAAO,eAAe,CAAGR,oCAAoC,CAACC,OAAO,CAAC,CAEnE,GAAIO,eAAe,CAACN,QAAQ,CAACN,gCAAgC,CAAC,CAAE,CAC9D,MAAO,CAAAY,eAAe,CACxB,CAEA,GAAM,CAAAC,IAAI,CAAG;AACf,EAAEb,gCAAgC;AAClC;AACA;AACA;AACA,EAAEC,8BAA8B;AAChC,CAAC,CAECW,eAAe,CAAG,GAAGA,eAAe,CAACE,OAAO,CAAC,CAAC,OAAOD,IAAI,IAAI,CAE7D,MAAO,CAAAD,eAAe,CACxB,CAQO,QAAS,CAAAG,aAAaA,CAC3BV,OAAe,CACfW,aAAqB,CACrBC,WAAoB,CACZ,CAER,GAAIZ,OAAO,CAACC,QAAQ,CAAC,WAAWU,aAAa,GAAG,CAAC,CAAE,CACjDE,eAAM,CAACC,QAAQ,CACb,qBAAqBH,aAAa,6CACpC,CAAC,CACD,MAAO,CAAAX,OAAO,CAChB,CAEAa,eAAM,CAACC,QAAQ,CAAC,oCAAoCH,aAAa,EAAE,CAAC,CAGpE,GAAM,CAAAI,oBAAoB,CAAG,GAAAC,sBAAc,EAAC,KAAK,CAAE,uBAAuB,CAAE,CAC1E,oBAAoB,CAAEL,aACxB,CAAC,CAAC,CAGF,GAAM,CAAAM,eAAe,CAAGjB,OAAO,CAACG,KAAK,CACnC,0DACF,CAAC,CAED,GAAI,CAACc,eAAe,CAAE,CACpB,KAAM,IAAI,CAAAC,gDAAuB,CAC/B,kFACF,CAAC,CACH,CAEA,IAAAC,gBAAA,IAAAC,eAAA,CAAAC,OAAA,EAAuCJ,eAAe,IAA7CK,WAAW,CAAAH,gBAAA,IAAEI,aAAa,CAAAJ,gBAAA,IACnC,GAAM,CAAAK,WAAW,CACfxB,OAAO,CAACyB,OAAO,CAACR,eAAe,CAAC,CAAC,CAAC,CAAC,CACnCK,WAAW,CAACI,MAAM,CAClBH,aAAa,CAACG,MAAM,CAEtB,GAAI,CAAAnB,eAAe,CACjBP,OAAO,CAAC2B,KAAK,CAAC,CAAC,CAAEH,WAAW,CAAC,CAC7BT,oBAAoB,CACpBf,OAAO,CAAC2B,KAAK,CAACH,WAAW,CAAC,CAE5BX,eAAM,CAACC,QAAQ,CAAC,2BAA2BH,aAAa,cAAc,CAAC,CAEvE,GAAIC,WAAW,CAAE,CACfL,eAAe,CAAGD,2BAA2B,CAACC,eAAe,CAAC,CAChE,CAEA,MAAO,CAAAA,eAAe,CACxB","ignoreList":[]}