当前位置: 首页 > news >正文

鸿蒙HarmonyOS应用开发之Node-API开发规范

当传入napi_get_cb_info的argv不为nullptr时,argv的长度必须大于等于传入argc声明的大小。

当argv不为nullptr时,napi_get_cb_info会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量,该接口仅会将声明的argc数量的参数写入argv;而当argc大于实际参数数量时,该接口会在argv的尾部填充undefined。

错误示例

static napi_value IncorrectDemo1(napi_env env, napi_callbackk_info info) {// argc 未正确的初始化,其值为不确定的随机值,导致 argv 的长度可能小于 argc 声明的数量,数据越界。size_t argc;napi_value argv[10] = {nullptr};napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);return nullptr;
}static napi_value IncorrectDemo2(napi_env env, napi_callback_info info) {// argc 声明的数量大与 argv 实际初始化的长度,导致 napi_get_cb_info 接口在写入 argv 时数据越界。size_t argc = 5;napi_value argv[3] = {nullptr};napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);return nullptr;
}

正确示例

static napi_value GetArgvDemo1(napi_env env, napi_callback_info info) {size_t argc = 0;// argv 传入 nullptr 来获取传入参数真实数量napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);// JS 传入参数为0,不执行后续逻辑if (argc == 0) {return nullptr;}// 创建数组用以获取JS传入的参数napi_value* argv = new napi_value[argc]; napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);// 业务代码// ... ...// argv 为 new 创建的对象,在使用完成后手动释放delete argv;return nullptr;
}static napi_value GetArgvDemo2(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value* argv[2] = {nullptr}; // napi_get_cb_info 会向 argv 中写入 argc 个 JS 传入参数或 undefinednapi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);// 业务代码// ... ...return nullptr;
}

生命周期管理

【规则】 合理使用napi_open_handle_scope和napi_close_handle_scope管理napi_value的生命周期,做到生命周期最小化,避免发生内存泄漏问题。

每个napi_value属于特定的HandleScope,HandleScope通过napi_open_handle_scope和napi_close_handle_scope来建立和关闭,HandleScope关闭后,所属的napi_value就会自动释放。

正确示例

// 在for循环中频繁调用napi接口创建js对象时,要加handle_scope及时释放不再使用的资源。 
// 下面例子中,每次循环结束局部变量res的生命周期已结束,因此加scope及时释放其持有的js对象,防止内存泄漏
for (int i = 0; i < 100000; i++) { napi_handle_scope scope = nullptr;   napi_open_handle_scope(env, &scope); if (scope == nullptr) { return; } napi_value res; napi_create_object(env, &res); napi_close_handle_scope(env, scope); 
}

上下文敏感

【规则】 多引擎实例场景下,禁止通过Node-API跨引擎实例访问JS对象。

引擎实例是一个独立运行环境,JS对象创建访问等操作必须在同一个引擎实例中进行。若在不同引擎实例中操作同一个对象,可能会引发程序崩溃。引擎实例在接口中体现为napi_env。

错误示例

// 线程1执行,在env1创建string对象,值为"bar"、 
napi_create_string_utf8(env1, "bar", NAPI_AUTO_LENGTH, &string);
// 线程2执行,在env2创建object对象,并将上述的string对象设置到object对象中
napi_status status = napi_create_object(env2, &object); 
if (status != napi_ok) { napi_throw_error(env, ...); return; 
} status = napi_set_named_property(env2, object, "foo", string); 
if (status != napi_ok) { napi_throw_error(env, ...); return; 
}

所有的JS对象都隶属于具体的某一napi_env,不可将env1的对象,设置到env2中的对象中。在env2中一旦访问到env1的对象,程序可能会发生崩溃。

异常处理

【建议】 Node-API接口调用发生异常需要及时处理,不能遗漏异常到后续逻辑,否则程序可能发生不可预期行为。

正确示例

// 1.创建对象
napi_status status = napi_create_object(env, &object); 
if (status != napi_ok) { napi_throw_error(env, ...); return;
} 
// 2.创建属性值 
status = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string); 
if (status != napi_ok) { napi_throw_error(env, ...); return; 
} 
// 3.将步骤2的结果设置为对象object属性foo的值 
status = napi_set_named_property(env, object, "foo", string); 
if (status != napi_ok) { napi_throw_error(env, ...); return; 
}

如上示例中,步骤1或者步骤2出现异常时,步骤3都不会正常进行。只有当方法的返回值是napi_ok时,才能保持继续正常运行;否则后续流程可能会出现不可预期的行为。

异步任务

【规则】 当使用uv_queue_work方法将任务抛到JS线程上面执行的时候,对JS线程的回调方法,一般情况下需要加上napi_handle_scope来管理回调方法创建的napi_value的生命周期。

使用uv_queue_work方法,不会走Node-API框架,此时需要开发者自己合理使用napi_handle_scope来管理napi_value的生命周期。

正确示例

void callbackTest(CallbackContext* context) 
{ uv_loop_s* loop = nullptr; napi_get_uv_event_loop(context->env, &loop); uv_work_t* work = new uv_work_t; context->retData = 1; work->data = (void*)context; uv_queue_work( loop, work, [](uv_work_t* work) {}, // using callback function back to JS thread [](uv_work_t* work, int status) { CallbackContext* context = (CallbackContext*)work->data; napi_handle_scope scope = nullptr; napi_open_handle_scope(context->env, &scope); if (scope == nullptr) { return; } napi_value callback = nullptr; napi_get_reference_value(context->env, context->callbackRef, &callback); napi_value retArg; napi_create_int32(context->env, context->retData, &retArg); napi_value ret; napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret); napi_delete_reference(context->env, context->callbackRef); napi_close_handle_scope(context->env, scope); if (work != nullptr) { delete work; } delete context; } ); 
}

对象绑定

【规则】 使用napi_wrap接口,如果最后一个参数result传递不为nullptr,需要开发者在合适的时机调用napi_remove_wrap函数主动删除创建的napi_ref。

napi_wrap接口定义如下:

napi_wrap(napi_env env, napi_value js_object, void* native_object, napi_finalize finalize_cb, void* finalize_hint, napi_ref* result)

当最后一个参数result不为空时,框架会创建一个napi_ref对象,指向js_object。此时开发者需要自己管理js_object的生命周期,即需要在合适的时机调用napi_remove_wrap删除napi_ref,这样GC才能正常释放js_object,从而触发绑定C++对象native_object的析构函数finalize_cb。

一般情况下,根据业务情况最后一个参数result可以直接传递为nullptr。

正确示例

// 用法1:napi_wrap不需要接收创建的napi_ref,最后一个参数传递nullptr,创建的napi_ref是弱引用,由系统管理,不需要用户手动释放 
napi_wrap(env, jsobject, nativeObject, cb, nullptr, nullptr); // 用法2:napi_wrap需要接收创建的napi_ref,最后一个参数不为nullptr,返回的napi_ref是强引用,需要用户手动释放,否则会内存泄漏 
napi_ref result; 
napi_wrap(env, jsobject, nativeObject, cb, nullptr, &result); 
// 当js_object和result后续不再使用时,及时调用napi_remove_wrap释放result 
napi_value result1; 
napi_remove_wrap(env, jsobject, result1);

高性能数组

【建议】 存储值类型数据时,使用ArrayBuffer代替JSArray来提高应用性能。

使用JSArray作为容器储存数据,支持几乎所有的JS数据类型。

使用napi_set_element方法对JSArray存储值类型数据(如int32)时,同样会涉及到与运行时的交互,造成不必要的开销。

ArrayBuffer进行增改是直接对缓冲区进行更改,具有远优于使用napi_set_element操作JSArray的性能表现。

因此此种场景下,更推荐使用napi_create_arraybuffer接口创建的ArrayBuffer对象。

示例:

// 以下代码使用常规JSArray作为容器,但其仅存储int32类型数据。
// 但因为是JS对象,因此只能使用napi方法对其进行增改,性能较低。
static napi_value ArrayDemo(napi_env env, napi_callback_info info)
{constexpr size_t arrSize = 1000;napi_value jsArr = nullptr;napi_create_array(env, &jsArr);for (int i = 0; i < arrSize; i++) {napi_value arrValue = nullptr;napi_create_int32(env, i, &arrValue);// 常规JSArray使用napi方法对array进行读写,性能较差。napi_set_element(env, jsArr, i, arrValue);}return jsArr;
}// 推荐写法:
// 同样以int32类型数据为例,但以下代码使用ArrayBuffer作为容器。
// 因此可以使用C/C++的方法直接对缓冲区进行增改。
static napi_value ArrayBufferDemo(napi_env env, napi_callback_info info)
{constexpr size_t arrSize = 1000;napi_value arrBuffer = nullptr;void* data = nullptr;napi_create_arraybuffer(env, arrSize * sizeof(int32_t), &data, &arrBuffer);int32_t* i32Buffer = reinterpret_cast<int32_t*>(data);for (int i = 0; i < arrSize; i++) {// arrayBuffer直接对缓冲区进行修改,跳过运行时,// 与操作原生C/C++对象性能相当i32Buffer[i] = i;}return arrBuffer;
}

napi_create_arraybuffer等同于JS代码中的new ArrayBuffer(size),其生成的对象不可直接在TS/JS中进行读取,需要将其包装为TyppedArray或DataView后方可进行读写。

基准性能测试结果如下:

说明: 以下数据为千次循环写入累计数据,为更好的体现出差异,已对设备核心频率进行限制。

容器类型Benchmark数据(us)
JSArray1566.174
ArrayBuffer3.609

数据转换

【建议】 尽可能的减少数据转换次数,避免不必要的复制。

  • 减少数据转换次数: 频繁的数据转换可能会导致性能下降,可以通过批量处理数据或者使用更高效的数据结构来优化性能;
  • 避免不必要的数据复制: 在进行数据转换时,可以使用Node-API提供的接口来直接访问原始数据,而不是创建新的副本;
  • 使用缓存: 如果某些数据在多次转换中都会被使用到,可以考虑使用缓存来避免重复的数据转换。缓存可以减少不必要的计算,提高性能。

其它

【规则】 使用napi_get_arraybuffer_info接口,第三个参数data资源开发者不允许释放,data的生命周期受引擎管理。

napi_get_arraybuffer_info接口定义如下:

napi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, void** data, size_t* byte_length)

data获取的是ArrayBuffer的Buffer头指针,开发者只可以在范围内读写该Buffer区域,不可以进行释放操作。该段内存由引擎内部的ArrayBuffer Allocator管理,随JS对象ArrayBuffer的生命周期释放。

错误示例:

void* arrayBufferPtr = nullptr;
napi_value arrayBuffer = nullptr;
size_t createBufferSize = ARRAY_BUFFER_SIZE;
napi_status verification = napi_create_arraybuffer(env, createBufferSize, &arrayBufferPtr, &arrayBuffer);
size_t arrayBufferSize;
napi_status result = napi_get_arraybuffer_info(env, arrayBuffer, &arrayBufferPtr, &arrayBufferSize);
delete arrayBufferPtr; // 这一步是禁止的,创建的arrayBufferPtr生命周期由引擎管理,不允许用户自己delete,否则会double free

【建议】 合理使用napi_object_freeze和napi_object_seal来控制对象以及对象属性的可变性。

napi_object_freeze等同于Object.freeze语义,freeze后对象的所有属性都不可能以任何方式被修改;napi_object_seal等同于Object.seal语义,对象不可增删属性。两者的主要区别是,freeze不能改属性的值,seal还可以改属性的值。

开发者使用以上语义时,需确保约束条件是自己需要的,一旦违背以上语义严格模式下就会抛出Error(默认严格模式)。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

相关文章:

鸿蒙HarmonyOS应用开发之Node-API开发规范

当传入napi_get_cb_info的argv不为nullptr时&#xff0c;argv的长度必须大于等于传入argc声明的大小。 当argv不为nullptr时&#xff0c;napi_get_cb_info会根据argc声明的数量将JS实际传入的参数写入argv。如果argc小于等于实际JS传入参数的数量&#xff0c;该接口仅会将声明…...

单例模式

文章目录 单例模式特殊类的设计单例模式饿汉模式懒汉模式懒汉VS饿汉懒汉的线程安全单例对象的释放 单例模式 认识单例模式之前先认识一下几种常见的特殊类的设计。 特殊类的设计 设计一个类 只能再堆上创建对象 只能再堆上创建&#xff0c;则通过new来创建对象。 将类的构造函…...

Android OpenMAX - 开篇

Android Media是一块非常庞大的内容&#xff0c;上到APP的书写&#xff0c;中到播放器的实现、封装格式的了解&#xff0c;下到OMX IL层的实现、Decoder的封装&#xff0c;每一块都需要我们下很大的功夫学习。除此之外&#xff0c;我们还要对一些相关的模块进行了解&#xff0c…...

ubuntu开启ssh服务

1.安装openssh-server sudo apt-get install openssh-server 2.开启服务 sudo servive ssh start 3.设置开机自启动 sudo systemctl enable ssh 4.检查是否开启成功 ps -ef | grep ssh 如使用xshell等连接时失败&#xff0c;可以尝试关闭防火墙&#xff1a; sudo sys…...

测试缺陷定位的基本方法

前后端bug特征 后端&#xff1a; 业务逻辑问题&#xff1a;如任务状态未扭转成功&#xff0c;创建任务失败等数据类问题&#xff1a;如新增的任务在页面没有展示出来等性能类问题&#xff1a;提交任务一直显示创建中、批量操作等待耗时长超时等 前端&#xff1a; 页面显示类…...

【数字图像处理matlab系列】数组索引

【数字图像处理matlab系列】数组索引 【先赞后看养成习惯】【求点赞+关注+收藏】 MATLAB 支持大量功能强大的索引方案,这些索引方案不仅简化了数组操作,而且提高了程序的运行效率。 1. 向量索引 维数为1xN的数组称为行向量。行向量中元素的存取是使用一维索引进行的。因此…...

【2024系统架构设计】案例分析- 3 数据库

目录 一 基础知识 二 真题 一 基础知识 1 ORM ORM(Object—Relationl Mapping...

vue基础——java程序员版(总集)

前言&#xff1a; ​ 这是一个java程序员的vue学习记录。 ​ vue是前端的主流框架&#xff0c;按照如今的就业形式作为后端开发的java程序员也是要有所了解的&#xff0c;下面是本人的vue学习记录&#xff0c;包括vue2的基本使用以及引入element-ui&#xff0c;使用的开发工具…...

Rancher(v2.6.3)——Rancher配置Harbor镜像仓库

Rancher配置Harbor镜像仓库详细说明文档&#xff1a;https://gitee.com/WilliamWangmy/snail-knowledge/blob/master/Rancher/Rancher%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3.md#8rancher%E9%85%8D%E7%BD%AEharbor ps&#xff1a;如果觉得作者写的还行&#xff0c;能够满足您的需…...

C++类和对象、面向对象编程 (OOP)

文章目录 一、封装1.抽象、封装2.类和对象(0)学习视频(1)类的构成(2)三种访问权限(3)struct和class的区别(4)私有的成员变量、共有的成员函数(5)类内可以直接访问私有成员&#xff0c;不需要经过对象 二、继承三、多态1.概念2.多态的满足条件3.多态的使用条件4.多态原理剖析5.纯…...

Introduction to Data Mining 数据挖掘

Why Data Mining? • The Explosive Growth of Data: from terabytes to petabytes — Data collection and data availability ◦ Automated data collection tools, database systems, Web, computerized society — Major sources of abundant data ◦ Business: Web, e-co…...

常用的 Git 命令

初始化一个新的仓库&#xff1a; git init 克隆一个仓库&#xff1a; git clone <仓库地址> 查看文件状态&#xff1a; git status 添加文件到暂存区&#xff1a; git add <文件名> 提交文件到仓库&#xff1a; git commit -m "提交说明" 查看提交历…...

jackson:JSON字符串(String)类型的成员序列化和反序列化

对于如下类型定义TestTaskInfo&#xff0c;props字段为JSON字符串(这在数据库经常用到),可以自由保存各种类型的数据 Data public class TestTaskInfo {private String id;private String props;public TestTaskInfo() {}public TestTaskInfo(String id, String props) {super…...

使用docker的好处???(docker的优势)

标准化环境&#xff1a; Docker通过容器技术封装应用程序及其依赖&#xff08;如库、配置文件、运行时环境等&#xff09;&#xff0c;确保应用程序在任何环境中都能以一致的方式运行。这种标准化消除了“在我机器上能运行”的问题&#xff0c;因为容器化应用能在开发、测试、生…...

Google AI 肺癌筛查的计算机辅助诊断

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

【字符串算法题记录】反转字符串中的单词(leetcode),右旋字符串(kama)——双指针以及反转的奇思妙用

反转字符串中的单词 题目链接 思考 这题的思路顺序是&#xff1a;移除多余空格&#xff08;双指针法&#xff09;——》反转整个字符串&#xff09;——》反转字符串中每个单词。 移除多余空格&#xff08;双指针法&#xff09; 因为字符串开头也可能有多个字符&#xff0…...

基于springboot+vue调用百度ai实现车牌号识别功能

百度车牌号识别官方文档 结果视频演示 后端代码 private String getCarNumber(String imagePath, int count) {// 请求urlString url "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate";try {byte[] imgData FileUtil.readFileByBytes(imagePath);Stri…...

【NTN 卫星通信】 TN和多NTN配合的应用场景

1 场景描述 此场景描述了农村环境&#xff0c;其中MNO (运营商TerrA)仅在城市附近提供本地地面覆盖&#xff0c;而MNO (SatA)提供广泛的NTN覆盖。SatA使用GSO轨道和NGSO轨道上的卫星。SatA与TerrA有漫游协议&#xff0c;允许:   所有TerrA用户的连接&#xff0c;当这些用户不…...

健康餐饮必备!油烟净化器超强洁净餐饮环境

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 ​在如今注重健康生活的时代&#xff0c;餐饮业不仅需要美味佳肴&#xff0c;更需要一个清洁、舒适的用餐环境。油烟净化器作…...

Redis修改开源协议,6大备胎重见天日

背景&#xff1a;Redis2018年以来修改了多次开源协议&#xff0c;以前是把一些高级功能收费&#xff0c;这次彻底怒了&#xff0c;把核心代码的协议修改为RSALv2和SSPL双重协议&#xff0c;这个修改对普通用户不受影响&#xff0c;是向所有云厂商开炮&#xff0c;以后云厂商将不…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...