mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
[0.75] Add support for handling com.facebook.react.bridge.Dynamic as parameter for TurboModules (#46066)
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.bridge
|
||||
|
||||
import com.facebook.jni.HybridData
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.proguard.annotations.DoNotStripAny
|
||||
|
||||
/**
|
||||
* An implementation of [Dynamic] that has a C++ implementation.
|
||||
*
|
||||
* This is used to support Legacy Native Modules that have not been migrated to the new architecture
|
||||
* and are using [Dynamic] as a parameter type.
|
||||
*/
|
||||
@DoNotStripAny
|
||||
private class DynamicNative(
|
||||
@Suppress("NoHungarianNotation") @field:DoNotStrip private val mHybridData: HybridData?
|
||||
) : Dynamic {
|
||||
|
||||
override val type: ReadableType
|
||||
get() = getTypeNative()
|
||||
|
||||
override val isNull: Boolean
|
||||
get() = isNullNative()
|
||||
|
||||
private external fun getTypeNative(): ReadableType
|
||||
|
||||
private external fun isNullNative(): Boolean
|
||||
|
||||
external override fun asBoolean(): Boolean
|
||||
|
||||
// The native representation is holding the value as Double. We do the Int conversion here.
|
||||
override fun asInt(): Int = asDouble().toInt()
|
||||
|
||||
external override fun asDouble(): Double
|
||||
|
||||
external override fun asString(): String
|
||||
|
||||
external override fun asArray(): ReadableArray
|
||||
|
||||
external override fun asMap(): ReadableMap
|
||||
|
||||
override fun recycle() {
|
||||
// Noop - nothing to recycle since there is no pooling
|
||||
}
|
||||
}
|
||||
+2
-5
@@ -161,14 +161,11 @@ class TurboModuleInteropUtils {
|
||||
|| paramClass == Callback.class
|
||||
|| paramClass == Promise.class
|
||||
|| paramClass == ReadableMap.class
|
||||
|| paramClass == ReadableArray.class) {
|
||||
|| paramClass == ReadableArray.class
|
||||
|| paramClass == Dynamic.class) {
|
||||
return convertClassToJniType(paramClass);
|
||||
}
|
||||
|
||||
if (paramClass == Dynamic.class) {
|
||||
// TODO(T145105887): Output warnings that TurboModules doesn't yet support Dynamic arguments
|
||||
}
|
||||
|
||||
throw new ParsingException(
|
||||
moduleName,
|
||||
methodName,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "JDynamicNative.h"
|
||||
#include "ReadableNativeArray.h"
|
||||
#include "ReadableNativeMap.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
jboolean JDynamicNative::isNullNative() {
|
||||
return payload_.isNull();
|
||||
}
|
||||
|
||||
jni::local_ref<ReadableType> JDynamicNative::getTypeNative() {
|
||||
return ReadableType::getType(payload_.type());
|
||||
}
|
||||
|
||||
jni::local_ref<jstring> JDynamicNative::asString() {
|
||||
return jni::make_jstring(payload_.asString());
|
||||
}
|
||||
|
||||
jboolean JDynamicNative::asBoolean() {
|
||||
return payload_.asBool();
|
||||
}
|
||||
|
||||
jdouble JDynamicNative::asDouble() {
|
||||
return payload_.asDouble();
|
||||
}
|
||||
|
||||
jni::local_ref<ReadableArray> JDynamicNative::asArray() {
|
||||
return jni::adopt_local(reinterpret_cast<ReadableArray::javaobject>(
|
||||
ReadableNativeArray::newObjectCxxArgs(payload_).release()));
|
||||
}
|
||||
|
||||
jni::local_ref<ReadableMap> JDynamicNative::asMap() {
|
||||
return jni::adopt_local(reinterpret_cast<ReadableMap::javaobject>(
|
||||
ReadableNativeMap::createWithContents(std::move(payload_)).release()));
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NativeCommon.h"
|
||||
#include "ReadableNativeArray.h"
|
||||
#include "ReadableNativeMap.h"
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct JDynamic : public jni::JavaClass<JDynamic> {
|
||||
constexpr static auto kJavaDescriptor = "Lcom/facebook/react/bridge/Dynamic;";
|
||||
};
|
||||
|
||||
class JDynamicNative : public jni::HybridClass<JDynamicNative, JDynamic> {
|
||||
public:
|
||||
constexpr static auto kJavaDescriptor =
|
||||
"Lcom/facebook/react/bridge/DynamicNative;";
|
||||
|
||||
JDynamicNative(folly::dynamic payload) : payload_(std::move(payload)) {}
|
||||
|
||||
static void registerNatives() {
|
||||
javaClassStatic()->registerNatives(
|
||||
{makeNativeMethod("isNullNative", JDynamicNative::isNullNative),
|
||||
makeNativeMethod("getTypeNative", JDynamicNative::getTypeNative),
|
||||
makeNativeMethod("asDouble", JDynamicNative::asDouble),
|
||||
makeNativeMethod("asBoolean", JDynamicNative::asBoolean),
|
||||
makeNativeMethod("asString", JDynamicNative::asString),
|
||||
makeNativeMethod("asArray", JDynamicNative::asArray),
|
||||
makeNativeMethod("asMap", JDynamicNative::asMap)});
|
||||
}
|
||||
|
||||
private:
|
||||
friend HybridBase;
|
||||
|
||||
jni::local_ref<ReadableType> getTypeNative();
|
||||
jni::local_ref<jstring> asString();
|
||||
jboolean asBoolean();
|
||||
jdouble asDouble();
|
||||
jboolean isNullNative();
|
||||
jni::local_ref<ReadableArray> asArray();
|
||||
jni::local_ref<ReadableMap> asMap();
|
||||
|
||||
folly::dynamic payload_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "CatalystInstanceImpl.h"
|
||||
#include "CxxModuleWrapperBase.h"
|
||||
#include "JCallback.h"
|
||||
#include "JDynamicNative.h"
|
||||
#include "JInspector.h"
|
||||
#include "JReactMarker.h"
|
||||
#include "JavaScriptExecutorHolder.h"
|
||||
@@ -89,6 +90,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
NativeMap::registerNatives();
|
||||
ReadableNativeMap::registerNatives();
|
||||
WritableNativeMap::registerNatives();
|
||||
JDynamicNative::registerNatives();
|
||||
JReactMarker::registerNatives();
|
||||
JInspector::registerNatives();
|
||||
ReactInstanceManagerInspectorTarget::registerNatives();
|
||||
|
||||
+8
-1
@@ -19,6 +19,7 @@
|
||||
#include <jsi/JSIDynamic.h>
|
||||
#include <react/bridging/Bridging.h>
|
||||
#include <react/debug/react_native_assert.h>
|
||||
#include <react/jni/JDynamicNative.h>
|
||||
#include <react/jni/NativeMap.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
#include <react/jni/WritableNativeMap.h>
|
||||
@@ -373,7 +374,9 @@ JNIArgs convertJSIArgsToJNIArgs(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg->isNull() || arg->isUndefined()) {
|
||||
// Dynamic encapsulates the Null type so we don't want to return null here.
|
||||
if ((arg->isNull() && type != "Lcom/facebook/react/bridge/Dynamic;") ||
|
||||
arg->isUndefined()) {
|
||||
jarg->l = nullptr;
|
||||
} else if (type == "Ljava/lang/Double;") {
|
||||
if (!arg->isNumber()) {
|
||||
@@ -436,6 +439,10 @@ JNIArgs convertJSIArgsToJNIArgs(
|
||||
auto jParams =
|
||||
ReadableNativeMap::createWithContents(std::move(dynamicFromValue));
|
||||
jarg->l = makeGlobalIfNecessary(jParams.release());
|
||||
} else if (type == "Lcom/facebook/react/bridge/Dynamic;") {
|
||||
auto dynamicFromValue = jsi::dynamicFromValue(rt, *arg);
|
||||
auto jParams = JDynamicNative::newObjectCxxArgs(dynamicFromValue);
|
||||
jarg->l = makeGlobalIfNecessary(jParams.release());
|
||||
} else {
|
||||
throw JavaTurboModuleInvalidArgumentTypeException(
|
||||
type, argIndex, methodName);
|
||||
|
||||
+40
@@ -13,12 +13,14 @@ import android.widget.Toast;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.WritableNativeArray;
|
||||
@@ -155,6 +157,44 @@ public class SampleLegacyModule extends ReactContextBaseJavaModule {
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public WritableMap getDynamic(Dynamic dynamic) {
|
||||
WritableNativeMap resultMap = new WritableNativeMap();
|
||||
ReadableType type = dynamic.getType();
|
||||
if (type == ReadableType.Null) {
|
||||
log("getDynamic as Null", dynamic, dynamic);
|
||||
resultMap.putString("type", "Null");
|
||||
resultMap.putNull("value");
|
||||
} else if (type == ReadableType.Boolean) {
|
||||
boolean result = dynamic.asBoolean();
|
||||
log("getDynamic as Boolean", dynamic, result);
|
||||
resultMap.putString("type", "Boolean");
|
||||
resultMap.putBoolean("value", result);
|
||||
} else if (type == ReadableType.Number) {
|
||||
int result = dynamic.asInt();
|
||||
log("getDynamic as Number", dynamic, result);
|
||||
resultMap.putString("type", "Number");
|
||||
resultMap.putInt("value", result);
|
||||
} else if (type == ReadableType.String) {
|
||||
String result = dynamic.asString();
|
||||
log("getDynamic as String", dynamic, result);
|
||||
resultMap.putString("type", "String");
|
||||
resultMap.putString("value", result);
|
||||
} else if (type == ReadableType.Array) {
|
||||
ReadableArray result = dynamic.asArray();
|
||||
log("getDynamic as Array", dynamic, result);
|
||||
resultMap.putString("type", "Array");
|
||||
resultMap.putArray("value", result);
|
||||
} else if (type == ReadableType.Map) {
|
||||
ReadableMap result = dynamic.asMap();
|
||||
log("getDynamic as Map", dynamic, result);
|
||||
resultMap.putString("type", "Map");
|
||||
resultMap.putMap("value", result);
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
@SuppressWarnings("unused")
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
|
||||
@@ -142,6 +142,17 @@ class SampleLegacyModuleExample extends React.Component<{||}, State> {
|
||||
getSampleLegacyModule()?.getObject({a: 1, b: 'foo', c: null}),
|
||||
getValue: () =>
|
||||
getSampleLegacyModule()?.getValue(5, 'test', {a: 1, b: 'foo'}),
|
||||
getDynamicWithNull: () => getSampleLegacyModule()?.getDynamic(null),
|
||||
getDynamicWithBoolean: () =>
|
||||
getSampleLegacyModule()?.getDynamic(true),
|
||||
getDynamicWithNumber: () =>
|
||||
getSampleLegacyModule()?.getDynamic(42.24),
|
||||
getDynamicWithString: () =>
|
||||
getSampleLegacyModule()?.getDynamic('The answer is 42'),
|
||||
getDynamicWithArray: () =>
|
||||
getSampleLegacyModule()?.getDynamic(['the', 'answer', 'is', '42']),
|
||||
getDynamicWithMap: () =>
|
||||
getSampleLegacyModule()?.getDynamic({answer: '42'}),
|
||||
callback: () =>
|
||||
getSampleLegacyModule()?.getValueWithCallback(callbackValue =>
|
||||
this._setResult('callback', callbackValue),
|
||||
|
||||
Reference in New Issue
Block a user