惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
J
Java Code Geeks
L
LangChain Blog
V
V2EX
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
博客园 - Franky
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
Blog — PlanetScale
Blog — PlanetScale
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Cloudflare Blog
博客园 - 司徒正美
B
Blog
G
Google Developers Blog
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
Engineering at Meta
Engineering at Meta
MyScale Blog
MyScale Blog
有赞技术团队
有赞技术团队
Hugging Face - Blog
Hugging Face - Blog

人人都是产品经理

为什么你的产品找不到差异化?90%的失败都卡在第一步上(下) – 人人都是产品经理, 3年从30万到1300万用户、获2200万美元融资,这个AI教育产品用“抽卡”破解了获客难题 – 人人都是产品经理, 园区招商系统怎么做才能真正帮到去化?我加了这一个功能,推广链接转发400次阅读过万 – 人人都是产品经理, AI大事件:OpenAI发完网络安全模型又搞药物研发,小鹏汽车要抓”DeepSeek时刻” – 人人都是产品经理, 电商不是卖货,是一场更残酷的产品经理实战 – 人人都是产品经理, 没想到,活动营销又回来了! – 人人都是产品经理, 为何All-in海外KOC:一场关于AI时代窗口期的豪赌 – 人人都是产品经理, 重新理解企业的内部协作 – 人人都是产品经理, 苹果的 AI 战略到底是什么? – 人人都是产品经理, 医疗智能体·第2讲——合规护城河:等保、PIPL与HIPAA的架构实战 – 人人都是产品经理, 向量知识库五步法:从“答非所问”到“精准回复” – 人人都是产品经理, 鸿蒙PC三方库构建总指挥HPKBUILD(sha)库为例 – 人人都是产品经理, 何时该用LLM?AI产品经理的LLM设计指南 – 人人都是产品经理, 医疗信息领域的需求方、决策方、准入方以及关注点(二) – 人人都是产品经理, 即梦涨价:一场被误读的「傲慢」 – 人人都是产品经理, 面试AI PM必答题:Hermes和OpenClaw的区别,如何讲清楚业务价值 – 人人都是产品经理, AI的下一张船票:世界模型——AI产品经理必须理解的技术拐点 – 人人都是产品经理, 小红书做GEO,怎么让AI信你?记住这 3 个重要信息 – 人人都是产品经理, 5 家印度 AI 初创公司,看看印度 AI 再做什么 – 人人都是产品经理, AI项目跨团队协作:产品技术业务如何不打架 – 人人都是产品经理, Agentic Workflow(智能体工作流):让AI从”答案生成器”变成”数字员工” – 人人都是产品经理, lycium_plusplus 项目全景解读:OpenHarmony 三方库构建的“大管家” – 人人都是产品经理, 从爆单救火到前置履约:两套预采策略,把生鲜大促履约效率拉满 – 人人都是产品经理, 什么时候该补货?我用一轮数据做了一个决定 – 人人都是产品经理, 从“机械兜底”到“动态分流”:AI客服重复进线治理的4大底层逻辑 – 人人都是产品经理, 抖音拼效率,红书拼洞察 – 人人都是产品经理, 全民狂欢与退潮——为什么龙虾这波热潮冷却得如此之快? – 人人都是产品经理, Stripe押注!MPP重塑全球支付 – 人人都是产品经理, 小红书GEO:AI引用你的内容,不是因为你对,而是因为你看起来可信 – 人人都是产品经理, 前百度副总裁押注办公Agent,日韩付费爆发,Manus迎来强劲对手 – 人人都是产品经理,
浅析鸿蒙(ark runtime)执行动态代码
纯爱掌门人 · 2026-01-21 · via 人人都是产品经理

众所周知,鸿蒙next的应用运行在ark runtime下,而ark runtime是驱动着鸿蒙应用的基石。ark runtime支持动态类型和静态类型在内的多种编程语言(目前支持js, ts, arkTs等,与传统js runtime不同的是,ark compiler工具链在编译ts源码时,不会像传统js引擎,先将ts转为js代码,再交给js runtime执行,而是在编译ts源码时,会分析推导类型信息,在运行前即可预生成内联缓存从而加速字节码执行)。详细的代码实现以及官方文档大家可以去这里看:arkcompiler仓库

整体上看,ark runtime仍然是符合Ecmascript规范的js虚拟机实现。既然是js虚拟机实现,那大家一定会想到这样执行远程动态代码下发/热修等场景在鸿蒙上岂不是可以遍地开花,分分钟绕过App Gallary的代码签名/审核随意更新客户端代码!

Eval / new Function

提起使用js动态执行代码,大家第一个想起的一定是eval

Eval作为js标准规范的方法,用于执行一段javascript表达式、声明、脚本并返回代码段执行结果。同时使用Function prototype也能达到相同的效果。

果然没有那么简单,还没有编译Dev Eco Studio的静态检查便提示无法在arkts中使用标准库。 image.png

这可难不倒大家,众所周知(大声宣扬),arkts的严格的静态检查仅适用于ets文件,只要把代码写在ts文件中,就能愉快的使用ts/js的大部分特性了(甚至any,随心所欲的向任意对象中加入/删除字段、方法等)。

说干就干,代码是不报错了,程序也跑起来了,但是在调用时app果断崩溃,调用eval / new Function分别提示:

Error message:not support eval().
Error message:Not support eval. Forbidden using new Function()/Function().
export class InjectUtil {
  static inject(obj: any) {
    eval("1+1")
    InjectUtil.evalByFunc()
    obj.Nav = null
  }

  static evalByFunc() {
    var fn = Function as any
    return fn('console.log(eval!!!!!!!!!!!!!!!!!!!!!!!!!!!!)')();
  }
}

看来arkcompiler在运行时也屏蔽掉了js可以随意动态执行代码的特性。看来直接使用ts的api是无法达到动态执行代码的目的。

查阅官方文档,已经对ark runtime的这一表现作出了解释:

ArkCompiler前端编译工具链将ArkTS/TS/JS程序预先静态编译为方舟字节码,并且还提供了多重混淆能力的增强,有效地提升了开发者代码资产的安全强度。另外出于安全的考虑,ArkCompiler不支持sloppy模式的JS代码,也不支持eval等运行动态字符串的功能。

在查阅了鸿蒙官方文档后,发现其并未完全堵死ark runtime动态代码的执行能力,在官方支持上仍然提供了使用ndk来开发动态js代码执行的能力。

JSVM-API

JSVM-API是鸿蒙中提供的基于标准JS引擎提供的一套稳定ABI,为开发者提供了一套较为完整的JS引擎能力,包括创建和销毁引擎,执行JS代码,JS/C++交互等关键能力。相当于v8 api的精简版。 image.png

这里的js engine在官方文档上并未说明是否是ark runtime,但基于目前ark runtime的开源代码,这里js vm的能力应该还是由ark runtime提供(欢迎勘误)。

受限于JSVM-API提供的能力,我们无法获取到主线程所在的jsvm env(也有可能主线程根本不是jsvm),只能通过jsvm创建一个全新的隔离环境,在这个js环境中,我们可以动态的执行js代码。

使用jsvm执行js脚本的主要流程:

image.png

核心代码

// jsvm提供的接口头文件
#include "ark_runtime/jsvm.h"

JSVM_VM* vm;
JSVM_ENV* env;

// 创建jsvm虚拟机 通过napi调用
static void createArcJsContext() {
  JSVM_Status status;

  // 初始化 可以设置vm启动参数 argv argc
  JSVM_InitOptions init_options;
  memset(&init_options, 0, sizeof(init_options));
  OH_JSVM_Init(&init_options);

  // 虚拟机实例
  // 可以设置gc相关参数、snapshot bin等
  JSVM_CreateVMOptions options;
  memset(&options, 0, sizeof(options));
  status = OH_JSVM_CreateVM(&options, vm);
  // vm scope。在jsvm中scope 即作用域,用于资源管理,在scope打开期间资源可用,scope关闭后自愿释放(RAII)
  // 类似v8中各种scope的设计,在后续使用中,各种scope可以以raii风格封装方便使用
  JSVM_VMScope vm_scope;
  status = OH_JSVM_OpenVMScope(js_vm, &vm_scope);

  // js env
  js_env = new JSVM_Env;
  status = OH_JSVM_CreateEnv(...);
  // env scope
  status = OH_JSVM_OpenEnvScope(...);
}

static napi_value EvalJS(napi_env env, napi_callback_info info) {
  ...省略...
  // 待运行js代码
  std::string scriptStr = napiValueToString(env, args[1]);
  // scope 用于资源管理
  OH_JSVM_OpenHandleScope(...);
  // 转为jsvm字符串
  OH_JSVM_CreateStringUtf8(...);
  // 编译js脚本
  OH_JSVM_CompileScript(...);
  // 运行脚本
  OH_JSVM_RunScript(...);
  // 获取执行结果(省略...)
  ...省略...
}

// 释放先前创建的各种scope 关闭vm napi调用
static void releaseResources() {
  OH_JSVM_CloseEnvScope(...);
  OH_JSVM_DestroyEnv(...);
  OH_JSVM_CloseVMScope(...);
  OH_JSVM_DestroyVM(...);
}
// index.d.ts 导出napi方法定义
export const createJsCore: (fun: Function) => number;
export const releaseJsCore: (a: number) => void;
export const evaluateJs: (a: number, str: string) => string;
// 创建首个运行环境,并绑定TS回调
const coreId = testNapi.createJsCore(MyCallback);

let sourcecodestr = `
          {
          let a = "hello World";
          consoleinfo(a);
          const mPromise = createPromise();
          mPromise.then((result) => {
          assertEqual(result, 0);
          onJSResultCallback(result, "abc", "v");
          });
          a;
          };`;

// 在首个运行环境中执行JS代码
console.log("TEST evalUateJS :   " + testNapi.evalUateJS(coreId, sourcecodestr));

// 释放运行环境
testNapi.releaseJsCore(coreId);

实测js代码片段可以成功运行编译执行,从应用的主线程调用napi创建jsvm,并执行指定的一段js代码,在jsvm中创建的环境也能调用创建vm时传入的回调函数将结果返回主线程/主vm。

可以正常实现动态代码和app主线程代码的双向调用:

主isolate(主线程) -> napi -> 用户isolate(jsvm)

用户isolate(jsvm) -> napi -> 主isolate(主线程)

优点

  • js执行环境与主线程环境隔离,通过napi进行中转通讯,在jsvm环境中执行代码不会影响到主线程代码执行,相对安全。

缺点

  • 需要手动管理jsvm、相关vm env等,使用较为繁琐,应用前需要对js vm api进行封装。
  • 动态执行的js代码不能使用import等,需为完整逻辑代码。
  • 不能调用主vm中中相关对象/api。
  • 未经编译arc compiler编译优化,可能会有性能损失。
  • 需要写大量的binding相关的胶水代码,繁杂的工作量较大。

NAPI

node的napi将v8底层数据结构全部黑盒化,抽象为统一的接口,使得开发者无需再使用v8相关api操作,与v8解耦,使开发者不会遇到由于v8引擎变更或node版本升级而重新开发的风险。

在鸿蒙中也实现了napi相关规范与接口定义,使开发者可以以napi规范来开发鸿蒙应用的native扩展。

napi_run_script

napi_run_script是napi标准规范中执行js代码的函数,依赖于napi,该方法的调用比较简单,直接上运行代码及调试结果

image.png 在鸿蒙中napi_run_script调用可以成功完成,也返回了napi_ok成功状态的返回码,但是实际上代码并没有执行,脚本运行返回值也被置为null。

查阅官方文档,并没有对napi_run_script这个接口做出说明,猜测ark runtime屏蔽了或未实现这个接口。

napi_run_script_path

针对这个接口,鸿蒙官方有给相关说明:napi_run_script_path官方文档。文档中提到可以使用该接口执行abc格式的文件(arkts编译后生成的字节码产物),但没有给出操作流程。摸索了下,鸿蒙sdk中的es2abc工具可以实现这个目标: /Applications/DevEco-Studio.app/Contents/sdk/HarmonyOS-NEXT-DB3/openharmony/ets/build-tools/ets-loader/bin/ark/build-mac/bin/es2abc

用法(注意,使用macos的同学需要将es2abc这个文件拷贝出.app, 否则会因为权限不足的原因拷贝失败):

./es2abc test.js

将生成的test.abc文件拷贝至entry的rawfile中,调用即可执行对应的代码。

napi_run_script_path(env, "/entry/resources/rawfile/test.abc", &result);

附上测试脚本test.ets:

console.log('hello world from dynamic code')
console.log(globalThis)
globalThis.Cornerstone.hello()

image.png 可以发现动态下发的代码可以正常调用到我们在程序运行时向globalThis中注入的Cornerstone对象,说明动态执行的代码与app运行的主线程代码处于同一vm环境。

优点

使用napi执行动态代码,无需手动管理vm虚拟机的生命周期,同时可以复用并调用到主vm环境中已存在的对象,更加灵活友好。

可享受到.abc带来的性能优化。

但同时下发的abc文件也与jsvm的限制一致,无法使用import,需将动态代码中的相关依赖提前注入到vm环境/携带完整逻辑等。

缺点

因为执行环境与app主vm一致,恶意代码可随意破环主vm中相关内存数据。

总结

出于安全考虑鸿蒙(ark runtime)在ts层面对动态执行代码作出了诸多限制,但是我们仍能通过napi / jsvm的方式达到动态执行代码的目的,尤其是napi,可在主vm环境中执行动态代码,并且能享受到方舟编译器所带来的性能优化。

本文作者@纯爱掌门人,未经许可禁止转载。