Skip to content

Conversation

@gronxb
Copy link

@gronxb gronxb commented Jan 16, 2026

Summary

https://discord.com/channels/426714625279524876/1460917572894457968/1461699896594792677

I’m integrating HotUpdater. After an OTA update, HotUpdater uses the bundle from the file system.

Return values of HotUpdater.getJSBundleFile():

Without an OTA bundle (initial state):
"assets://index.android.bundle"

With an OTA bundle:
"/storage/emulated/0/Android/data/com.callstack.brownfield.android.example/files/bundle-store/019bc77b-d454-7ccd-9d39-721800a3026d/index.android.bundle"

Therefore, when the app is closed and reopened, file path access also needs to be allowed.

Test plan

  1. fork example and change this code
package com.rnapp.brownfieldlib

import android.app.Application
import com.callstack.reactnativebrownfield.OnJSBundleLoaded
import com.callstack.reactnativebrownfield.ReactNativeBrownfield
import com.facebook.react.PackageList
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import com.hotupdater.HotUpdater

object ReactNativeHostManager {
    fun initialize(application: Application, onJSBundleLoaded: OnJSBundleLoaded? = null) {
        loadReactNative(application)

        val packageList = PackageList(application).packages
        val options = hashMapOf<String, Any>(
            "packages" to packageList,
            "mainModuleName" to "index",
            "bundleAssetPath" to HotUpdater.getJSBundleFile(application),
            "useDeveloperSupport" to false
        )

        ReactNativeBrownfield.initialize(application, options) { initialized ->
            // Set ReactHost in HotUpdater after initialization
            HotUpdater.setReactHost(ReactNativeBrownfield.shared.reactHost)
            onJSBundleLoaded?.invoke(initialized)
        }
    }

    fun destroy() {
        HotUpdater.clearReactHost()
    }
}
2026-01-17.12.54.13.mov

@thymikee thymikee requested a review from artus9033 January 16, 2026 15:55
Copy link
Collaborator

@artus9033 artus9033 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @gronxb ! Thank you for contributing, this is a useful feature. Left two minor comments - I'll be happy to merge when they're addressed!

.filterIsInstance<ReactPackage>(),
jsMainModulePath = options["mainModuleName"] as? String ?: "index",
jsBundleAssetPath = options["bundleAssetPath"] as? String ?: "index.android.bundle",
jsBundleAssetPath = if (isFilePath) "index.android.bundle" else bundlePath,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, how about always passing bundlePath to jsBundleAssetPath? In RN source indeed jsBundleAssetPath is not effective if jsBundleFilePath is provided, but if the behaviour was to somehow change in the future, we would've had a 'silent' potential cause of problems here. If we set it to bundlePath, we will be more resilient.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually like it even more! I was worried that changing the name might be considered an API change, but this is exactly what I wanted.

Copy link
Author

@gronxb gronxb Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I change options["bundleAssetPath"] to options["bundlePath"]?

Since this is a breaking change, it will affect existing code, but it would result in a clearer name.
What would you prefer to do?

) {
val reactHost: ReactHost by lazy {
val bundlePath = options["bundleAssetPath"] as? String ?: "index.android.bundle"
val isFilePath = bundlePath.startsWith("/") || bundlePath.startsWith("file://")
Copy link
Collaborator

@artus9033 artus9033 Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] Would you mind adding || bundlePath.startsWith("assets://") to isFilePath? RN's DefaultReactHost has logic for this non-standard protocol (even though the docstring mentions only the file:// protocol).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@gronxb gronxb requested a review from artus9033 January 16, 2026 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants