Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ internal object InspectorFlags {
SoLoader.loadLibrary("react_devsupportjni")
}

@DoNotStrip @JvmStatic external fun getScreenshotCaptureEnabled(): Boolean

@DoNotStrip @JvmStatic external fun getFuseboxEnabled(): Boolean

@DoNotStrip @JvmStatic external fun getIsProfilingBuild(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<84bfc7b7a1b239c514b6d7c38dd91283>>
* @generated SignedSource<<eacf6769e8598f88fe1790149e437f3f>>
*/

/**
Expand Down Expand Up @@ -408,6 +408,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun fuseboxNetworkInspectionEnabled(): Boolean = accessor.fuseboxNetworkInspectionEnabled()

/**
* Enable Page.captureScreenshot CDP method support in the React Native DevTools CDP backend. This flag is global and should not be changed across React Host lifetimes.
*/
@JvmStatic
public fun fuseboxScreenshotCaptureEnabled(): Boolean = accessor.fuseboxScreenshotCaptureEnabled()

/**
* Hides offscreen VirtualViews on iOS by setting hidden = YES to avoid extra cost of views
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1b59188082b9222b22b5cb0585cd166f>>
* @generated SignedSource<<668885665a149d50bdff92bd96a297f0>>
*/

/**
Expand Down Expand Up @@ -83,6 +83,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var fuseboxEnabledReleaseCache: Boolean? = null
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
private var fuseboxScreenshotCaptureEnabledCache: Boolean? = null
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
private var perfIssuesEnabledCache: Boolean? = null
Expand Down Expand Up @@ -677,6 +678,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}

override fun fuseboxScreenshotCaptureEnabled(): Boolean {
var cached = fuseboxScreenshotCaptureEnabledCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.fuseboxScreenshotCaptureEnabled()
fuseboxScreenshotCaptureEnabledCache = cached
}
return cached
}

override fun hideOffscreenVirtualViewsOnIOS(): Boolean {
var cached = hideOffscreenVirtualViewsOnIOSCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2fd657c62d07ed766a9241cb1c14d98d>>
* @generated SignedSource<<aa4a2ab7af66d857da4318ac2e75899b>>
*/

/**
Expand Down Expand Up @@ -154,6 +154,8 @@ public object ReactNativeFeatureFlagsCxxInterop {

@DoNotStrip @JvmStatic public external fun fuseboxNetworkInspectionEnabled(): Boolean

@DoNotStrip @JvmStatic public external fun fuseboxScreenshotCaptureEnabled(): Boolean

@DoNotStrip @JvmStatic public external fun hideOffscreenVirtualViewsOnIOS(): Boolean

@DoNotStrip @JvmStatic public external fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f3204842cd731d7eff8c4c4eeeead515>>
* @generated SignedSource<<6348c0cc9285f2bac6df9986155b584f>>
*/

/**
Expand Down Expand Up @@ -149,6 +149,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun fuseboxNetworkInspectionEnabled(): Boolean = true

override fun fuseboxScreenshotCaptureEnabled(): Boolean = false

override fun hideOffscreenVirtualViewsOnIOS(): Boolean = false

override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<251381892c7d15310d61b35913c5cba6>>
* @generated SignedSource<<f545945b19339923fcafab4eeb1da134>>
*/

/**
Expand Down Expand Up @@ -87,6 +87,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var fuseboxEnabledReleaseCache: Boolean? = null
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
private var fuseboxScreenshotCaptureEnabledCache: Boolean? = null
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
private var perfIssuesEnabledCache: Boolean? = null
Expand Down Expand Up @@ -744,6 +745,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}

override fun fuseboxScreenshotCaptureEnabled(): Boolean {
var cached = fuseboxScreenshotCaptureEnabledCache
if (cached == null) {
cached = currentProvider.fuseboxScreenshotCaptureEnabled()
accessedFeatureFlags.add("fuseboxScreenshotCaptureEnabled")
fuseboxScreenshotCaptureEnabledCache = cached
}
return cached
}

override fun hideOffscreenVirtualViewsOnIOS(): Boolean {
var cached = hideOffscreenVirtualViewsOnIOSCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7e47ac680222281a813e65484e7f8e39>>
* @generated SignedSource<<e340fe9805381dcf818f51e333f7c120>>
*/

/**
Expand Down Expand Up @@ -149,6 +149,8 @@ public interface ReactNativeFeatureFlagsProvider {

@DoNotStrip public fun fuseboxNetworkInspectionEnabled(): Boolean

@DoNotStrip public fun fuseboxScreenshotCaptureEnabled(): Boolean

@DoNotStrip public fun hideOffscreenVirtualViewsOnIOS(): Boolean

@DoNotStrip public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
import android.os.Bundle
import androidx.core.graphics.createBitmap
import com.facebook.common.logging.FLog
import com.facebook.infer.annotation.Assertions
import com.facebook.infer.annotation.ThreadConfined
Expand Down Expand Up @@ -447,6 +448,43 @@ public class ReactHostImpl(
InspectorNetworkHelper.loadNetworkResource(url, listener)
}

@DoNotStrip
private fun captureScreenshot(format: String, quality: Int): String? {
val activity = currentActivity ?: return null
val window = activity.window ?: return null
val decorView = window.decorView.rootView

val width = decorView.width
val height = decorView.height
if (width <= 0 || height <= 0) {
return null
}

val bitmap = createBitmap(width, height)
val canvas = android.graphics.Canvas(bitmap)
decorView.draw(canvas)

val outputStream = java.io.ByteArrayOutputStream()
val compressFormat =
when (format) {
"jpeg" -> android.graphics.Bitmap.CompressFormat.JPEG
"webp" ->
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
android.graphics.Bitmap.CompressFormat.WEBP_LOSSY
} else {
@Suppress("DEPRECATION") android.graphics.Bitmap.CompressFormat.WEBP
}
else -> android.graphics.Bitmap.CompressFormat.PNG
}
val compressQuality = if (quality in 0..100) quality else 80

bitmap.compress(compressFormat, compressQuality, outputStream)
bitmap.recycle()

val bytes = outputStream.toByteArray()
return android.util.Base64.encodeToString(bytes, android.util.Base64.NO_WRAP)
}

/**
* Entrypoint to destroy the ReactInstance. If the ReactInstance is reloading, will wait until
* reload is finished, before destroying.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@

namespace facebook::react::jsinspector_modern {

bool JInspectorFlags::getScreenshotCaptureEnabled(
jni::alias_ref<jclass> /*unused*/) {
auto& inspectorFlags = InspectorFlags::getInstance();
return inspectorFlags.getScreenshotCaptureEnabled();
}

bool JInspectorFlags::getFuseboxEnabled(jni::alias_ref<jclass> /*unused*/) {
auto& inspectorFlags = InspectorFlags::getInstance();
return inspectorFlags.getFuseboxEnabled();
Expand All @@ -28,6 +34,11 @@ bool JInspectorFlags::getFrameRecordingEnabled(
}

void JInspectorFlags::registerNatives() {
javaClassLocal()->registerNatives({
makeNativeMethod(
"getScreenshotCaptureEnabled",
JInspectorFlags::getScreenshotCaptureEnabled),
});
javaClassLocal()->registerNatives({
makeNativeMethod("getFuseboxEnabled", JInspectorFlags::getFuseboxEnabled),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class JInspectorFlags : public jni::JavaClass<JInspectorFlags> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/InspectorFlags;";

static bool getScreenshotCaptureEnabled(jni::alias_ref<jclass> /*unused*/);
static bool getFuseboxEnabled(jni::alias_ref<jclass> /*unused*/);
static bool getIsProfilingBuild(jni::alias_ref<jclass> /*unused*/);
static bool getFrameRecordingEnabled(jni::alias_ref<jclass> /*unused*/);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7e78fc846fe46b5dc7d451817db90ec1>>
* @generated SignedSource<<367bb35175543888c27d2e26a049289c>>
*/

/**
Expand Down Expand Up @@ -417,6 +417,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}

bool fuseboxScreenshotCaptureEnabled() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fuseboxScreenshotCaptureEnabled");
return method(javaProvider_);
}

bool hideOffscreenVirtualViewsOnIOS() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("hideOffscreenVirtualViewsOnIOS");
Expand Down Expand Up @@ -892,6 +898,11 @@ bool JReactNativeFeatureFlagsCxxInterop::fuseboxNetworkInspectionEnabled(
return ReactNativeFeatureFlags::fuseboxNetworkInspectionEnabled();
}

bool JReactNativeFeatureFlagsCxxInterop::fuseboxScreenshotCaptureEnabled(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::fuseboxScreenshotCaptureEnabled();
}

bool JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::hideOffscreenVirtualViewsOnIOS();
Expand Down Expand Up @@ -1242,6 +1253,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"fuseboxNetworkInspectionEnabled",
JReactNativeFeatureFlagsCxxInterop::fuseboxNetworkInspectionEnabled),
makeNativeMethod(
"fuseboxScreenshotCaptureEnabled",
JReactNativeFeatureFlagsCxxInterop::fuseboxScreenshotCaptureEnabled),
makeNativeMethod(
"hideOffscreenVirtualViewsOnIOS",
JReactNativeFeatureFlagsCxxInterop::hideOffscreenVirtualViewsOnIOS),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<022cea241825b693de81b5f1f6d7d638>>
* @generated SignedSource<<e3364d03414c159bf8ad8afbd4d3fafe>>
*/

/**
Expand Down Expand Up @@ -219,6 +219,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool fuseboxNetworkInspectionEnabled(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool fuseboxScreenshotCaptureEnabled(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool hideOffscreenVirtualViewsOnIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ void JReactHostInspectorTarget::loadNetworkResource(
}
}

std::optional<std::string> JReactHostInspectorTarget::captureScreenshot(
const jsinspector_modern::HostTargetDelegate::PageCaptureScreenshotRequest&
request) {
if (auto javaReactHostImplStrong = javaReactHostImpl_->get()) {
std::string format = request.format.value_or("png");
int quality = request.quality.value_or(-1);
auto result = javaReactHostImplStrong->captureScreenshot(format, quality);
if (result) {
return result->toStdString();
}
}
return std::nullopt;
}

HostTarget* JReactHostInspectorTarget::getInspectorTarget() {
return inspectorTarget_ ? inspectorTarget_.get() : nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ struct JReactHostImpl : public jni::JavaClass<JReactHostImpl> {
"loadNetworkResource");
return method(self(), jni::make_jstring(url), listener);
}

jni::local_ref<jni::JString> captureScreenshot(const std::string &format, int quality) const
{
auto method = javaClassStatic()->getMethod<jni::local_ref<jni::JString>(jni::local_ref<jni::JString>, jint)>(
"captureScreenshot");
return method(self(), jni::make_jstring(format), static_cast<jint>(quality));
}
};

/**
Expand Down Expand Up @@ -275,6 +282,8 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar
void loadNetworkResource(
const jsinspector_modern::LoadNetworkResourceRequest &params,
jsinspector_modern::ScopedExecutor<jsinspector_modern::NetworkRequestListener> executor) override;
std::optional<std::string> captureScreenshot(
const jsinspector_modern::HostTargetDelegate::PageCaptureScreenshotRequest &request) override;
jsinspector_modern::HostTargetTracingDelegate *getTracingDelegate() override;

private:
Expand Down
Loading
Loading