diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 4eebfab03e3..18c9adec193 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2325,16 +2325,17 @@ public class com/facebook/react/devsupport/StackTraceHelper$StackFrameImpl : com public fun toJSON ()Lorg/json/JSONObject; } -public class com/facebook/react/devsupport/inspector/InspectorNetworkHelper { - public static fun loadNetworkResource (Ljava/lang/String;Lcom/facebook/react/devsupport/inspector/InspectorNetworkRequestListener;)V +public final class com/facebook/react/devsupport/inspector/InspectorNetworkHelper { + public static final field INSTANCE Lcom/facebook/react/devsupport/inspector/InspectorNetworkHelper; + public static final fun loadNetworkResource (Ljava/lang/String;Lcom/facebook/react/devsupport/inspector/InspectorNetworkRequestListener;)V } -public class com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener { +public final class com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener { public fun (Lcom/facebook/jni/HybridData;)V - public fun onCompletion ()V - public fun onData (Ljava/lang/String;)V - public fun onError (Ljava/lang/String;)V - public fun onHeaders (ILjava/util/Map;)V + public final fun onCompletion ()V + public final fun onData (Ljava/lang/String;)V + public final fun onError (Ljava/lang/String;)V + public final fun onHeaders (ILjava/util/Map;)V } public abstract interface class com/facebook/react/devsupport/interfaces/BundleLoadCallback { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.java deleted file mode 100644 index 3f81af8c5db..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and 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.inspector; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; - -public class InspectorNetworkHelper { - private static OkHttpClient client; - - private InspectorNetworkHelper() {} - - public static void loadNetworkResource(String url, InspectorNetworkRequestListener listener) { - if (client == null) { - client = - new OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read - .build(); - } - - Request request; - try { - request = new Request.Builder().url(url).build(); - } catch (IllegalArgumentException e) { - listener.onError("Not a valid URL: " + url); - return; - } - - // TODO(T196951523): Assign cancel function to listener - Call call = client.newCall(request); - - call.enqueue( - new Callback() { - @Override - public void onFailure(Call call, IOException e) { - if (call.isCanceled()) { - return; - } - - listener.onError(e.getMessage()); - } - - @Override - public void onResponse(Call call, Response response) { - Headers headers = response.headers(); - HashMap headersMap = new HashMap<>(); - - for (String name : headers.names()) { - headersMap.put(name, headers.get(name)); - } - - listener.onHeaders(response.code(), headersMap); - - try (ResponseBody responseBody = response.body()) { - if (responseBody != null) { - InputStream inputStream = responseBody.byteStream(); - int chunkSize = 1024; - byte[] buffer = new byte[chunkSize]; - int bytesRead; - - try { - while ((bytesRead = inputStream.read(buffer)) != -1) { - String chunk = new String(buffer, 0, bytesRead); - listener.onData(chunk); - } - } finally { - inputStream.close(); - } - } - - listener.onCompletion(); - } catch (IOException e) { - listener.onError(e.getMessage()); - } - } - }); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt new file mode 100644 index 00000000000..e6cd962325c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +@file:Suppress("DEPRECATION_ERROR") // Conflicting okhttp versions + +package com.facebook.react.devsupport.inspector + +import java.io.IOException +import java.util.concurrent.TimeUnit +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response + +public object InspectorNetworkHelper { + private lateinit var client: OkHttpClient + + @JvmStatic + public fun loadNetworkResource(url: String, listener: InspectorNetworkRequestListener) { + if (!::client.isInitialized) { + client = + OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read + .build() + } + + val request = + try { + Request.Builder().url(url).build() + } catch (e: IllegalArgumentException) { + listener.onError("Not a valid URL: $url") + return + } + + // TODO(T196951523): Assign cancel function to listener + val call = client.newCall(request) + + call.enqueue( + object : Callback { + override fun onFailure(call: Call, e: IOException) { + if (call.isCanceled()) { + return + } + + listener.onError(e.message) + } + + override fun onResponse(call: Call, response: Response) { + val headers = response.headers() + val headersMap = HashMap() + + for (name in headers.names()) { + headersMap[name] = headers[name] + } + + listener.onHeaders(response.code(), headersMap) + + try { + response.body().use { responseBody -> + if (responseBody != null) { + val inputStream = responseBody.byteStream() + val chunkSize = 1024 + val buffer = ByteArray(chunkSize) + var bytesRead: Int + + inputStream.use { stream -> + while ((stream.read(buffer).also { bytesRead = it }) != -1) { + val chunk = String(buffer, 0, bytesRead) + listener.onData(chunk) + } + } + } + listener.onCompletion() + } + } catch (e: IOException) { + listener.onError(e.message) + } + } + }) + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.java deleted file mode 100644 index 5f7986f65d7..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and 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.inspector; - -import androidx.annotation.Nullable; -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStripAny; -import java.util.Map; - -/** - * JNI wrapper for {@code jsinspectormodern::NetworkRequestListener}. Handles the {@code - * ScopedExecutor} callback use on the C++ side. - */ -@DoNotStripAny -public class InspectorNetworkRequestListener { - private final HybridData mHybridData; - - public InspectorNetworkRequestListener(HybridData hybridData) { - mHybridData = hybridData; - } - - public native void onHeaders(int httpStatusCode, Map headers); - - public native void onData(String data); - - public native void onError(@Nullable String message); - - public native void onCompletion(); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.kt new file mode 100644 index 00000000000..2b9a4b6ecca --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkRequestListener.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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.inspector + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.proguard.annotations.DoNotStripAny + +/** + * JNI wrapper for `jsinspectormodern::NetworkRequestListener`. Handles the `ScopedExecutor` + * callback use on the C++ side. + */ +@DoNotStripAny +public class InspectorNetworkRequestListener +public constructor(@field:DoNotStrip private val mHybridData: HybridData) { + public external fun onHeaders(httpStatusCode: Int, headers: Map?) + + public external fun onData(data: String?) + + public external fun onError(message: String?) + + public external fun onCompletion() +}