各位码友们好!今天这篇干货主要聚焦实操细节,希望能帮大家少踩坑。​
要是过程中遇到哪块没看懂、有疑问,或者你有更优的实现思路,评论区尽管聊!发现文档里有疏漏或错误也尽管指出来 ——
技术这东西就得互相挑刺才能越磨越精,咱们一起把这些知识点吃透~

前置学习

声明js接口

  • Native C++样例中,实现了两个数字相加。这篇文章我们来实现两个字符串的相加ConcatenateString: (a: string, b: string) => string;,将字符串a和b拼接成一个字符串。
  • 同时我们还会严格检查参数类型,个数等是否和接口定义一致,不一致时会抛出异常。
  • 通过之前文章的介绍我们了解到,我们要实现的js接口都是放在src/main/cpp/types/libentry/Index.d.ts文件中的。所以我们也将我们拼接字符串的js接口也放到该文件中,如下:
export const add: (a: number, b: number) => number;
export const ConcatenateString: (a: string, b: string) => string;

实现js接口

  • Dev Eco做了非常贴心的功能,当我们添加了接口声明,但是没有接口的Native实现的时候,他会提醒你。此时我们点击Generate native implementation它就会自动在napi_init.cpp文件中添加该接口的实现模板。
    在这里插入图片描述
  • Dev Eco自动帮我们添加了js接口ConcatenateString和c++侧实现NAPI_Global_ConcatenateString的关联。我们只需要添加NAPI_Global_ConcatenateString的实现即可。
    在这里插入图片描述
  • NAPI_Global_ConcatenateString的实现如下,我通过注释对里面的每行代码做了详细的说明。
static napi_value NAPI_Global_ConcatenateString(napi_env env, napi_callback_info info) {
    // 定义变量存储从JS接收的参数
    size_t argc = 2;
    napi_value args[2];
    
    // 获取JS传递的参数
    napi_status status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to get callback info");
        return NULL;
    }
    
    // 检查参数数量是否正确
    if (argc < 2) {
        napi_throw_error(env, NULL, "Expected 2 arguments");
        return NULL;
    }
    
    // 检查第一个参数是否为字符串
    napi_valuetype type;
    status = napi_typeof(env, args[0], &type);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to check type of first argument");
        return NULL;
    }
    if (type != napi_string) {
        napi_throw_error(env, NULL, "First argument must be a string");
        return NULL;
    }
    
    // 检查第二个参数是否为字符串
    status = napi_typeof(env, args[1], &type);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to check type of second argument");
        return NULL;
    }
    if (type != napi_string) {
        napi_throw_error(env, NULL, "Second argument must be a string");
        return NULL;
    }
    
    // 获取第一个字符串的长度
    size_t len1;
    status = napi_get_value_string_utf8(env, args[0], NULL, 0, &len1);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to get length of first string");
        return NULL;
    }
    
    // 分配内存并获取第一个字符串内容
    char* str1 = (char*)malloc(len1 + 1);
    if (str1 == NULL) {
        napi_throw_error(env, NULL, "Failed to allocate memory for first string");
        return NULL;
    }
    status = napi_get_value_string_utf8(env, args[0], str1, len1 + 1, NULL);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to get first string value");
        free(str1);
        return NULL;
    }
    
    // 获取第二个字符串的长度
    size_t len2;
    status = napi_get_value_string_utf8(env, args[1], NULL, 0, &len2);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to get length of second string");
        free(str1);
        return NULL;
    }
    
    // 分配内存并获取第二个字符串内容
    char* str2 = (char*)malloc(len2 + 1);
    if (str2 == NULL) {
        napi_throw_error(env, NULL, "Failed to allocate memory for second string");
        free(str1);
        return NULL;
    }
    status = napi_get_value_string_utf8(env, args[1], str2, len2 + 1, NULL);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to get second string value");
        free(str1);
        free(str2);
        return NULL;
    }
    
    // 分配内存存储拼接后的字符串
    char* result = (char*)malloc(len1 + len2 + 1);
    if (result == NULL) {
        napi_throw_error(env, NULL, "Failed to allocate memory for result string");
        free(str1);
        free(str2);
        return NULL;
    }
    
    // 执行字符串拼接
    strcpy(result, str1);
    strcat(result, str2);
    
    // 释放临时字符串的内存
    free(str1);
    free(str2);
    
    // 创建JS字符串并返回
    napi_value return_value;
    status = napi_create_string_utf8(env, result, len1 + len2, &return_value);
    free(result); // 释放结果字符串的内存
    
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to create return string");
        return NULL;
    }
    
    return return_value;
}

验证js接口

  • 我们将上面实现的js接口添加到src/main/ets/pages/Index.ets文件中来验证其功能是否正常。
  • onClick回调中添加如下代码:
hilog.info(DOMAIN, 'testTag', 'Test NAPI aaa + bbb = %{public}s', testNapi.ConcatenateString("aaa", "bbb"));
  • 编译,安装应用,点击Hello World,在log界面我们可以看到如下打印,说明接口功能正常:
    在这里插入图片描述

总结

  • 到这里我们已经初步掌握了napi的用法,想要更深层次了解napi,大家可以参考华为官方文档,写的非常详细:使用Node-API实现跨语言交互

参考文档

Node.js v24.7.0 documentation

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐