From 8720d4bc76892f574b29148f34f9602da07efb6f Mon Sep 17 00:00:00 2001 From: Felix Oghina Date: Thu, 11 Feb 2016 13:34:09 -0800 Subject: [PATCH] strip devsupport from prod builds Reviewed By: zen Differential Revision: D2912192 fb-gh-sync-id: ff89fc16dcd86481657197055e31d2b67a94e7ea shipit-source-id: ff89fc16dcd86481657197055e31d2b67a94e7ea --- .../react/ReactInstanceManagerImpl.java | 17 ++--- .../devsupport/DevSupportManagerFactory.java | 62 +++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java index a6a69810e..c4f550495 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java @@ -58,8 +58,7 @@ import com.facebook.react.common.ReactConstants; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.devsupport.DevServerHelper; import com.facebook.react.devsupport.DevSupportManager; -import com.facebook.react.devsupport.DevSupportManagerImpl; -import com.facebook.react.devsupport.DisabledDevSupportManager; +import com.facebook.react.devsupport.DevSupportManagerFactory; import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -275,15 +274,11 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*; mJSMainModuleName = jsMainModuleName; mPackages = packages; mUseDeveloperSupport = useDeveloperSupport; - if (mUseDeveloperSupport) { - mDevSupportManager = new DevSupportManagerImpl( - applicationContext, - mDevInterface, - mJSMainModuleName, - useDeveloperSupport); - } else { - mDevSupportManager = new DisabledDevSupportManager(); - } + mDevSupportManager = DevSupportManagerFactory.create( + applicationContext, + mDevInterface, + mJSMainModuleName, + useDeveloperSupport); mBridgeIdleDebugListener = bridgeIdleDebugListener; mLifecycleState = initialLifecycleState; mUIImplementationProvider = uiImplementationProvider; diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java new file mode 100644 index 000000000..22d925672 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java @@ -0,0 +1,62 @@ +package com.facebook.react.devsupport; + +import javax.annotation.Nullable; + +import java.lang.reflect.Constructor; + +import android.content.Context; +import android.util.Log; + +import com.facebook.react.common.ReactConstants; +import com.facebook.react.common.build.ReactBuildConfig; + +/** + * A simple factory that creates instances of {@link DevSupportManager} implementations. Uses + * reflection to create DevSupportManagerImpl if it exists. This allows ProGuard to strip that class + * and its dependencies in release builds. If the class isn't found, + * {@link DisabledDevSupportManager} is returned instead. + */ +public class DevSupportManagerFactory { + + private static final String DEVSUPPORT_IMPL_PACKAGE = "com.facebook.react.devsupport"; + private static final String DEVSUPPORT_IMPL_CLASS = "DevSupportManagerImpl"; + + public static DevSupportManager create( + Context applicationContext, + ReactInstanceDevCommandsHandler reactInstanceCommandsHandler, + @Nullable String packagerPathForJSBundleName, + boolean enableOnCreate) { + if (!enableOnCreate) { + return new DisabledDevSupportManager(); + } + try { + // ProGuard is surprisingly smart in this case and will keep a class if it detects a call to + // Class.forName() with a static string. So instead we generate a quasi-dynamic string to + // confuse it. + String className = + new StringBuilder(DEVSUPPORT_IMPL_PACKAGE) + .append(".") + .append(DEVSUPPORT_IMPL_CLASS) + .toString(); + Class devSupportManagerClass = + Class.forName(className); + Constructor constructor = + devSupportManagerClass.getConstructor( + Context.class, + ReactInstanceDevCommandsHandler.class, + String.class, + boolean.class); + return (DevSupportManager) constructor.newInstance( + applicationContext, + reactInstanceCommandsHandler, + packagerPathForJSBundleName, + true); + } catch (Exception e) { + throw new RuntimeException( + "Requested enabled DevSupportManager, but DevSupportManagerImpl class was not found" + + " or could not be created", + e); + } + } + +}