小手动一动,点赞转发加关注。微信搜索【大前端杂货铺】公众号关注大前端老司机带您遨游大前端知识的海洋。关注 Github https://github.com/big-frontend 还有大前端代码实践哦。

java 与 javascript 互操作原理

1.java 与 cpp 通信

javajni内存分配描述boolean(1bit)jboolean1byte无符号8位整型 uint8_tbytejbyte1byte有符号8位整型 int8_tcharjchar2bytes无符号16位整型 uint16_tshortjshort2bytes有符号8位整型 int16_tintjint4bytes有符号32位整型 int32_tlongjlong8bytes有符号64位整型 int64_tfloatjfloat4bytes32位浮点型 floatdoublejdouble8bytes64位浮点型 doubleObjectjobjectClassjclassStringjstringObject[]jobjectArrayboolean[]jbooleanArraybyte[]jbyteArraychar[]jcharArrayshort[]jshortArrayint[]jintArraylong[]jlongArrayfloat[]jfloatArraydouble[]jdoubleArrayvoidvoid

java访问cpp函数通过jni将java的native函数与cpp的函数进行映射,cpp访问java函数可以通过反射。

javafbjniTJavaClass

为了使其使用简单、易扩展、强鲁棒性,facebook封装了自己的库fbjni,其中的java与cpp混合对象内存管理利用了虚可达。

不可达:一个对象没有被有效的引用所指向,且指向该对象的PhantomReference(如果有的话)也成了垃圾虚可达:一个对象虽然没有被有效的引用所指向,但被PhantomReference引用所关联,且关联它的PhantomReference对象被其他有效引用指到了(不算垃圾了)

HybridData.java

public class HybridData {

static {

NativeLoader.loadLibrary("fbjni");

}

@DoNotStrip private Destructor mDestructor = new Destructor(this);

public synchronized void resetNative() {

mDestructor.destruct();

}

public boolean isValid() {

return mDestructor.mNativePointer != 0;

}

public static class Destructor extends DestructorThread.Destructor {

// Private C++ instance

@DoNotStrip private volatile long mNativePointer;

Destructor(Object referent) {

super(referent);

}

@Override

protected final void destruct() {

deleteNative(mNativePointer);

mNativePointer = 0;

}

static native void deleteNative(long pointer);

}

}

当java侧的对象没有被引用,jvm触发回收时,fbjni就会在Destructor#destruct,释放c++对象,从而避免内存泄漏等内存问题。

JavaClass.cpp

struct DocTests : JavaClass {

static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/DocTests;";

}

在cpp堆中创建java类对象,通过智能指针管理生命周期。

cpp标准库的智能指针与fbjni的智能引用

cpp

- weak_ptr:weak_ptr可以解决shared_ptr循环引用问题,导致内存泄漏问题

- shared_ptr:只有引用计数为0才会释放指针

- unique_ptr:引用计数只能为1

jni

- alias_ref:non-owning reference, like a bare pointer。用于函数的形参

- local_ref:引用计数指针。用于函数体内部应用,return 到java侧自动释放

- global_ref:引用计数指针。用于类成员变量,return到java侧并不会自动释放

2.javascript 与 cpp 通信

javascriptjsijs的对象host objectjs的函数host functioin

javascript调用cpp接口通过jsi, cpp调用javascript接口也是通过jsi

//TurboModuleRegistry.js

const turboModuleProxy = global.__turboModuleProxy;

function requireModule(name: string): ?T {

...

if (turboModuleProxy != null) {

const module: ?T = turboModuleProxy(name);

return module;

}

return null;

}

...

//TurboModuleBinding.cpp

void TurboModuleBinding::install(

jsi::Runtime &runtime,

const TurboModuleProviderFunctionType &&moduleProvider,

TurboModuleBindingMode bindingMode,

std::shared_ptr longLivedObjectCollection) {

runtime.global().setProperty(

runtime,

"__turboModuleProxy",

jsi::Function::createFromHostFunction(

runtime,

jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),

1,

[binding = TurboModuleBinding(

std::move(moduleProvider),

bindingMode,

std::move(longLivedObjectCollection))](

jsi::Runtime &rt,

const jsi::Value &thisVal,

const jsi::Value *args,

size_t count) mutable {

return binding.getModule(rt, thisVal, args, count);

}));

}

js函数__turboModuleProxy为global对象的成员属性,在react native初始化的时候cpp层通过createFromHostFunction函数将入host function注入到global对象。

createFromHostFunction函数参数如下

runtime:js引擎name:函数名paramCount:函数参数个数func:函数体

在react native中使用了jsi技术将cpp层的函数映射js侧的函数,就能相互调用.

3.java 与 javascript 通信

react native的java与javascript通信是基于前面两种融合实现的,前者使用jni后者使用jsi,cpp层作为了两者的桥梁。

javascript调用java接口

这里我们来案例分析一个例子,js如何调用java的接口。

在native模块接口实现

//native module

public class CalendarModule extends ReactContextBaseJavaModule {

CalendarModule(ReactApplicationContext context) {

super(context);

}

@Override

public String getName() {

return "CalendarModule";

}

@ReactMethod

public void createCalendarEvent(String name, String location) {

}

}

//包

public class MyAppPackage implements ReactPackage {

@Override

public List createViewManagers(ReactApplicationContext reactContext) {

return Collections.emptyList();

}

@Override

public List createNativeModules(

ReactApplicationContext reactContext) {

List modules = new ArrayList<>();

modules.add(new CalendarModule(reactContext));

return modules;

}

}

//app

public class MainApplication{

@Override

protected List getPackages() {

@SuppressWarnings("UnnecessaryLocalVariable")

List packages = new PackageList(this).getPackages();

// below MyAppPackage is added to the list of packages returned

packages.add(new MyAppPackage());

return packages;

}

}

在js中调用接口

import React from 'react';

import { NativeModules, Button } from 'react-native';

const NewModuleButton = () => {

const onPress = () => {

const { CalendarModule } = NativeModules;

//CalendarModule类的静态方法

CalendarModule.createCalendarEvent('testName', 'testLocation');

console.log('We will invoke the native module here!');

};

return (

title="Click to invoke your native module!"

color="#841584"

onPress={onPress}

/>

);

};

export default NewModuleButton;

这里有两处关键逻辑

查找到对于的native模块调用native模块中的函数

1.获取native module

当NativeModules被import之后,NativeModules.js模块会被初始化,由于使用了jsi接口架构,NativeModule就是全局对象global的nativeModuleProxy

let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};

if (global.nativeModuleProxy) {

NativeModules = global.nativeModuleProxy;

} else if (!global.nativeExtensions) {

const bridgeConfig = global.__fbBatchedBridgeConfig;

invariant(

bridgeConfig,

'__fbBatchedBridgeConfig is not set, cannot invoke native modules',

);

const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');

(bridgeConfig.remoteModuleConfig || []).forEach(

(config: ModuleConfig, moduleID: number) => {

// Initially this config will only contain the module name when running in JSC. The actual

// configuration of the module will be lazily loaded.

const info = genModule(config, moduleID);

if (!info) {

return;

}

if (info.module) {

NativeModules[info.name] = info.module;

}

// If there's no module config, define a lazy getter

else {

defineLazyObjectProperty(NativeModules, info.name, {

get: () => loadModule(info.name, moduleID),

});

}

},

);

}

module.exports = NativeModules;

当const {CalendarModule} = NativeModules; 进行NativeModules解构时,会调用cpp层的NativeModuleProxy#get函数,因为NativeModuleProxy是JSINativeModules的代理类,所以真正查找模块还得看JSINativeModules,其调用链为JSINativeModules#getModule ---> ModuleRegistry#getConfig ---> m_genNativeModuleJS#call(js侧的函数global.__fbGenNativeModule) ModuleRegistry为模块的注册中心,所以我们需要知道模块什么时候注册到ModuleRegistry,这里就不继续追踪了直接给答案。在createReactContext时,会解析所有的ReactPackage得到全部的native模块并且存放在java侧的NativeModuleRegistry(存放ModuleHolder)中,然后在CatalystInstanceImpl#initializeBridge时,会将所有的native module传递到cpp层的ModuleRegistry(存放NativeModule)进行注册,方便js侧查询且使用。

通过ModuleRegistry获取到函数的元数据,然后将这些数据传给m_genNativeModuleJS,调用js侧global.__fbGenNativeModule(指向genModule函数)生成模块以及内部的函数,返回给cpp层的对象为这样的数据结构

{

name: string,

module?: {...},

...

}

//本质上就是NativeModules类型

let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};

cpp层的JSINativeModules得到生成的模块之后会先缓存一份再给js侧解构之后的变量。

2.调用native module的函数

当js侧执行CalendarModule.createCalendarEvent('testName', 'testLocation');指令时,就会调用之前在生成模块与函数时埋下的回调。

function genMethod(moduleID: number, methodID: number, type: MethodType) {

let fn = null;

if (type === 'promise') {

...

} else {

fn = function nonPromiseMethodWrapper(...args: Array) {

const lastArg = args.length > 0 ? args[args.length - 1] : null;

const secondLastArg = args.length > 1 ? args[args.length - 2] : null;

const hasSuccessCallback = typeof lastArg === 'function';

const hasErrorCallback = typeof secondLastArg === 'function';

...

// $FlowFixMe[incompatible-type]

const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;

// $FlowFixMe[incompatible-type]

const onFail: ?(mixed) => void = hasErrorCallback ? secondLastArg : null;

const callbackCount = hasSuccessCallback + hasErrorCallback;

const newArgs = args.slice(0, args.length - callbackCount);

if (type === 'sync') {

return BatchedBridge.callNativeSyncHook(

moduleID,

methodID,

newArgs,

onFail,

onSuccess,

);

} else {

BatchedBridge.enqueueNativeCall(

moduleID,

methodID,

newArgs,

onFail,

onSuccess,

);

}

};

}

fn.type = type;

return fn;

}

这里我们可以看到函数的类型分为promise、async/await、sync,对于同步函数来说执行BatchedBridge.callNativeSyncHook(BatchedBridge为MessageQueue类实例化的对象)调用。 其调用链为

---> MessageQueue#callNativeSyncHook

---> global.nativeCallSyncHook

---> JSIExecutor#nativeCallSyncHook(cpp层)

---> JsToNativeBridge#callSerializableNativeHook

---> ModuleRegistry#callSerializableNativeHook

---> JavaNativeModule#callSerializableNativeHook

---> MethodInvoker#invoke

MethodCallResult MethodInvoker::invoke(

std::weak_ptr &instance,

alias_ref module,

const folly::dynamic ¶ms) {

#ifdef WITH_FBSYSTRACE

fbsystrace::FbSystraceSection s(

TRACE_TAG_REACT_CXX_BRIDGE,

isSync_ ? "callJavaSyncHook" : "callJavaModuleMethod",

"method",

traceName_);

#endif

...

auto env = Environment::current();

auto argCount = signature_.size() - 2;

JniLocalScope scope(env, argCount);

jvalue args[argCount];

std::transform(

signature_.begin() + 2,

signature_.end(),

args,

[&instance, it = params.begin(), end = params.end()](char type) mutable {

return extract(instance, type, it, end);

});

#define PRIMITIVE_CASE(METHOD) \

{ \

auto result = env->Call##METHOD##MethodA(module.get(), method_, args); \

throwPendingJniExceptionAsCppException(); \

return folly::dynamic(result); \

}

#define PRIMITIVE_CASE_CASTING(METHOD, RESULT_TYPE) \

{ \

auto result = env->Call##METHOD##MethodA(module.get(), method_, args); \

throwPendingJniExceptionAsCppException(); \

return folly::dynamic(static_cast(result)); \

}

#define OBJECT_CASE(JNI_CLASS, ACTIONS) \

{ \

auto jobject = env->CallObjectMethodA(module.get(), method_, args); \

throwPendingJniExceptionAsCppException(); \

if (!jobject) { \

return folly::dynamic(nullptr); \

} \

auto result = adopt_local(static_cast(jobject)); \

return folly::dynamic(result->ACTIONS()); \

}

#define OBJECT_CASE_CASTING(JNI_CLASS, ACTIONS, RESULT_TYPE) \

{ \

auto jobject = env->CallObjectMethodA(module.get(), method_, args); \

throwPendingJniExceptionAsCppException(); \

if (!jobject) { \

return folly::dynamic(nullptr); \

} \

auto result = adopt_local(static_cast(jobject)); \

return folly::dynamic(static_cast(result->ACTIONS())); \

}

char returnType = signature_.at(0);

switch (returnType) {

case 'v':

env->CallVoidMethodA(module.get(), method_, args);

throwPendingJniExceptionAsCppException();

return folly::none;

case 'z':

PRIMITIVE_CASE_CASTING(Boolean, bool)

case 'Z':

OBJECT_CASE_CASTING(JBoolean, value, bool)

case 'i':

PRIMITIVE_CASE(Int)

case 'I':

OBJECT_CASE(JInteger, value)

case 'd':

PRIMITIVE_CASE(Double)

case 'D':

OBJECT_CASE(JDouble, value)

case 'f':

PRIMITIVE_CASE(Float)

case 'F':

OBJECT_CASE(JFloat, value)

case 'S':

OBJECT_CASE(JString, toStdString)

case 'M':

OBJECT_CASE(WritableNativeMap, cthis()->consume)

case 'A':

OBJECT_CASE(WritableNativeArray, cthis()->consume)

default:

LOG(FATAL) << "Unknown return type: " << returnType;

return folly::none;

}

}

从这里我们就能够知道最后通过jvm反射的方式调用模块的函数,在调用链的最后一环,完成到达java侧的逻辑。这个调用链都是在js线程完成的,也就是会阻塞js线程,如果不想阻塞js线程,可以采用异步的方式,promise或者async/await,异步的方式会将模块与函数的信息存到queue,flush到cpp层(global.nativeFlushQueueImmediate),flush间隔不能小于5ms。 调用链

---> global.nativeFlushQueueImmediate

---> JSIExecutor#callNativeModules

---> JsToNativeBridge#callNativeModules

---> ModuleRegistry#callNativeMethod

---> JavaNativeModule#invoke(切到mqt_native_modules线程)

这样就完成了异步操作。

那么如何回调?方法执行完成之后,JavaMethodWrapper#ARGUMENT_EXTRACTOR_CALLBACK的callback将数据放回给js侧,

---> CallbackImpl#invoke

---> CatalystInstanceImpl#invokeCallback(CatalystInstanceImpl为JSInstance类的实现化对象)

---> CatalystInstanceImpl#jniCallJSCallback

---> Instance::callJSCallback

---> NativeToJsBridge#invokeCallback(切换到mqt_js线程)

---> ... ---> MessageQueue#invokeCallbackAndReturnFlushedQueue

3.升级版turbo

2022年react native架构进行了升级,提出了一种turbo package,使用turbo方式编写的模块使用懒加载,需要实现TurboReactPackage包与TurboModule模块。下面是一个sample的代码。

SampleTurboModule js

TurboModuleExample.js

const React = require('react');

const SampleTurboModuleExample = require('./SampleTurboModuleExample');

exports.displayName = (undefined: ?string);

exports.title = 'TurboModule';

exports.category = 'Basic';

exports.description = 'Usage of TurboModule';

exports.examples = [

{

title: 'SampleTurboModule',

render: function (): React.Element {

return ;

},

},

];

NativeSampleTurboModule.js

...

export interface Spec extends TurboModule {

// Exported methods.

+getConstants: () => {|

const1: boolean,

const2: number,

const3: string,

|};

+voidFunc: () => void;

+getBool: (arg: boolean) => boolean;

+getNumber: (arg: number) => number;

+getString: (arg: string) => string;

+getArray: (arg: Array) => Array;

+getObject: (arg: Object) => Object;

+getUnsafeObject: (arg: UnsafeObject) => UnsafeObject;

+getRootTag: (arg: RootTag) => RootTag;

+getValue: (x: number, y: string, z: Object) => Object;

+getValueWithCallback: (callback: (value: string) => void) => void;

+getValueWithPromise: (error: boolean) => Promise;

}

export default (TurboModuleRegistry.getEnforcing(

'SampleTurboModule',

): Spec);

SampleTurboModule java

//export的接口声明

public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {

public NativeSampleTurboModuleSpec(ReactApplicationContext reactContext) {

super(reactContext);

}

...

@ReactMethod(isBlockingSynchronousMethod = true)

public abstract double getNumber(double arg);

...

}

//export的接口实现

@ReactModule(name = SampleTurboModule.NAME)

public class SampleTurboModule extends NativeSampleTurboModuleSpec {

@DoNotStrip

@SuppressWarnings("unused")

@Override

public double getNumber(double arg) {

log("getNumber", arg, arg);

return arg;

}

}

SampleTurboModule cpp

//cpp header

namespace facebook {

namespace react {

/**

* C++ class for module 'SampleTurboModule'

*/

class JSI_EXPORT NativeSampleTurboModuleSpecJSI : public JavaTurboModule {

public:

NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms);

};

std::shared_ptr SampleTurboModuleSpec_ModuleProvider(

const std::string &moduleName,

const JavaTurboModule::InitParams ¶ms);

} // namespace react

} // namespace facebook

//cpp source

//该函数对应SampleTurboModule文件的getNumber

static facebook::jsi::Value

__hostFunction_NativeSampleTurboModuleSpecJSI_getNumber(

facebook::jsi::Runtime &rt,

TurboModule &turboModule,

const facebook::jsi::Value *args,

size_t count) {

return static_cast(turboModule)

.invokeJavaMethod(rt, NumberKind, "getNumber", "(D)D", args, count);

}

...

NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(

const JavaTurboModule::InitParams ¶ms)

: JavaTurboModule(params) {

methodMap_["voidFunc"] =

MethodMetadata{0, __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc};

methodMap_["getBool"] =

MethodMetadata{1, __hostFunction_NativeSampleTurboModuleSpecJSI_getBool};

methodMap_["getNumber"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getNumber};

methodMap_["getString"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getString};

methodMap_["getArray"] =

MethodMetadata{1, __hostFunction_NativeSampleTurboModuleSpecJSI_getArray};

methodMap_["getObject"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getObject};

methodMap_["getRootTag"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getRootTag};

methodMap_["getValue"] =

MethodMetadata{3, __hostFunction_NativeSampleTurboModuleSpecJSI_getValue};

methodMap_["getValueWithCallback"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithCallback};

methodMap_["getValueWithPromise"] = MethodMetadata{

1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise};

methodMap_["getConstants"] = MethodMetadata{

0, __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants};

}

std::shared_ptr SampleTurboModuleSpec_ModuleProvider(

const std::string &moduleName,

const JavaTurboModule::InitParams ¶ms) {

if (moduleName == "SampleTurboModule") {

return std::make_shared(params);

}

return nullptr;

}

上面的sample代码,我们可以看到在cpp层会将java侧的SampleTurboModule.java的函数元数据信息注册到methodMap_,注册的时机为jni load时。

//js:global.__turboModuleProxy --> cpp:TurboModuleBinding

jsi::Value TurboModuleBinding::getModule(

jsi::Runtime &runtime,

const jsi::Value &thisVal,

const jsi::Value *args,

size_t count) {

if (count < 1) {

throw std::invalid_argument(

"__turboModuleProxy must be called with at least 1 argument");

}

std::string moduleName = args[0].getString(runtime).utf8(runtime);

std::shared_ptr module;

{

SystraceSection s(

"TurboModuleBinding::moduleProvider", "module", moduleName);

module = moduleProvider_(moduleName);

}

if (module) {

// Default behaviour

if (bindingMode_ == TurboModuleBindingMode::HostObject) {

return jsi::Object::createFromHostObject(runtime, std::move(module));

}

auto &jsRepresentation = module->jsRepresentation_;

if (!jsRepresentation) {

jsRepresentation = std::make_unique(runtime);

if (bindingMode_ == TurboModuleBindingMode::Prototype) {

// Option 1: create plain object, with it's prototype mapped back to the

// hostobject. Any properties accessed are stored on the plain object

auto hostObject =

jsi::Object::createFromHostObject(runtime, std::move(module));

jsRepresentation->setProperty(

runtime, "__proto__", std::move(hostObject));

} else {

// Option 2: eagerly install all hostfunctions at this point, avoids

// prototype

for (auto &propName : module->getPropertyNames(runtime)) {

module->get(runtime, propName);

}

}

}

return jsi::Value(runtime, *jsRepresentation);

} else {

return jsi::Value::null();

}

}

TurboModuleProviderFunctionType moduleProvider_;

与global.nativeModuleProxy相比turbo也有一个proxy(global.__turboModuleProxy),通过TurboModuleBinding类将js侧的global.__turboModuleProxy与cpp层的某个host function绑定。那么调用global.__turboModuleProxy(moduleName)就可直接调用TurboModuleBinding#getModule函数获取模块。

通过codegen会自动生成cpp与java的turbo接口代码,java侧的TurboModule的接口签名信息与函数地址会被存储在cpp层的TurboModule#methodMap_中.

获取某个函数地址时会从methodMap_中获取,当调用函数会执行MethodMetadata.invokder.

//获取函数地址

virtual facebook::jsi::Value get(

facebook::jsi::Runtime &runtime,

const facebook::jsi::PropNameID &propName) override {

std::string propNameUtf8 = propName.utf8(runtime);

auto p = methodMap_.find(propNameUtf8);

if (p == methodMap_.end()) {

// Method was not found, let JS decide what to do.

return jsi::Value::undefined();

}

MethodMetadata meta = p->second;

return jsi::Function::createFromHostFunction(

runtime,

propName,

static_cast(meta.argCount),

//调用某个函数时

[this, meta](

facebook::jsi::Runtime &rt,

const facebook::jsi::Value &thisVal,

const facebook::jsi::Value *args,

size_t count) { return meta.invoker(rt, *this, args, count); });

}

由于cpp层的JTurboModule对象与java侧的TurboModule对象是混合对象,所以执行MethodMetadata.invokder之后就会调用TurboModule#getNumber函数 JavaTurboModule.h

struct JTurboModule : jni::JavaClass {

static auto constexpr kJavaDescriptor =

"Lcom/facebook/react/turbomodule/core/interfaces/TurboModule;";

};

java调用javascript接口

那么java如何调用javascript接口呢? javascript接口实现

const AppRegistry = {

...

runApplication(

appKey: string,

appParameters: any,

displayMode?: number,

): void {

...

},

...

unmountApplicationComponentAtRootTag(rootTag: RootTag): void {

// NOTE: RootTag type

// $FlowFixMe[incompatible-call] RootTag: RootTag is incompatible with number, needs an updated synced version of the ReactNativeTypes.js file

ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag);

},

...

startHeadlessTask(taskId: number, taskKey: string, data: any): void {

...

}

...

}

java接口调用

public interface AppRegistry extends JavaScriptModule {

void runApplication(String appKey, WritableMap appParameters);

void unmountApplicationComponentAtRootTag(int rootNodeTag);

void startHeadlessTask(int taskId, String taskKey, WritableMap data);

}

catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);

JavaScriptModuleRegistry#getJavaScriptModule通过动态代理创建一个AppRegistry代理类

private static class JavaScriptModuleInvocationHandler implements InvocationHandler {

private final CatalystInstance mCatalystInstance;

private final Class mModuleInterface;

private @Nullable String mName;

...

private String getJSModuleName() {

if (mName == null) {

// Getting the class name every call is expensive, so cache it

mName = JavaScriptModuleRegistry.getJSModuleName(mModuleInterface);

}

return mName;

}

@Override

public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)

throws Throwable {

NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();

mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);

return null;

}

}

继续调用

---> java侧:CatalystInstance#callFunction

---> java侧:PendingJSCall#call

---> cpp层:CatalystInstance#jniCallJSFunction

---> cpp层:Instant#callJSFunction

---> cpp层:NativeToJsBridge#callFunction(切到mqt_js线程)

---> cpp层:JSIExecutor#callFunction

---> cpp层:调用callFunctionReturnFlushedQueue_#call

---> javascript侧:MessageQueue#callFunctionReturnFlushedQueue(回调js接口)

---> javascript侧:...

---> javascript侧:AppRegistry#runApplication 创建react元素树 与 shadow树

---> javascript侧:MessageQueue#flushedQueue 数据通过queue传给cpp层

---> cpp层:得到callFunctionReturnFlushedQueue_#call的返回结果

---> cpp层:JsToNativeBridge#callNativeModules , isEndOfBatch的值为true时,会调用onBatchComplete函数

---> java侧:ReactCallback#onBatchComplete

---> java侧:NativeModuleRegistry#onBatchComplete

---> java侧:UIManagerModule#onBatchComplete 开始异步计算shadow树的布局

整个链路到最后通过js引擎调用js接口,再把值通过JsToNativeBridge返回给java调用者,为了保证js接口安全,NativeToJsBridge在处理时会切换到了mqt_js线程。

MessageQueueNativeToJsBridgedesccallFunctionReturnFlushedQueuecallFunction回调时都会切换到mqt_js线程invokeCallbackAndReturnFlushedQueueinvokeCallback回调时都会切换到mqt_js线程

参考资料

Java中PhantomReference和ReferenceQueue的使用方法和工作机制

C++11学习

Chromium和WebKit的智能指针实现原理分析

小手动一动,点赞转发加关注。微信搜索【大前端杂货铺】公众号关注大前端老司机带您遨游大前端知识的海洋。关注 Github https://github.com/big-frontend 还有大前端代码实践哦。

相关链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。