-
Notifications
You must be signed in to change notification settings - Fork 33
(feat): add method to deallocate reactNativeFactory instance #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@callstack/react-native-brownfield': minor | ||
| --- | ||
|
|
||
| feat: add method to deallocate reactNativeFactory instance |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,17 @@ final class ExpoHostRuntime { | |
| private var reactNativeFactory: RCTReactNativeFactory? | ||
| private var expoDelegate: ExpoAppDelegate? | ||
|
|
||
| private var factory: RCTReactNativeFactory { | ||
| if let existingFactory = reactNativeFactory { | ||
| return existingFactory | ||
| } | ||
|
|
||
| delegate.dependencyProvider = RCTAppDependencyProvider() | ||
| let createdFactory = ExpoReactNativeFactory(delegate: delegate) | ||
| reactNativeFactory = createdFactory | ||
| return createdFactory | ||
| } | ||
|
|
||
| /** | ||
| * Starts React Native with default parameters. | ||
| */ | ||
|
|
@@ -28,11 +39,6 @@ final class ExpoHostRuntime { | |
| public func startReactNative(onBundleLoaded: (() -> Void)?) { | ||
| guard reactNativeFactory == nil else { return } | ||
|
|
||
| let factory = ExpoReactNativeFactory(delegate: delegate) | ||
| delegate.dependencyProvider = RCTAppDependencyProvider() | ||
|
|
||
| reactNativeFactory = factory | ||
|
|
||
| let appDelegate = ExpoAppDelegate() | ||
| // below: https://github.com/expo/expo/pull/39418/changes/5abd332b55b2ee7daee848284ed5f7fe1639452e | ||
| // has removed bindReactNativeFactory method from ExpoAppDelegate | ||
|
|
@@ -46,6 +52,24 @@ final class ExpoHostRuntime { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Stops React Native and releases the underlying factory instance. | ||
| */ | ||
| public func stopReactNative() { | ||
| if !Thread.isMainThread { | ||
| DispatchQueue.main.async { [weak self] in self?.stopReactNative() } | ||
| return | ||
| } | ||
|
|
||
| #if !EXPO_SDK_GTE_55 | ||
| guard let factory = reactNativeFactory else { return } | ||
| factory.bridge?.invalidate() | ||
| #endif | ||
|
Comment on lines
+64
to
+67
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is here because there is no bridge instance on Expo > 55?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| reactNativeFactory = nil | ||
| expoDelegate = nil | ||
| } | ||
|
|
||
| /** | ||
| * Path to JavaScript root. | ||
| * Default value: ".expo/.virtual-metro-entry" | ||
|
|
@@ -125,19 +149,19 @@ final class ExpoHostRuntime { | |
| // below: https://github.com/expo/expo/commit/2013760c46cde1404872d181a691da72fbf207a4 | ||
| // has moved the recreateRootView method to ExpoReactNativeFactory | ||
| #if EXPO_SDK_GTE_55 // this define comes from the Brownfield Expo config plugin | ||
| return (reactNativeFactory as? ExpoReactNativeFactory)?.recreateRootView( | ||
| withBundleURL: bundleURL, | ||
| moduleName: moduleName, | ||
| initialProps: initialProps, | ||
| launchOptions: launchOptions | ||
| ) | ||
| return (factory as? ExpoReactNativeFactory)?.recreateRootView( | ||
| withBundleURL: bundleURL, | ||
| moduleName: moduleName, | ||
| initialProps: initialProps, | ||
| launchOptions: launchOptions | ||
| ) | ||
| #else | ||
| return expoDelegate?.recreateRootView( | ||
| withBundleURL: bundleURL, | ||
| moduleName: moduleName, | ||
| initialProps: initialProps, | ||
| launchOptions: launchOptions | ||
| ) | ||
| return expoDelegate?.recreateRootView( | ||
| withBundleURL: bundleURL, | ||
| moduleName: moduleName, | ||
| initialProps: initialProps, | ||
| launchOptions: launchOptions | ||
| ) | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,6 +59,7 @@ final class ReactNativeHostRuntime { | |
| delegate.bundlePath = bundlePath | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Bundle instance to lookup the JavaScript bundle. | ||
| * Default value: Bundle.main | ||
|
|
@@ -68,6 +69,7 @@ final class ReactNativeHostRuntime { | |
| delegate.bundle = bundle | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Dynamic bundle URL provider called on every bundle load. | ||
| * When set, this overrides the default bundleURL() behavior in the delegate. | ||
|
|
@@ -79,17 +81,23 @@ final class ReactNativeHostRuntime { | |
| delegate.bundleURLOverride = bundleURLOverride | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * React Native factory instance created when starting React Native. | ||
| * Default value: nil | ||
| */ | ||
| private var reactNativeFactory: RCTReactNativeFactory? = nil | ||
| /** | ||
| * Root view factory used to create React Native views. | ||
| */ | ||
| lazy private var rootViewFactory: RCTRootViewFactory? = { | ||
| return reactNativeFactory?.rootViewFactory | ||
| }() | ||
|
|
||
| private var factory: RCTReactNativeFactory { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. likewise
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here - please, @hurali97 , check my second commit |
||
| if let existingFactory = reactNativeFactory { | ||
| return existingFactory | ||
| } | ||
|
|
||
| delegate.dependencyProvider = RCTAppDependencyProvider() | ||
| let createdFactory = RCTReactNativeFactory(delegate: delegate) | ||
| reactNativeFactory = createdFactory | ||
| return createdFactory | ||
| } | ||
|
|
||
| /** | ||
| * Starts React Native with default parameters. | ||
|
|
@@ -98,12 +106,28 @@ final class ReactNativeHostRuntime { | |
| startReactNative(onBundleLoaded: nil) | ||
| } | ||
|
|
||
| /** | ||
| * Stops React Native and releases the underlying factory instance. | ||
| */ | ||
| public func stopReactNative() { | ||
| if !Thread.isMainThread { | ||
| DispatchQueue.main.async { [weak self] in self?.stopReactNative() } | ||
| return | ||
| } | ||
|
|
||
| guard let factory = reactNativeFactory else { return } | ||
|
|
||
| factory.bridge?.invalidate() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we can skip this invocation as we do not support old arch anymore? And if I recall correctly on newer versions of RN, this
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we still do - we have a separate sourceset on Android. Not all APIs support it (e.g. I'd leave it as-is, unless you object?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recall we did a few PRs to remove the old arch support, when react-native decided to drop it. For instance, here - we previously provided a way for old arch but that was removed. As part of this - we dropped support for old arch on Android - #148 I see that we still have a few places with old arch, we can plan removing those now. |
||
|
|
||
| reactNativeFactory = nil | ||
| } | ||
|
|
||
| public func view( | ||
| moduleName: String, | ||
| initialProps: [AnyHashable: Any]?, | ||
| launchOptions: [AnyHashable: Any]? = nil | ||
| ) -> UIView? { | ||
| rootViewFactory?.view( | ||
| factory.rootViewFactory.view( | ||
| withModuleName: moduleName, | ||
| initialProperties: initialProps, | ||
| launchOptions: launchOptions | ||
|
|
@@ -144,9 +168,6 @@ final class ReactNativeHostRuntime { | |
| public func startReactNative(onBundleLoaded: (() -> Void)?) { | ||
| guard reactNativeFactory == nil else { return } | ||
|
|
||
| delegate.dependencyProvider = RCTAppDependencyProvider() | ||
| self.reactNativeFactory = RCTReactNativeFactory(delegate: delegate) | ||
|
|
||
| if let onBundleLoaded { | ||
| jsBundleLoadObserver.observeOnce(onBundleLoaded: onBundleLoaded) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already create a factory instance in
startReactNativeand assign it asreactNativeFactory. So I believe we do not need to create anotherfactoryinstance here. I know that it will only create a new instance ifreactNativeFactoryisnilBUT if we think about it, this instance will only be nil ifstartReactNativehasn't been called ORstopReactNativehave been called already.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hurali97 some duplicated code removed in my second commit, please check it again