mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add native module for loading split JS bundles in development
Reviewed By: mdvacca, cpojer Differential Revision: D22001709 fbshipit-source-id: 4e378fd6ae90268e7db9092a71628205b9f7c37d
This commit is contained in:
committed by
Facebook GitHub Bot
parent
2e2c881147
commit
fca3a39da5
@@ -35,6 +35,7 @@ rn_android_library(
|
||||
react_native_target("java/com/facebook/react/module/model:model"),
|
||||
react_native_target("java/com/facebook/react/modules/appregistry:appregistry"),
|
||||
react_native_target("java/com/facebook/react/modules/appearance:appearance"),
|
||||
react_native_target("java/com/facebook/react/modules/bundleloader:bundleloader"),
|
||||
react_native_target("java/com/facebook/react/modules/debug:debug"),
|
||||
react_native_target("java/com/facebook/react/modules/fabric:fabric"),
|
||||
react_native_target("java/com/facebook/react/modules/debug:interfaces"),
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.module.annotations.ReactModuleList;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
||||
import com.facebook.react.modules.bundleloader.NativeDevSplitBundleLoaderModule;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.modules.core.ExceptionsManagerModule;
|
||||
@@ -56,6 +57,7 @@ import java.util.Map;
|
||||
SourceCodeModule.class,
|
||||
TimingModule.class,
|
||||
UIManagerModule.class,
|
||||
NativeDevSplitBundleLoaderModule.class,
|
||||
})
|
||||
public class CoreModulesPackage extends TurboReactPackage implements ReactPackageLogger {
|
||||
|
||||
@@ -101,7 +103,8 @@ public class CoreModulesPackage extends TurboReactPackage implements ReactPackag
|
||||
HeadlessJsTaskSupportModule.class,
|
||||
SourceCodeModule.class,
|
||||
TimingModule.class,
|
||||
UIManagerModule.class
|
||||
UIManagerModule.class,
|
||||
NativeDevSplitBundleLoaderModule.class,
|
||||
};
|
||||
|
||||
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
|
||||
@@ -158,6 +161,9 @@ public class CoreModulesPackage extends TurboReactPackage implements ReactPackag
|
||||
return createUIManager(reactContext);
|
||||
case DeviceInfoModule.NAME:
|
||||
return new DeviceInfoModule(reactContext);
|
||||
case NativeDevSplitBundleLoaderModule.NAME:
|
||||
return new NativeDevSplitBundleLoaderModule(
|
||||
reactContext, mReactInstanceManager.getDevSupportManager());
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"In CoreModulesPackage, could not find Native module for " + name);
|
||||
|
||||
@@ -240,6 +240,11 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
||||
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSplitBundleFromFile(String fileName, String sourceURL) {
|
||||
jniLoadScriptFromFile(fileName, sourceURL, false);
|
||||
}
|
||||
|
||||
private native void jniSetSourceURL(String sourceURL);
|
||||
|
||||
private native void jniRegisterSegment(int segmentId, String path);
|
||||
|
||||
@@ -73,6 +73,25 @@ public abstract class JSBundleLoader {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This loader is used when proxy debugging is enabled. In that case there is no point in fetching
|
||||
* the bundle from device as remote executor will have to do it anyway.
|
||||
|
||||
@@ -33,6 +33,12 @@ public interface JSBundleLoaderDelegate {
|
||||
*/
|
||||
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
|
||||
|
||||
/**
|
||||
* Load a split JS bundle from the filesystem. See {@link
|
||||
* JSBundleLoader#createCachedSplitBundleFromNetworkLoader(String, String)}.
|
||||
*/
|
||||
void loadSplitBundleFromFile(String fileName, String sourceURL);
|
||||
|
||||
/**
|
||||
* This API is used in situations where the JS bundle is being executed not on the device, but on
|
||||
* a host machine. In that case, we must provide two source URLs for the JS bundle: One to be used
|
||||
|
||||
@@ -40,16 +40,25 @@ public class DebugServerException extends RuntimeException {
|
||||
return new DebugServerException(reason + message + extra, t);
|
||||
}
|
||||
|
||||
private final String mOriginalMessage;
|
||||
|
||||
private DebugServerException(String description, String fileName, int lineNumber, int column) {
|
||||
super(description + "\n at " + fileName + ":" + lineNumber + ":" + column);
|
||||
mOriginalMessage = description;
|
||||
}
|
||||
|
||||
public DebugServerException(String description) {
|
||||
super(description);
|
||||
mOriginalMessage = description;
|
||||
}
|
||||
|
||||
public DebugServerException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
mOriginalMessage = detailMessage;
|
||||
}
|
||||
|
||||
public String getOriginalMessage() {
|
||||
return mOriginalMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -107,10 +107,7 @@ public class BundleDownloader {
|
||||
Request.Builder requestBuilder) {
|
||||
|
||||
final Request request =
|
||||
requestBuilder
|
||||
.url(formatBundleUrl(bundleURL))
|
||||
.addHeader("Accept", "multipart/mixed")
|
||||
.build();
|
||||
requestBuilder.url(bundleURL).addHeader("Accept", "multipart/mixed").build();
|
||||
mDownloadBundleFromURLCall = Assertions.assertNotNull(mClient.newCall(request));
|
||||
mDownloadBundleFromURLCall.enqueue(
|
||||
new Callback() {
|
||||
@@ -165,10 +162,6 @@ public class BundleDownloader {
|
||||
});
|
||||
}
|
||||
|
||||
private String formatBundleUrl(String bundleURL) {
|
||||
return bundleURL;
|
||||
}
|
||||
|
||||
private void processMultipartResponse(
|
||||
final String url,
|
||||
final Response response,
|
||||
|
||||
@@ -419,15 +419,26 @@ public class DevServerHelper {
|
||||
}
|
||||
|
||||
private String createBundleURL(String mainModuleID, BundleType type, String host) {
|
||||
return createBundleURL(mainModuleID, type, host, false, true);
|
||||
}
|
||||
|
||||
private String createSplitBundleURL(String mainModuleID, String host) {
|
||||
return createBundleURL(mainModuleID, BundleType.BUNDLE, host, true, false);
|
||||
}
|
||||
|
||||
private String createBundleURL(
|
||||
String mainModuleID, BundleType type, String host, boolean modulesOnly, boolean runModule) {
|
||||
return String.format(
|
||||
Locale.US,
|
||||
"http://%s/%s.%s?platform=android&dev=%s&minify=%s&app=%s",
|
||||
"http://%s/%s.%s?platform=android&dev=%s&minify=%s&app=%s&modulesOnly=%s&runModule=%s",
|
||||
host,
|
||||
mainModuleID,
|
||||
type.typeID(),
|
||||
getDevMode(),
|
||||
getJSMinifyMode(),
|
||||
mPackageName);
|
||||
mPackageName,
|
||||
modulesOnly ? "true" : "false",
|
||||
runModule ? "true" : "false");
|
||||
}
|
||||
|
||||
private String createBundleURL(String mainModuleID, BundleType type) {
|
||||
@@ -454,6 +465,11 @@ public class DevServerHelper {
|
||||
mSettings.getPackagerConnectionSettings().getDebugServerHost());
|
||||
}
|
||||
|
||||
public String getDevServerSplitBundleURL(String jsModulePath) {
|
||||
return createSplitBundleURL(
|
||||
jsModulePath, mSettings.getPackagerConnectionSettings().getDebugServerHost());
|
||||
}
|
||||
|
||||
public void isPackagerRunning(final PackagerStatusCallback callback) {
|
||||
String statusURL =
|
||||
createPackagerStatusURL(mSettings.getPackagerConnectionSettings().getDebugServerHost());
|
||||
|
||||
+102
-35
@@ -23,12 +23,14 @@ import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.debug.holder.PrinterHolder;
|
||||
import com.facebook.debug.tags.ReactDebugOverlayTags;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.R;
|
||||
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
@@ -43,6 +45,7 @@ import com.facebook.react.common.futures.SimpleSettableFuture;
|
||||
import com.facebook.react.devsupport.DevServerHelper.PackagerCommandListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevOptionHandler;
|
||||
import com.facebook.react.devsupport.interfaces.DevSplitBundleCallback;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.ErrorCustomizer;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
@@ -70,6 +73,7 @@ public abstract class DevSupportManagerBase
|
||||
private static final int JAVA_ERROR_COOKIE = -1;
|
||||
private static final int JSEXCEPTION_ERROR_COOKIE = -1;
|
||||
private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
|
||||
private static final String JS_SPLIT_BUNDLES_DIR_NAME = "dev_js_split_bundles";
|
||||
private static final String RELOAD_APP_ACTION_SUFFIX = ".RELOAD_APP_ACTION";
|
||||
private static final String FLIPPER_DEBUGGER_URL =
|
||||
"flipper://null/Hermesdebuggerrn?device=React%20Native";
|
||||
@@ -97,6 +101,7 @@ public abstract class DevSupportManagerBase
|
||||
private final ReactInstanceManagerDevHelper mReactInstanceManagerHelper;
|
||||
private final @Nullable String mJSAppBundleName;
|
||||
private final File mJSBundleTempFile;
|
||||
private final File mJSSplitBundlesDir;
|
||||
private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
|
||||
private final DevLoadingViewController mDevLoadingViewController;
|
||||
|
||||
@@ -104,6 +109,7 @@ public abstract class DevSupportManagerBase
|
||||
private @Nullable AlertDialog mDevOptionsDialog;
|
||||
private @Nullable DebugOverlayController mDebugOverlayController;
|
||||
private boolean mDevLoadingViewVisible = false;
|
||||
private int mPendingJSSplitBundleRequests = 0;
|
||||
private @Nullable ReactContext mCurrentContext;
|
||||
private DevInternalSettings mDevSettings;
|
||||
private boolean mIsReceiverRegistered = false;
|
||||
@@ -113,7 +119,6 @@ public abstract class DevSupportManagerBase
|
||||
private @Nullable String mLastErrorTitle;
|
||||
private @Nullable StackFrame[] mLastErrorStack;
|
||||
private int mLastErrorCookie = 0;
|
||||
private @Nullable ErrorType mLastErrorType;
|
||||
private @Nullable DevBundleDownloadListener mBundleDownloadListener;
|
||||
private @Nullable List<ErrorCustomizer> mErrorCustomizers;
|
||||
private @Nullable PackagerLocationCustomizer mPackagerLocationCustomizer;
|
||||
@@ -204,6 +209,9 @@ public abstract class DevSupportManagerBase
|
||||
// TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
|
||||
mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
|
||||
|
||||
mJSSplitBundlesDir =
|
||||
mApplicationContext.getDir(JS_SPLIT_BUNDLES_DIR_NAME, Context.MODE_PRIVATE);
|
||||
|
||||
mDefaultNativeModuleCallExceptionHandler = new DefaultNativeModuleCallExceptionHandler();
|
||||
|
||||
setDevSupportEnabled(enableOnCreate);
|
||||
@@ -776,26 +784,6 @@ public abstract class DevSupportManagerBase
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case {@link
|
||||
* com.facebook.react.ReactInstanceManager} should use that file from assets instead of
|
||||
* downloading bundle from dev server
|
||||
*/
|
||||
public boolean hasBundleInAssets(String bundleAssetName) {
|
||||
try {
|
||||
String[] assets = mApplicationContext.getAssets().list("");
|
||||
for (int i = 0; i < assets.length; i++) {
|
||||
if (assets[i].equals(bundleAssetName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore this error and just fallback to downloading JS from devserver
|
||||
FLog.e(ReactConstants.TAG, "Error while loading assets list");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void resetCurrentContext(@Nullable ReactContext reactContext) {
|
||||
if (mCurrentContext == reactContext) {
|
||||
// new context is the same as the old one - do nothing
|
||||
@@ -875,6 +863,82 @@ public abstract class DevSupportManagerBase
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSplitBundleFromServer(String bundlePath, final DevSplitBundleCallback callback) {
|
||||
final String bundleUrl = mDevServerHelper.getDevServerSplitBundleURL(bundlePath);
|
||||
// The bundle path may contain the '/' character, which is not allowed in file names.
|
||||
final File bundleFile =
|
||||
new File(mJSSplitBundlesDir, bundlePath.replaceAll("/", "_") + ".jsbundle");
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showSplitBundleDevLoadingView(bundleUrl);
|
||||
mDevServerHelper.downloadBundleFromURL(
|
||||
new DevBundleDownloadListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
hideSplitBundleDevLoadingView();
|
||||
}
|
||||
});
|
||||
|
||||
@Nullable ReactContext context = mCurrentContext;
|
||||
if (context == null || !context.hasActiveCatalystInstance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSBundleLoader.createCachedSplitBundleFromNetworkLoader(
|
||||
bundleUrl, bundleFile.getAbsolutePath())
|
||||
.loadScript(context.getCatalystInstance());
|
||||
context.getJSModule(HMRClient.class).registerBundle(bundleUrl);
|
||||
|
||||
callback.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(
|
||||
@Nullable String status, @Nullable Integer done, @Nullable Integer total) {
|
||||
mDevLoadingViewController.updateProgress(status, done, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception cause) {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
hideSplitBundleDevLoadingView();
|
||||
}
|
||||
});
|
||||
callback.onError(bundleUrl, cause);
|
||||
}
|
||||
},
|
||||
bundleFile,
|
||||
bundleUrl,
|
||||
null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void showSplitBundleDevLoadingView(String bundleUrl) {
|
||||
mDevLoadingViewController.showForUrl(bundleUrl);
|
||||
mDevLoadingViewVisible = true;
|
||||
mPendingJSSplitBundleRequests++;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void hideSplitBundleDevLoadingView() {
|
||||
if (--mPendingJSSplitBundleRequests == 0) {
|
||||
mDevLoadingViewController.hide();
|
||||
mDevLoadingViewVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isPackagerRunning(final PackagerStatusCallback callback) {
|
||||
Runnable checkPackagerRunning =
|
||||
@@ -988,7 +1052,6 @@ public abstract class DevSupportManagerBase
|
||||
mLastErrorTitle = message;
|
||||
mLastErrorStack = stack;
|
||||
mLastErrorCookie = errorCookie;
|
||||
mLastErrorType = errorType;
|
||||
}
|
||||
|
||||
private void reloadJSInProxyMode() {
|
||||
@@ -1107,19 +1170,7 @@ public abstract class DevSupportManagerBase
|
||||
mBundleDownloadListener.onFailure(cause);
|
||||
}
|
||||
FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (cause instanceof DebugServerException) {
|
||||
DebugServerException debugServerException = (DebugServerException) cause;
|
||||
showNewJavaError(debugServerException.getMessage(), cause);
|
||||
} else {
|
||||
showNewJavaError(
|
||||
mApplicationContext.getString(R.string.catalyst_reload_error), cause);
|
||||
}
|
||||
}
|
||||
});
|
||||
reportBundleLoadingFailure(cause);
|
||||
}
|
||||
},
|
||||
mJSBundleTempFile,
|
||||
@@ -1127,6 +1178,22 @@ public abstract class DevSupportManagerBase
|
||||
bundleInfo);
|
||||
}
|
||||
|
||||
private void reportBundleLoadingFailure(final Exception cause) {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (cause instanceof DebugServerException) {
|
||||
DebugServerException debugServerException = (DebugServerException) cause;
|
||||
showNewJavaError(debugServerException.getMessage(), cause);
|
||||
} else {
|
||||
showNewJavaError(
|
||||
mApplicationContext.getString(R.string.catalyst_reload_error), cause);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startInspector() {
|
||||
if (mIsDevSupportEnabled) {
|
||||
|
||||
+4
@@ -13,6 +13,7 @@ import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.devsupport.interfaces.DevOptionHandler;
|
||||
import com.facebook.react.devsupport.interfaces.DevSplitBundleCallback;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.ErrorCustomizer;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
@@ -129,6 +130,9 @@ public class DisabledDevSupportManager implements DevSupportManager {
|
||||
@Override
|
||||
public void reloadJSFromServer(String bundleURL) {}
|
||||
|
||||
@Override
|
||||
public void loadSplitBundleFromServer(String bundlePath, DevSplitBundleCallback callback) {}
|
||||
|
||||
@Override
|
||||
public void isPackagerRunning(final PackagerStatusCallback callback) {}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ public interface HMRClient extends JavaScriptModule {
|
||||
*/
|
||||
void setup(String platform, String bundleEntry, String host, int port, boolean isEnabled);
|
||||
|
||||
/** Registers an additional JS bundle with HMRClient. */
|
||||
void registerBundle(String bundleUrl);
|
||||
|
||||
/**
|
||||
* Sets up a connection to the packager when called the first time. Ensures code updates received
|
||||
* from the packager are applied.
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.devsupport.interfaces;
|
||||
|
||||
/** Callback class for loading split JS bundles from Metro in development. */
|
||||
public interface DevSplitBundleCallback {
|
||||
/** Called when the split JS bundle has been downloaded and evaluated. */
|
||||
void onSuccess();
|
||||
/** Called when the split JS bundle failed to load. */
|
||||
void onError(String url, Throwable cause);
|
||||
}
|
||||
+2
@@ -69,6 +69,8 @@ public interface DevSupportManager extends NativeModuleCallExceptionHandler {
|
||||
|
||||
void reloadJSFromServer(final String bundleURL);
|
||||
|
||||
void loadSplitBundleFromServer(String bundlePath, DevSplitBundleCallback callback);
|
||||
|
||||
void isPackagerRunning(PackagerStatusCallback callback);
|
||||
|
||||
void setHotModuleReplacementEnabled(final boolean isHotModuleReplacementEnabled);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library")
|
||||
|
||||
rn_android_library(
|
||||
name = "bundleloader",
|
||||
srcs = glob(["*.java"]),
|
||||
is_androidx = True,
|
||||
labels = ["supermodule:xplat/default/public.react_native.infra"],
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/androidx:annotation"),
|
||||
],
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/devsupport:interfaces"),
|
||||
react_native_target("java/com/facebook/react/module/annotations:annotations"),
|
||||
],
|
||||
exported_deps = [react_native_target("java/com/facebook/fbreact/specs:FBReactNativeSpec")],
|
||||
)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.modules.bundleloader;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.facebook.fbreact.specs.NativeDevSplitBundleLoaderSpec;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.DebugServerException;
|
||||
import com.facebook.react.devsupport.interfaces.DevSplitBundleCallback;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
||||
@ReactModule(name = NativeDevSplitBundleLoaderModule.NAME)
|
||||
public class NativeDevSplitBundleLoaderModule extends NativeDevSplitBundleLoaderSpec {
|
||||
public static final String NAME = "DevSplitBundleLoader";
|
||||
private static final String REJECTION_CODE = "E_BUNDLE_LOAD_ERROR";
|
||||
|
||||
private final DevSupportManager mDevSupportManager;
|
||||
|
||||
public NativeDevSplitBundleLoaderModule(
|
||||
ReactApplicationContext reactContext, DevSupportManager devSupportManager) {
|
||||
super(reactContext);
|
||||
mDevSupportManager = devSupportManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBundle(String bundlePath, final Promise promise) {
|
||||
mDevSupportManager.loadSplitBundleFromServer(
|
||||
bundlePath,
|
||||
new DevSplitBundleCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
promise.resolve(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String url, Throwable cause) {
|
||||
String message =
|
||||
cause instanceof DebugServerException
|
||||
? ((DebugServerException) cause).getOriginalMessage()
|
||||
: "Unknown error fetching '" + url + "'.";
|
||||
promise.reject(REJECTION_CODE, message, cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user