JS代码require到沙箱的JS文件

Cocos引擎加载js文件,能否加载沙箱内的js文件

HarmonyOS
2024-12-27 16:38:13
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
aquaa

提供Demo:

#include <cstring>
#include <fstream>
#include <string>
#include <vector>

// 依赖libjsvm.so
#include "ark_runtime/jsvm.h"

using namespace std;

static JSVM_Value hello(JSVM_Env env, JSVM_CallbackInfo info) {
  JSVM_Value output;
  void* data = nullptr;
  OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, nullptr, &data);
  OH_JSVM_CreateStringUtf8(env, (char*)data, strlen((char*)data), &output);
  return output;
}

static JSVM_CallbackStruct hello_cb = { hello, (void*)"Hello" };

static string srcGlobal = R"JS(
  const concat = (...args) => args.reduce((a, b) => a + b);
)JS";

static void run_script(JSVM_Env env, string& src,
const uint8_t** dataPtr = nullptr,
size_t* lengthPtr = nullptr) {
  JSVM_HandleScope handleScope;
  OH_JSVM_OpenHandleScope(env, &handleScope);

  JSVM_Value jsSrc;
  OH_JSVM_CreateStringUtf8(env, src.c_str(), src.size(), &jsSrc);

  const uint8_t* data = dataPtr ? *dataPtr : nullptr;
  size_t length = lengthPtr ? *lengthPtr : 0;
  bool cacheRejected = true;
  JSVM_Script script;
  // 编译js代码
  OH_JSVM_CompileScript(env, jsSrc, data, length, true, &cacheRejected, &script);
  printf("Code cache is %s\n", cacheRejected ? "rejected" : "used");

  JSVM_Value result;
  // 执行js代码
  OH_JSVM_RunScript(env, script, &result);

  char resultStr[128];
  size_t size;
  OH_JSVM_GetValueStringUtf8(env, result, resultStr, 128, &size);
  printf("%s\n", resultStr);

  if (dataPtr && lengthPtr && *dataPtr == nullptr) {
    // 将js源码编译出的脚本保存到cache,可以避免重复编译,带来性能提升
    OH_JSVM_CreateCodeCache(env, script, dataPtr, lengthPtr);
    printf("Code cache created with length = %ld\n", *lengthPtr);
  }

  OH_JSVM_CloseHandleScope(env, handleScope);
}

static void create_snapshot() {
  JSVM_VM vm;
  JSVM_CreateVMOptions options;
  memset(&options, 0, sizeof(options));
  options.isForSnapshotting = true;
  OH_JSVM_CreateVM(&options, &vm);
  JSVM_VMScope vmScope;
  OH_JSVM_OpenVMScope(vm, &vmScope);

  JSVM_Env env;
  // 将native函数注册成js可调用的方法,hello_cb中记录该native方法的指针和参数等信息
  JSVM_PropertyDescriptor descriptors[] = {
    { "hello", NULL, &hello_cb, NULL, NULL, NULL, JSVM_DEFAULT }
};
OH_JSVM_CreateEnv(vm, 1, descriptors, &env);

JSVM_EnvScope envScope;
OH_JSVM_OpenEnvScope(env, &envScope);
// 执行js源码src,src中可以包含任何js语法。也可以调用已注册的native方法。
string src = srcGlobal + "concat(hello(), ', ', 'World from create_snapshot!');";
run_script(env, src);

// 创建snapshot,将当前的env保存到字符串,可以在某个时机通过该字符串还原出env,避免重复定义该env中的属性,带来性能提升。
const char* blobData = nullptr;
size_t blobSize = 0;
JSVM_Env envs[1] = { env };
OH_JSVM_CreateSnapshot(vm, 1, envs, &blobData, &blobSize);
printf("Snapshot blob size = %ld\n", blobSize);

// 如果将snapshot保存到文件中,需要考虑应用中的文件读写权限
ofstream file("blob.bin", ios::out | ios::binary | ios::trunc);
file.write(blobData, blobSize);
file.close();

OH_JSVM_CloseEnvScope(env, envScope);
OH_JSVM_DestroyEnv(env);
OH_JSVM_CloseVMScope(vm, vmScope);
OH_JSVM_DestroyVM(vm);
}

void run_without_snapshot(const uint8_t** dataPtr, size_t* lengthPtr) {
  // 创建虚拟机实例
  JSVM_VM vm;
  OH_JSVM_CreateVM(nullptr, &vm);
  JSVM_VMScope vmScope;
  OH_JSVM_OpenVMScope(vm, &vmScope);

  JSVM_Env env;
  // 将native函数注册成js可调用的方法,hello_cb中记录该native方法的指针和参数等信息
  JSVM_PropertyDescriptor descriptors[] = {
    { "hello", NULL, &hello_cb, NULL, NULL, NULL, JSVM_DEFAULT }
};
OH_JSVM_CreateEnv(vm, 1, descriptors, &env);
JSVM_EnvScope envScope;
OH_JSVM_OpenEnvScope(env, &envScope);
// 执行js源码src,src中可以包含任何js语法。也可以调用已注册的native方法。
auto src = srcGlobal + "concat(hello(), ', ', 'World', ' from run_without_snapshot!')";
run_script(env, src, dataPtr, lengthPtr);

OH_JSVM_CloseEnvScope(env, envScope);
OH_JSVM_DestroyEnv(env);
OH_JSVM_CloseVMScope(vm, vmScope);
OH_JSVM_DestroyVM(vm);
}

void run_with_snapshot(const uint8_t **dataPtr, size_t *lengthPtr) {
  // The lifetime of blobData must not be shorter than that of the vm.
  // 如果从文件中读取snapshot,需要考虑应用中的文件读写权限
  vector<char> blobData;
  ifstream file("blob.bin", ios::in | ios::binary | ios::ate);
  size_t blobSize = file.tellg();
  blobData.resize(blobSize);
  file.seekg(0, ios::beg);
  file.read(blobData.data(), blobSize);
  file.close();

  // 创建虚拟机实例
  JSVM_VM vm;
  JSVM_CreateVMOptions options;
  memset(&options, 0, sizeof(options));
  options.snapshotBlobData = blobData.data();
  options.snapshotBlobSize = blobSize;
  OH_JSVM_CreateVM(&options, &vm);
  JSVM_VMScope vmScope;
  OH_JSVM_OpenVMScope(vm, &vmScope);

  // 从快照中创建env
  JSVM_Env env;
  OH_JSVM_CreateEnvFromSnapshot(vm, 0, &env);
  JSVM_EnvScope envScope;
  OH_JSVM_OpenEnvScope(env, &envScope);

  // 执行js脚本,因为快照记录的env中定义了hello(),所以无需重新定义。dataPtr中如果保存了编译后的js脚本,就能直接执行js脚本,避免从源码重复编译。
  string src = "concat(hello(), ', ', 'World', ' from run_with_snapshot!')";
  run_script(env, src, dataPtr, lengthPtr);

  OH_JSVM_CloseEnvScope(env, envScope);
  OH_JSVM_DestroyEnv(env);
  OH_JSVM_CloseVMScope(vm, vmScope);
  OH_JSVM_DestroyVM(vm);
}

void print_vm_info() {
  JSVM_VMInfo vmInfo;
  OH_JSVM_GetVMInfo(&vmInfo);
  printf("apiVersion: %d\n", vmInfo.apiVersion);
  printf("engine: %s\n", vmInfo.engine);
  printf("version: %s\n", vmInfo.version);
  printf("cachedDataVersionTag: 0x%x\n", vmInfo.cachedDataVersionTag);
}

static intptr_t externals[] = {
  (intptr_t)&hello_cb,
  0,
};

int main(int argc, char *argv[]) {
  if (argc <= 1) {
    printf("Usage: %s gen-snapshot|use-snapshot|no-snapshot\n", argv[0]);
    return 0;
  }

  JSVM_InitOptions initOptions;
  memset(&initOptions, 0, sizeof(initOptions));
  initOptions.externalReferences = externals;
  // 初始化引擎,一个进程中只能初始化一次
  OH_JSVM_Init(&initOptions);
  print_vm_info();

  if (argv[1] == string("gen-snapshot")) {
    create_snapshot();
    return 0;
  }

  // snapshot可以记录下某个时间的js执行环境,可以跨进程通过snapshot快速还原出js执行上下文环境,前提是保证snapshot数据的生命周期。
  const auto use_snapshot = argv[1] == string("use-snapshot");
  const auto run = use_snapshot ? run_with_snapshot : run_without_snapshot;
  const uint8_t* data = nullptr;
  size_t length = 0;
  run(&data, &length);
  run(&data, &length);
  delete[] data;

  return 0;
}
分享
微博
QQ
微信
回复
2024-12-27 19:12:00
相关问题
HarmonyOS 如何调用js代码
438浏览 • 1回复 待解决
如何在js文件中引入自定义js文件
8123浏览 • 1回复 待解决
HarmonyOS web组件注入JS代码
233浏览 • 1回复 待解决
HarmonyOS native层js代码调用
488浏览 • 1回复 待解决
HarmonyOS rawfile文件拷贝沙箱
581浏览 • 1回复 待解决
需要提供c++js通信demo
968浏览 • 1回复 待解决
js api 如何读取预置json文件
7850浏览 • 1回复 待解决
资源目录下文件沙箱单向流动
1508浏览 • 1回复 待解决
加密算法(crypto-js)Arkts转化代码
1582浏览 • 1回复 待解决
基于JSVM创建引擎执行JS代码并销毁
986浏览 • 1回复 待解决
如何在ArkTS代码中执行HTML内JS函数
2857浏览 • 1回复 待解决
js开发上传文件路径问题
6735浏览 • 2回复 待解决
HarmonyOS web组件如何注入js文件
427浏览 • 1回复 待解决
HarmonyOS 如何调用工程里js文件
314浏览 • 1回复 待解决
ArkTS调用js/ts代码会有性能损耗吗
3357浏览 • 2回复 待解决