在前 3 小结笔者简单介绍了 NAPI 工程并对生成的源码进行了简单介绍,本节笔者在前 3 小节的基础上对 NAPI 工程做个扩展,再额外添加一个计算 MD5 的方法 md5()。
声明md5方法
在 index.d.ts 文件中声明一个 md5() 方法,该方法接收一个 string 参数,返回类型也是 string 类型,表示经过 MD5 计算后的值,样例代码如下所示:
export const add: (a: number, b: number) => number;
// 声明 md5 方法
export const md5: (value: string) => string;
映射C++方法
在前 3 节的介绍中我们知道,JS 端声明的方法由 C++ 端实现时需要把两端的方法做个映射,因此先在 hello.cpp 的 Init() 方法内设置 md5() 方法为 C++ 的 Md5() 方法,样例代码如下所示:
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
      { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
      // 设置JS的md5()方法的C++实现为Md5()方法,其它参数默认即可
      { "md5", nullptr, Md5, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
实现C++代码
在 Init() 方法中配置了 C++ 的 Md5() 方法后,需要实现 Md5() 方法,样例代码如下所示:
static napi_value Md5(napi_env env, napi_callback_info info) {
    // 1、从info中取出JS传递过来的参数放入args
    size_t argc = 1;
    napi_value args[1] = { nullptr };
    if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) {
        napi_throw_error(env, "-1000", "napi_get_cb_info error");
        return nullptr;
    }
    // 2、获取参数的类型
    napi_valuetype stringType;
    if (napi_ok != napi_typeof(env, args[0], &stringType)) {
        napi_throw_error(env, "-1001", "napi_typeof error");
        return nullptr;
    }
    // 3、如果参数为null,则抛异常
    if (napi_null == stringType) {
        napi_throw_error(env, "-1002", "the param can't be null");
        return nullptr;
    }
    // 4、获取传递的string长度
    size_t length = 0;
    if (napi_ok != napi_get_value_string_utf8(env, args[0], nullptr, 0, &length)) {
        napi_throw_error(env, "-1003", "napi_get_value_string_utf8 error");
        return nullptr;
    }
    // 5、如果传递的是"",则抛异常
    if (length == 0) {
        napi_throw_error(env, "-1004", "the param length invalid");
        return nullptr;
    }
    // 6、读取传递的string参数放入buffer中
    char* buffer = new char[length + 1];
    if (napi_ok != napi_get_value_string_utf8(env, args[0], buffer, length + 1, &length)) {
        delete[] buffer;
        buffer = nullptr;
        napi_throw_error(env, "-1005", "napi_get_value_string_utf8 error");
        return nullptr;
    }
    // 7、模拟MD5加密操作,直接给传递进来的string后追加[NAPI]
    std::string str = buffer;
    str = str + "[NAPI]";
    // 8、把C++数据转成napi_value
    napi_value value = nullptr;
    const char* md5 = str.c_str();
    if (napi_ok != napi_create_string_utf8(env, md5, strlen(md5), &value)) {
        delete[] buffer;
        buffer = nullptr;
        napi_throw_error(env, "-1006", "napi_create_string_utf8 error");
        return nullptr;
    }
    // 9、资源清理
    delete[] buffer;
    buffer = nullptr;
    // 返回 value
    return value;
}
Md5() 方法的解释说明的很清楚:第 1 步从 napi_callback_info 中读取传递进来的参数放入 args 中;第 2 步读取传递的参数类型;第 3 步判断参数类型是否为 null,如果为 null 则抛异常;第 4 步读取参数长度;第 5 步如果传递的参数为 "" 则抛异常;第 6 步根据参数长度把参数读取出来放入 buffer 里,第 7 布模拟 MD5 操作直接在参数末尾追加 [NAPI] 字符串,第 8 步把 C++ 类型转换成 napi_value 类型,第 9 布清理资源,第 10 步返回结果。
📢:读取 string 时先读取参数的长度,再读取内容。
测试C++方法
根据 Md5() 方法的实现,限制条件是不允许数据 null 和 “”,如果输入则抛异常。因此可测试以下三种场景:正常参数,null 参数和 “” 参数,样例代码如下所示:
import testNapi from 'libentry.so'
@Entry @Component struct Index {
  @State message: string = 'Hello,OpenHarmony'
  build() {
    Column({space: 10}) {
      Text(this.message)
        .fontSize(20)
      Button("正常参数")
        .onClick(() => {
          this.message = testNapi.md5("Hello, OpenHarmony")
        })
      Button("null参数")
        .onClick(() => {
          this.message = testNapi.md5(null);
        })
      Button("\"\"参数")
        .onClick(() => {
          this.message = testNapi.md5("");
        })
    }
    .padding(10)
    .width('100%')
    .height("100%")
  }
}
点解 正常参数 按钮,样例运行结果如下所示:

点击 null参数 测试异常情况,异常日志如下:
02-28 23:50:56.176 2093-2093/com.example.oh_0400_napi E C03f00/ArkCompiler: [default] Call:1307 occur exception need return
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: [jsi_base_utils.cpp(ReportJsErrorEvent)-(0)] summaryBody:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Lifetime: 0.000000s
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Js-Engine: ark
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: page: pages/Index.js
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Error message: the param can't be null
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: SourceCode:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: this.message = testNapi.md5(null);
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: ^
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: Stacktrace:
02-28 23:50:56.177 2093-2093/com.example.oh_0400_napi E C03900/Ace: at anonymous (/ets/pages/Index.ets:20:26)
小结
本节笔者在前 3 小节的基础上简单实现了 C++ 端的 md5() 方法并实现 JS 端调用,该 md5() 方法是一个模拟,目的是跑通 JS 到 C++的调用流程,下节笔者将要介绍如何引入三方库实现真正的 MD5 计算。
码牛课堂也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线。大家可以进行参考学习:https://qr21.cn/FV7h05

①全方位,更合理的学习路径:
路线图包括ArkTS基础语法、鸿蒙应用APP开发、鸿蒙能力集APP开发、次开发多端部署开发、物联网开发等九大模块,六大实战项目贯穿始终,由浅入深,层层递进,深入理解鸿蒙开发原理!②多层次,更多的鸿蒙原生应用:
路线图将包含完全基于鸿蒙内核开发的应用,比如一次开发多端部署、自由流转、元服务、端云一体化等,多方位的学习内容让学生能够高效掌握鸿蒙开发,少走弯路,真正理解并应用鸿蒙的核心技术和理念。③实战化,更贴合企业需求的技术点:
学习路线图中的每一个技术点都能够紧贴企业需求,经过多次真实实践,每一个知识点、每一个项目,都是码牛课堂鸿蒙研发团队精心打磨和深度解析的成果,注重对学生的细致教学,每一步都确保学生能够真正理解和掌握。
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
《鸿蒙开发学习手册》:https://qr21.cn/FV7h05
 
如何快速入门:
- 基本概念
- 构建第一个ArkTS应用
- ……

开发基础知识:https://qr21.cn/FV7h05
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……

基于ArkTS 开发:https://qr21.cn/FV7h05
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ……

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

大厂鸿蒙面试题::https://qr18.cn/F781PH
 

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH
 
1.项目开发必备面试题
 2.性能优化方向
 3.架构方向
 4.鸿蒙开发系统底层方向
 5.鸿蒙音视频开发方向
 6.鸿蒙车载开发方向
 7.鸿蒙南向开发方向




















