Add dev bundle download listener on Android
Summary: This exposes a way to listen to JS bundle download events when creating a ReactInstanceManager. This can be used to display a custom native UI while the JS bundle is loading. It is a pretty specific use case but Expo will need this to display loading progress on the app loading splash screen. **Test plan** Tested by adding a listener to the ReactInstanceManager in the Expo app and checked that it gets called when the bundle is loading. Closes https://github.com/facebook/react-native/pull/12984 Reviewed By: devknoll Differential Revision: D4797638 Pulled By: hramos fbshipit-source-id: 04d7cd4071535670c1bcb121566748e495197c80
This commit is contained in:
parent
c848c3820b
commit
960e5db0ed
|
@ -53,6 +53,7 @@ import com.facebook.react.common.annotations.VisibleForTesting;
|
|||
import com.facebook.react.devsupport.DevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
import com.facebook.react.modules.appregistry.AppRegistry;
|
||||
|
@ -221,6 +222,7 @@ public class ReactInstanceManager {
|
|||
@Nullable RedBoxHandler redBoxHandler,
|
||||
boolean lazyNativeModulesEnabled,
|
||||
boolean lazyViewManagersEnabled,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
boolean setupReactContextInBackgroundEnabled,
|
||||
boolean useSeparateUIBackgroundThread,
|
||||
int minNumShakes) {
|
||||
|
@ -242,6 +244,7 @@ public class ReactInstanceManager {
|
|||
mJSMainModuleName,
|
||||
useDeveloperSupport,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes);
|
||||
mBridgeIdleDebugListener = bridgeIdleDebugListener;
|
||||
mLifecycleState = initialLifecycleState;
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
|||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
||||
import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
@ -42,6 +43,7 @@ public class ReactInstanceManagerBuilder {
|
|||
protected @Nullable RedBoxHandler mRedBoxHandler;
|
||||
protected boolean mLazyNativeModulesEnabled;
|
||||
protected boolean mLazyViewManagersEnabled;
|
||||
protected @Nullable DevBundleDownloadListener mDevBundleDownloadListener;
|
||||
protected boolean mSetupReactContextInBackground;
|
||||
protected boolean mUseSeparateUIBackgroundThread;
|
||||
protected int mMinNumShakes = 1;
|
||||
|
@ -189,6 +191,11 @@ public class ReactInstanceManagerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ReactInstanceManagerBuilder setDevBundleDownloadListener(@Nullable DevBundleDownloadListener listener) {
|
||||
mDevBundleDownloadListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReactInstanceManagerBuilder setSetupReactContextInBackgroundEnabled(
|
||||
boolean setupReactContextInBackground) {
|
||||
mSetupReactContextInBackground = setupReactContextInBackground;
|
||||
|
@ -252,6 +259,7 @@ public class ReactInstanceManagerBuilder {
|
|||
mRedBoxHandler,
|
||||
mLazyNativeModulesEnabled,
|
||||
mLazyViewManagersEnabled,
|
||||
mDevBundleDownloadListener,
|
||||
mSetupReactContextInBackground,
|
||||
mUseSeparateUIBackgroundThread,
|
||||
mMinNumShakes);
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.regex.Pattern;
|
|||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.common.DebugServerException;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
@ -36,12 +37,6 @@ import okio.Okio;
|
|||
import okio.Sink;
|
||||
|
||||
public class BundleDownloader {
|
||||
public interface DownloadCallback {
|
||||
void onSuccess();
|
||||
void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total);
|
||||
void onFailure(Exception cause);
|
||||
}
|
||||
|
||||
private final OkHttpClient mClient;
|
||||
|
||||
private @Nullable Call mDownloadBundleFromURLCall;
|
||||
|
@ -51,7 +46,7 @@ public class BundleDownloader {
|
|||
}
|
||||
|
||||
public void downloadBundleFromURL(
|
||||
final DownloadCallback callback,
|
||||
final DevBundleDownloadListener callback,
|
||||
final File outputFile,
|
||||
final String bundleURL) {
|
||||
final Request request = new Request.Builder()
|
||||
|
@ -156,7 +151,7 @@ public class BundleDownloader {
|
|||
int statusCode,
|
||||
BufferedSource body,
|
||||
File outputFile,
|
||||
DownloadCallback callback) throws IOException {
|
||||
DevBundleDownloadListener callback) throws IOException {
|
||||
// Check for server errors. If the server error has the expected form, fail with more info.
|
||||
if (statusCode != 200) {
|
||||
String bodyString = body.readUtf8();
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.facebook.infer.annotation.Assertions;
|
|||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.network.OkHttpCallUtil;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
import com.facebook.react.devsupport.interfaces.StackFrame;
|
||||
import com.facebook.react.modules.systeminfo.AndroidInfoHelpers;
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.lang.reflect.Constructor;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
|
||||
/**
|
||||
|
@ -41,6 +42,7 @@ public class DevSupportManagerFactory {
|
|||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null,
|
||||
null,
|
||||
minNumShakes);
|
||||
}
|
||||
|
||||
|
@ -50,6 +52,7 @@ public class DevSupportManagerFactory {
|
|||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes) {
|
||||
if (!enableOnCreate) {
|
||||
return new DisabledDevSupportManager();
|
||||
|
@ -72,6 +75,7 @@ public class DevSupportManagerFactory {
|
|||
String.class,
|
||||
boolean.class,
|
||||
RedBoxHandler.class,
|
||||
DevBundleDownloadListener.class,
|
||||
int.class);
|
||||
return (DevSupportManager) constructor.newInstance(
|
||||
applicationContext,
|
||||
|
@ -79,6 +83,7 @@ public class DevSupportManagerFactory {
|
|||
packagerPathForJSBundleName,
|
||||
true,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.facebook.react.common.ReactConstants;
|
|||
import com.facebook.react.common.ShakeDetector;
|
||||
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.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
|
@ -133,6 +134,7 @@ public class DevSupportManagerImpl implements
|
|||
private @Nullable StackFrame[] mLastErrorStack;
|
||||
private int mLastErrorCookie = 0;
|
||||
private @Nullable ErrorType mLastErrorType;
|
||||
private @Nullable DevBundleDownloadListener mBundleDownloadListener;
|
||||
|
||||
private static class JscProfileTask extends AsyncTask<String, Void, Void> {
|
||||
private static final MediaType JSON =
|
||||
|
@ -179,6 +181,7 @@ public class DevSupportManagerImpl implements
|
|||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null,
|
||||
null,
|
||||
minNumShakes);
|
||||
}
|
||||
|
||||
|
@ -188,12 +191,14 @@ public class DevSupportManagerImpl implements
|
|||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes) {
|
||||
mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
|
||||
mApplicationContext = applicationContext;
|
||||
mJSAppBundleName = packagerPathForJSBundleName;
|
||||
mDevSettings = new DevInternalSettings(applicationContext, this);
|
||||
mDevServerHelper = new DevServerHelper(mDevSettings);
|
||||
mBundleDownloadListener = devBundleDownloadListener;
|
||||
|
||||
// Prepare shake gesture detector (will be started/stopped from #reload)
|
||||
mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
|
||||
|
@ -827,11 +832,14 @@ public class DevSupportManagerImpl implements
|
|||
mDevLoadingViewVisible = true;
|
||||
|
||||
mDevServerHelper.getBundleDownloader().downloadBundleFromURL(
|
||||
new BundleDownloader.DownloadCallback() {
|
||||
new DevBundleDownloadListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
mDevLoadingViewController.hide();
|
||||
mDevLoadingViewVisible = false;
|
||||
if (mBundleDownloadListener != null) {
|
||||
mBundleDownloadListener.onSuccess();
|
||||
}
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
|
@ -844,12 +852,18 @@ public class DevSupportManagerImpl implements
|
|||
@Override
|
||||
public void onProgress(@Nullable final String status, @Nullable final Integer done, @Nullable final Integer total) {
|
||||
mDevLoadingViewController.updateProgress(status, done, total);
|
||||
if (mBundleDownloadListener != null) {
|
||||
mBundleDownloadListener.onProgress(status, done, total);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Exception cause) {
|
||||
mDevLoadingViewController.hide();
|
||||
mDevLoadingViewVisible = false;
|
||||
if (mBundleDownloadListener != null) {
|
||||
mBundleDownloadListener.onFailure(cause);
|
||||
}
|
||||
FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport.interfaces;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface DevBundleDownloadListener {
|
||||
void onSuccess();
|
||||
void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total);
|
||||
void onFailure(Exception cause);
|
||||
}
|
Loading…
Reference in New Issue