Permalink
Browse files

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 #12984

Reviewed By: devknoll

Differential Revision: D4797638

Pulled By: hramos

fbshipit-source-id: 04d7cd4071535670c1bcb121566748e495197c80
  • Loading branch information...
janicduplessis authored and facebook-github-bot committed Jun 29, 2017
1 parent c848c38 commit 960e5db0edd8f9c9b7faf1da4d0fa88a07e9fb5c
@@ -53,6 +53,7 @@
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 static ReactInstanceManagerBuilder builder() {
@Nullable RedBoxHandler redBoxHandler,
boolean lazyNativeModulesEnabled,
boolean lazyViewManagersEnabled,
@Nullable DevBundleDownloadListener devBundleDownloadListener,
boolean setupReactContextInBackgroundEnabled,
boolean useSeparateUIBackgroundThread,
int minNumShakes) {
@@ -242,6 +244,7 @@ public static ReactInstanceManagerBuilder builder() {
mJSMainModuleName,
useDeveloperSupport,
redBoxHandler,
devBundleDownloadListener,
minNumShakes);
mBridgeIdleDebugListener = bridgeIdleDebugListener;
mLifecycleState = initialLifecycleState;
@@ -15,6 +15,7 @@
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 @@
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 ReactInstanceManagerBuilder setLazyViewManagersEnabled(boolean lazyViewMa
return this;
}
public ReactInstanceManagerBuilder setDevBundleDownloadListener(@Nullable DevBundleDownloadListener listener) {
mDevBundleDownloadListener = listener;
return this;
}
public ReactInstanceManagerBuilder setSetupReactContextInBackgroundEnabled(
boolean setupReactContextInBackground) {
mSetupReactContextInBackground = setupReactContextInBackground;
@@ -252,6 +259,7 @@ public ReactInstanceManager build() {
mRedBoxHandler,
mLazyNativeModulesEnabled,
mLazyViewManagersEnabled,
mDevBundleDownloadListener,
mSetupReactContextInBackground,
mUseSeparateUIBackgroundThread,
mMinNumShakes);
@@ -20,6 +20,7 @@
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.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 BundleDownloader(OkHttpClient client) {
}
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 @@ private void processBundleResult(
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.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 android.content.Context;
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
/**
@@ -41,6 +42,7 @@ public static DevSupportManager create(
packagerPathForJSBundleName,
enableOnCreate,
null,
null,
minNumShakes);
}
@@ -50,6 +52,7 @@ public static DevSupportManager create(
@Nullable String packagerPathForJSBundleName,
boolean enableOnCreate,
@Nullable RedBoxHandler redBoxHandler,
@Nullable DevBundleDownloadListener devBundleDownloadListener,
int minNumShakes) {
if (!enableOnCreate) {
return new DisabledDevSupportManager();
@@ -72,13 +75,15 @@ public static DevSupportManager create(
String.class,
boolean.class,
RedBoxHandler.class,
DevBundleDownloadListener.class,
int.class);
return (DevSupportManager) constructor.newInstance(
applicationContext,
reactInstanceCommandsHandler,
packagerPathForJSBundleName,
true,
redBoxHandler,
devBundleDownloadListener,
minNumShakes);
} catch (Exception e) {
throw new RuntimeException(
@@ -52,6 +52,7 @@
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 @@
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 DevSupportManagerImpl(
packagerPathForJSBundleName,
enableOnCreate,
null,
null,
minNumShakes);
}
@@ -188,12 +191,14 @@ public DevSupportManagerImpl(
@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 void reloadJSFromServer(final String bundleURL) {
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 void run() {
@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);
}

0 comments on commit 960e5db

Please sign in to comment.