refactor: Rewrite JSBundleLoader from Java to Kotlin (#50911)

Summary:
Rewrite of JSBundleLoader from Java to Kotlin in scope of https://github.com/facebook/react-native/issues/50513

## Changelog:
[ANDROID] [CHANGED] - Migrated JSBundleLoader to Kotlin

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

Pull Request resolved: https://github.com/facebook/react-native/pull/50911

Test Plan: Tested using RNTester app, on both old and new arch, and tested by navigating to multiple pages

Reviewed By: cortinico

Differential Revision: D73649145

Pulled By: javache

fbshipit-source-id: 7ef1fc1ea1c53a8b914ae1aada1966e64b4c3d80
This commit is contained in:
Yogesh Choudhary Paliyal
2025-04-25 05:23:43 -07:00
committed by Facebook GitHub Bot
parent 0c8f3aca0e
commit de165a2cfd
3 changed files with 113 additions and 104 deletions
@@ -770,15 +770,24 @@ public final class com/facebook/react/bridge/JSApplicationIllegalArgumentExcepti
}
public abstract class com/facebook/react/bridge/JSBundleLoader {
public static final field Companion Lcom/facebook/react/bridge/JSBundleLoader$Companion;
public fun <init> ()V
public static fun createAssetLoader (Landroid/content/Context;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
public static fun createCachedBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static fun createCachedSplitBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static fun createFileLoader (Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static fun createFileLoader (Ljava/lang/String;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
public static final fun createAssetLoader (Landroid/content/Context;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
public static final fun createCachedBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static final fun createCachedSplitBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static final fun createFileLoader (Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public static final fun createFileLoader (Ljava/lang/String;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
public abstract fun loadScript (Lcom/facebook/react/bridge/JSBundleLoaderDelegate;)Ljava/lang/String;
}
public final class com/facebook/react/bridge/JSBundleLoader$Companion {
public final fun createAssetLoader (Landroid/content/Context;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
public final fun createCachedBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public final fun createCachedSplitBundleFromNetworkLoader (Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public final fun createFileLoader (Ljava/lang/String;)Lcom/facebook/react/bridge/JSBundleLoader;
public final fun createFileLoader (Ljava/lang/String;Ljava/lang/String;Z)Lcom/facebook/react/bridge/JSBundleLoader;
}
public abstract interface class com/facebook/react/bridge/JSBundleLoaderDelegate {
public abstract fun loadScriptFromAssets (Landroid/content/res/AssetManager;Ljava/lang/String;Z)V
public abstract fun loadScriptFromFile (Ljava/lang/String;Ljava/lang/String;Z)V
@@ -1,99 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import android.content.Context;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.common.DebugServerException;
import java.util.Objects;
/** A class that stores JS bundle information and allows a {@link JSBundleLoaderDelegate}. */
@Nullsafe(Nullsafe.Mode.LOCAL)
public abstract class JSBundleLoader {
/**
* This loader is recommended one for release version of your app. In that case local JS executor
* should be used. JS bundle will be read from assets in native code to save on passing large
* strings from java to native memory.
*/
public static JSBundleLoader createAssetLoader(
final Context context, final String assetUrl, final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
}
/**
* This loader loads bundle from file system. The bundle will be read in native code to save on
* passing large strings from java to native memory.
*/
public static JSBundleLoader createFileLoader(final String fileName) {
return createFileLoader(fileName, fileName, false);
}
public static JSBundleLoader createFileLoader(
final String fileName, final String assetUrl, final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
return fileName;
}
};
}
/**
* This loader is used when bundle gets reloaded from dev server. In that case loader expect JS
* bundle to be prefetched and stored in local file. We do that to avoid passing large strings
* between java and native code and avoid allocating memory in java to fit whole JS bundle in it.
* Providing correct {@param sourceURL} of downloaded bundle is required for JS stacktraces to
* work correctly and allows for source maps to correctly symbolize those.
*/
public static JSBundleLoader createCachedBundleFromNetworkLoader(
final String sourceURL, final String cachedFileLocation) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(
sourceURL, Objects.toString(e.getMessage(), ""), e);
}
}
};
}
/**
* Same as {{@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}}, but for
* split bundles in development.
*/
public static JSBundleLoader createCachedSplitBundleFromNetworkLoader(
final String sourceURL, final String cachedFileLocation) {
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadSplitBundleFromFile(cachedFileLocation, sourceURL);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(
sourceURL, Objects.toString(e.getMessage(), ""), e);
}
}
};
}
/** Loads the script, returning the URL of the source it loaded. */
public abstract String loadScript(JSBundleLoaderDelegate delegate);
}
@@ -0,0 +1,99 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge
import android.content.Context
import com.facebook.react.common.DebugServerException
/** A class that stores JS bundle information and allows a [JSBundleLoaderDelegate]. */
public abstract class JSBundleLoader {
/** Loads the script, returning the URL of the source it loaded. */
public abstract fun loadScript(delegate: JSBundleLoaderDelegate): String
public companion object {
/**
* This loader is recommended one for release version of your app. In that case local JS
* executor should be used. JS bundle will be read from assets in native code to save on passing
* large strings from java to native memory.
*/
@JvmStatic
public fun createAssetLoader(
context: Context,
assetUrl: String,
loadSynchronously: Boolean
): JSBundleLoader =
object : JSBundleLoader() {
override fun loadScript(delegate: JSBundleLoaderDelegate): String {
delegate.loadScriptFromAssets(context.assets, assetUrl, loadSynchronously)
return assetUrl
}
}
/**
* This loader loads bundle from file system. The bundle will be read in native code to save on
* passing large strings from java to native memory.
*/
@JvmStatic
public fun createFileLoader(fileName: String): JSBundleLoader =
createFileLoader(fileName, fileName, false)
@JvmStatic
public fun createFileLoader(
fileName: String,
assetUrl: String,
loadSynchronously: Boolean
): JSBundleLoader =
object : JSBundleLoader() {
override fun loadScript(delegate: JSBundleLoaderDelegate): String {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously)
return fileName
}
}
/**
* This loader is used when bundle gets reloaded from dev server. In that case loader expect JS
* bundle to be prefetched and stored in local file. We do that to avoid passing large strings
* between java and native code and avoid allocating memory in java to fit whole JS bundle in
* it. Providing correct [sourceURL] of downloaded bundle is required for JS stacktraces to work
* correctly and allows for source maps to correctly symbolize those.
*/
@JvmStatic
public fun createCachedBundleFromNetworkLoader(
sourceURL: String,
cachedFileLocation: String
): JSBundleLoader =
object : JSBundleLoader() {
override fun loadScript(delegate: JSBundleLoaderDelegate): String {
return try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false)
sourceURL
} catch (e: Exception) {
throw DebugServerException.makeGeneric(sourceURL, e.message.orEmpty(), e)
}
}
}
/** Same as [createCachedBundleFromNetworkLoader], but for split bundles in development. */
@JvmStatic
public fun createCachedSplitBundleFromNetworkLoader(
sourceURL: String,
cachedFileLocation: String
): JSBundleLoader =
object : JSBundleLoader() {
override fun loadScript(delegate: JSBundleLoaderDelegate): String {
return try {
delegate.loadSplitBundleFromFile(cachedFileLocation, sourceURL)
sourceURL
} catch (e: Exception) {
throw DebugServerException.makeGeneric(sourceURL, e.message.orEmpty(), e)
}
}
}
}
}