-
Notifications
You must be signed in to change notification settings - Fork 24.9k
Android: Add setBundleSource
method to ReactHost
for changing bundle URL at runtime
#54139
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
Draft
coado
wants to merge
1
commit into
facebook:main
Choose a base branch
from
coado:bundle-url-android
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…dle URL at runtime (facebook#54139) Summary: Following the [RFC](react-native-community/discussions-and-proposals#933), this PR adds new `setBundleSource` methods to `ReactHost` for modifying bundle URL at runtime. The first one with signature: ```Kotlin public fun setBundleSource(debugServerHost: String, moduleName: String, queryBuilder: (Map<String, String>) -> Map<String, String> = { it }) ``` takes debugServerHost (set in packager connection settings), moduleName (set in DevSupportManager's jsAppBundleName), and queryBuilder (set in packager connection settings). Before updating settings, the packager connection is closed to reset the packager client, which will be newly created during reload with updated configuration. The second one for loading bundle from the file takes single `filePath` argument: ```Kotlin public fun setBundleSource(filePath: String) ``` It sets `customBundleFilePath` in `DevSupportManager` which has priority over other methods of loading the bundle in `jsBundleLoader` and reloads `ReactHost`. ## Changelog: [ANDROID][ADDED] - added new `setBundleSource` method to `ReactHost` for changing bundle URL at runtime. Test Plan: Started with running two Metro instances on ports `8081` and `8082` (first with white background, second with blue). Created a native button that toggles `debugServerHost` port and invokes `setBundleSource`. https://github.com/user-attachments/assets/7afe2cbc-6fef-44bc-930c-e9f9c4edd2bd For setting bundle file path, generated JS bundle with different background comparing to the one serving by Metro. Moved file to the `app/files` directory in android emulator and configured native button to invoke a `setBundleSource(filePath)`. https://github.com/user-attachments/assets/5e59d7b7-c6ae-475c-94e3-50d4ac69cf24 <details> <summary>code:</summary> Changing debug server host: `RNTesterActivity.kt`: ```Kotlin package com.facebook.react.uiapp import android.content.res.Configuration import android.graphics.Color import android.os.Bundle import android.view.View import android.widget.Button import android.widget.FrameLayout import androidx.core.graphics.drawable.toDrawable import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import com.facebook.common.logging.FLog import com.facebook.react.FBRNTesterEndToEndHelper import com.facebook.react.ReactActivity import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate import java.io.FileDescriptor import java.io.PrintWriter internal class RNTesterActivity : ReactActivity() { private var activePort = "8081" class RNTesterActivityDelegate(val activity: ReactActivity, mainComponentName: String) : DefaultReactActivityDelegate(activity, mainComponentName, fabricEnabled) { private val PARAM_ROUTE = "route" private lateinit var initialProps: Bundle override fun onCreate(savedInstanceState: Bundle?) { // Get remote param before calling super which uses it val bundle = activity.intent?.extras if (bundle != null && bundle.containsKey(PARAM_ROUTE)) { val routeUri = "rntester://example/${bundle.getString(PARAM_ROUTE)}Example" initialProps = Bundle().apply { putString("exampleFromAppetizeParams", routeUri) } } FBRNTesterEndToEndHelper.onCreate(activity.application) super.onCreate(savedInstanceState) } override fun getLaunchOptions() = if (this::initialProps.isInitialized) initialProps else Bundle() } private fun getButtonText(): String { return "Port: $activePort" } private fun setupPortButton(onClick: () -> Unit) { val portButton = Button(this).apply { text = getButtonText() setBackgroundColor(Color.rgb(0, 123, 255)) // Blue background setTextColor(Color.WHITE) setPadding(32, 16, 32, 16) textSize = 16f elevation = 8f } // Get the root view and add button to it val rootView = this.findViewById<FrameLayout>(android.R.id.content) val layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT ).apply { gravity = android.view.Gravity.TOP or android.view.Gravity.CENTER_HORIZONTAL topMargin = 200 // 50dp from top } rootView.addView(portButton, layoutParams) portButton.setOnClickListener { onClick() portButton.text = getButtonText() } } // set background color so it will show below transparent system bars on forced edge-to-edge private fun maybeUpdateBackgroundColor() { val isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES val color = if (isDarkMode) { Color.rgb(11, 6, 0) } else { Color.rgb(243, 248, 255) } window?.setBackgroundDrawable(color.toDrawable()) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) fullyDrawnReporter.addReporter() maybeUpdateBackgroundColor() reactDelegate?.reactHost?.let { setupPortButton { activePort = if (activePort == "8081") "8082" else "8081" reactHost.setBundleSource("10.0.2.2:$activePort", "js/RNTesterApp.android") // reactHost.setBundleSource("/data/user/0/com.facebook.react.uiapp/files/android.bundle") } } // register insets listener to update margins on the ReactRootView to avoid overlap w/ system // bars reactDelegate?.reactRootView?.let { rootView -> val insetsType: Int = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() val windowInsetsListener = { view: View, windowInsets: WindowInsetsCompat -> val insets = windowInsets.getInsets(insetsType) (view.layoutParams as FrameLayout.LayoutParams).apply { setMargins(insets.left, insets.top, insets.right, insets.bottom) } WindowInsetsCompat.CONSUMED } ViewCompat.setOnApplyWindowInsetsListener(rootView, windowInsetsListener) } } override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // update background color on UI mode change maybeUpdateBackgroundColor() } override fun createReactActivityDelegate() = RNTesterActivityDelegate(this, mainComponentName) override fun getMainComponentName() = "RNTesterApp" override fun dump( prefix: String, fd: FileDescriptor?, writer: PrintWriter, args: Array<String>?, ) { FBRNTesterEndToEndHelper.maybeDump(prefix, writer, args) } } ``` </detail> Differential Revision: D84713639 Pulled By: coado
08cd3b8
to
7713574
Compare
cortinico
requested changes
Oct 17, 2025
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.
Review automatically exported from Phabricator review in Meta.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
CLA Signed
This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
fb-exported
meta-exported
p: Facebook
Partner: Facebook
p: Software Mansion
Partner: Software Mansion
Partner
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary:
Following the RFC, this PR adds new
setBundleSource
methods toReactHost
for modifying bundle URL at runtime. The first one with signature:takes
debugServerHost
(set in packager connection settings),moduleName
(set in DevSupportManager's jsAppBundleName), andqueryBuilder
(set in packager connection settings). Before updating settings, the packager connection is closed to reset the packager client, which will be newly created during reload with updated configuration.The second one for loading bundle from the file takes single
filePath
argument:It sets
customBundleFilePath
inDevSupportManager
which has priority over other methods of loading the bundle injsBundleLoader
and reloadsReactHost
.It also changes host caching in
PackagerConnectionSettings
to prevent storage on the device, as this leads to a problem when the bundle source is changed, for instance, from the default10.0.2.2:8081
to10.0.2.2:8082
. Then, the new bundle source is persisted, but it fails to load the bundle from the default source after restarting the app, which is probably not a desired behavior. This can be observed using the existing option in the dev menu for changing bundle location and restarting the app. It won't try to connect to the default Metro address and will fail with the following error:On iOS it works as expected.
Changelog:
[ANDROID][ADDED] - added new
setBundleSource
method toReactHost
for changing bundle URL at runtime.Test Plan:
Started with running two Metro instances on ports
8081
and8082
(first with white background, second with blue). Created a native button that togglesdebugServerHost
port and invokessetBundleSource
.android-setBundleSource.mov
For setting bundle file path, generated JS bundle with different background comparing to the one serving by Metro. Moved file to the
app/files
directory in android emulator and configured native button to invoke asetBundleSource(filePath)
.load_from_file.mov
code:
Changing debug server host:
RNTesterActivity.kt
: