场景描述
通过JSVM,可以在应用运行期间直接执行一段动态加载的JS代码。也可以选择将一些对性能、底层系统调用有较高要求的核心功能用C/C++实现并将C++方法注册到JS侧,在JS代码中直接调用,提高应用的执行效率。
功能描述
通过createJsCore方法来创建一个新的JS基础运行时环境,并通过该方法获得一个虚拟机ID,通过evalUateJS方法使用虚拟机ID对应的运行环境来运行JS代码,在JS代码中创建promise并异步调取TS侧设定的callback函数,最后使用releaseJsCore方法来释放虚拟机ID对应的运行环境。
JSVM主要交互流程
接口介绍
创建所需接口:
// 初始化虚拟机
JSVM_EXTERN JSVM_Status OH_JSVM_Init(const JSVM_InitOptions* options);
// 创建虚拟机实例
JSVM_EXTERN JSVM_Status OH_JSVM_CreateVM(const JSVM_CreateVMOptions* options,JSVM_VM* result);
// 创建虚拟机作用域
JSVM_EXTERN JSVM_Status OH_JSVM_OpenVMScope(JSVM_VM vm,JSVM_VMScope* result);
// 创建上下文环境
JSVM_EXTERN JSVM_Status OH_JSVM_CreateEnv(JSVM_VM vm,size_t propertyCount,const JSVM_PropertyDescriptor* properties,JSVM_Env* result);
// 创建上下文环境作用域
JSVM_EXTERN JSVM_Status OH_JSVM_OpenEnvScope(JSVM_Env env,JSVM_EnvScope* result);
执行所需接口:
// 开启新作用域
JSVM_EXTERN JSVM_Status OH_JSVM_OpenHandleScope(JSVM_Env env,JSVM_HandleScope* result);
// 编译一串JS代码,并返回编译后脚本
JSVM_EXTERN JSVM_Status OH_JSVM_CompileScript(JSVM_Env env,JSVM_Value script,const uint8_t* cachedData,size_t cacheDataLength,bool eagerCompile,bool* cacheRejected,JSVM_Script* result);
// 执行一段JS代码并返回结果
JSVM_EXTERN JSVM_Status OH_JSVM_RunScript(JSVM_Env env,JSVM_Script script,JSVM_Value* result);
// 关闭传入的作用域
JSVM_EXTERN JSVM_Status OH_JSVM_CloseHandleScope(JSVM_Env env,JSVM_HandleScope scope);
关闭所需接口:
// 关闭上下文环境作用域
JSVM_EXTERN JSVM_Status OH_JSVM_CloseEnvScope(JSVM_Env env,JSVM_EnvScope scope);
// 销毁上下文环境
JSVM_EXTERN JSVM_Status OH_JSVM_DestroyEnv(JSVM_Env env);
// 关闭虚拟机作用域
JSVM_EXTERN JSVM_Status OH_JSVM_CloseVMScope(JSVM_VM vm,JSVM_VMScope scope);
// 销毁虚拟机实例
JSVM_EXTERN JSVM_Status OH_JSVM_DestroyVM(JSVM_VM vm);
场景代码
场景一:JSVM执行JS代码并回调C++代码
创建虚拟机所需环境,编译并执行JS代码回调C++代码,销毁之前创建的虚拟机环境。
配置
cmakelists:
target_link_libraries(entry PUBLIC libjsvm.so)
ArkTS代码:
示例中包含了提供给JSVM的JS里的consoleinfo同步方法,createPromise创建异步方法,执行assertEqual方法,onJSResultCallback异步方法回调。
- 调用Native的创建虚拟机及环境的接口,绑定MyCallback回调(用于JS代码里onJSResultCallback方法的回调),接收native返回的虚拟机id。
- 调用Native的执行JS代码的接口,传入虚拟机id和JS代码字符串,在native侧的虚拟机里编译并执行。
- 调用Native的销毁虚拟机及环境的接口,传入虚拟机id,指定销毁对应的虚拟机和环境。
可以同时运行多个JSVM虚拟机执行多个JS代码。
import testNapi from 'libentry.so';
// 用于JSVM执行的JS代码字符串
let jsCodeStr = `{
let a = "hello World";
consoleinfo(a);
let b = add(99, 1);
const mPromise = createPromise();
mPromise.then((result) => {
assertEqual(result, 0);
onJSResultCallback(result, "abc", "v");
});
a;
};`;
function MyCallback(a:string, b:string):string {
console.log("TEST MyCallback run: " + a);
b = "callback done";
console.log("TEST MyCallback run: " + b);
return "callback pass";
}
// 创建首个运行环境,并绑定TS回调
const coreId = testNapi.createJsCore(MyCallback);
// 在首个运行环境中执行JS代码
testNapi.evalUateJS(coreId, jsCodeStr);
// 释放首个运行环境
testNapi.releaseJsCore(coreId);
Native代码:
JS运行环境创建,创建让JS代码运行的虚拟机环境:
- 通过OH_JSVM_Init初始化虚拟机。
- 通过OH_JSVM_CreateVM创建虚拟机实例。
- 通过OH_JSVM_OpenVMScope创建虚拟机作用域。
- 将本地函数的回调函数放到JSVM_PropertyDescriptor集合中(用于JS调用的C++函数)。
- 通过OH_JSVM_CreateEnv创建上下文环境并注册JSVM_PropertyDescriptor。
- 通过OH_JSVM_OpenEnvScope创建上下文环境作用域。
static void CreateArkJSContext() {
JSVM_Status status;
JSVM_InitOptions init_options;
memset(&init_options, 0, sizeof(init_options));
if (aa == 0) {
//****1****初始化JSVM
OH_JSVM_Init(&init_options);
aa++;
}
g_vmMap[ENVTAG_NUMBER] = new JSVM_VM;
JSVM_VMScope vmScope;
g_vmScopeMap[ENVTAG_NUMBER] = vmScope;
JSVM_CreateVMOptions options;
memset(&options, 0, sizeof(options));
//****2****创建JSVM实例
status = OH_JSVM_CreateVM(&options, g_vmMap[ENVTAG_NUMBER]);
//****3****创建JSVM作用域
status = OH_JSVM_OpenVMScope(*g_vmMap[ENVTAG_NUMBER], &g_vmScopeMap[ENVTAG_NUMBER]);
g_envMap[ENVTAG_NUMBER] = new JSVM_Env;
g_callBackStructMap[ENVTAG_NUMBER] = new JSVM_CallbackStruct[5];
// 注册用户提供的本地函数的回调函数指针和数据,通过JSVM-API暴露给JS
for (int i = 0; i < 5; i++) {
g_callBackStructMap[ENVTAG_NUMBER][i].data = nullptr;
}
g_callBackStructMap[ENVTAG_NUMBER][0].callback = Co