Node-API(让node附有C++能力)入门保姆级起步教程

1,789 阅读2分钟

简介

插件使用 C++ 编写的动态链接共享对象。 require() 函数可以将插件加载为普通的 Node.js 模块。 插件提供了 JavaScript 和 C/C++ 库之间的接口。

与在此之前主流的ffi,nan,V8,libuv 不一样的是 Node-API 具有超强的兼容性(在node8.0以上) ,可以无需重新编译就能在electron上运行,有优势就必有劣势 由于NAPI与node内部使用的C++函数支持是一致的,因此编写时候便需要使用严格的类型进行编写;

起步

  1. 工欲善其事必先利其器
安装必要的支持
  • Visual Studio
  • 安装node-gyp
npm install -g node-gyp
  • 配置头文件位置包含路径 (不设置也能编译 只是为了让IDE可检查)

image.png

2.创建你的NAPI项目

mkdir helloNapi & cd helloNapi 
npm init -f

3.设置插件编译目标和模块入口文件

  • 创建以下文件
    • binding.gyp
    • index.js
    • mian.cpp (C语言: mian.c , C++: mian.cpp , mian.cc)

image.png

  • binding.gyp 内容
  "targets": [
    {
      "target_name": "helloNapi",
      "conditions": [
        ['OS=="win"', {
          "sources": ["mian.cpp" ],
          'msvs_settings': {
            'VCCLCompilerTool': {
              'AdditionalOptions': [
                '/W3',
                '/Qspectre',
                '/guard:cf'
              ]
            },
            'VCLinkerTool': {
              'AdditionalOptions': [
                '/guard:cf'
              ]
            }
          },
        }]
      ]
    }
  ]
}

  • index.js 内容
module.exports = require("./build/Release/helloNapi.node");
  • mian.cpp
#include <node_api.h>

// 实际暴露的方法,这里只是简单返回一个字符串
napi_value HelloMethod(napi_env env, napi_callback_info info)
{
    napi_value world;
    napi_create_string_utf8(env, "hello world!", 12, &world);
    return world;
}

// 开始暴露模块
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor BIND_NAPI_METHOD[] = {
        {"HelloMethod", 0, HelloMethod , 0, 0, 0, napi_default, 0}
    };

    napi_define_properties(env, exports, sizeof(BIND_NAPI_METHOD) / sizeof(BIND_NAPI_METHOD[0]), BIND_NAPI_METHOD);
    return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init);

编译你的c++模块

node-gyp rebuild
  • 编译命令 image.png

  • 开始编译 image.png

  • 编译成功

image.png

使用你的c++模块

 // 导入模块
 let hello = require("./helloNapi");
 console.log(hello.HelloMethod());

image.png

让代码更好写的模块进阶

  • 导出简化
 //原来 导出函数时候需要使用json提交 重复度过高并不友好
napi_property_descriptor BIND_NAPI_METHOD[] = {
        {"HelloMethod", 0, HelloMethod , 0, 0, 0, napi_default, 0}
};
    
 //优化(使用宏)
 // 导出类型是一个函数
#define DECLARE_NAPI_METHOD(name, func)         \
    {                                           \
        name, 0, func, 0, 0, 0, napi_default, 0 \
     }
     
//暴露方式
napi_property_descriptor BIND_NAPI_METHOD[] = {
       DECLARE_NAPI_METHOD("HelloMethod", HelloMethod),
};
  • 简化 文本转node文本 过程
  1. 添加头声明

#include <string>
#include <stdio.h>
#include <windows.h>

using namespace std;
// 配置 win-api字符自适应 
#ifdef UNICODE
typedef LPWSTR LPTSTR;
typedef LPCWSTR LPCTSTR;
#else
typedef LPSTR LPTSTR;
typedef LPCSTR LPCTSTR;
#endif
  1. 变更文本转node文本函数
/**
 * @brief 将文本变成node支持的utf8文本类型
 *
 * @param env
 * @param SetString
 * @return napi_value
 */
napi_value _create_String(napi_env env, string SetString)
{
    napi_value Results;
    napi_create_string_utf8(env, SetString.c_str(), NAPI_AUTO_LENGTH, &Results);
    return Results;
}

// 原来返回文本编写:

napi_value HelloMethod(napi_env env, napi_callback_info info)
{
    napi_value world;
    napi_create_string_utf8(env, "world", 5, &world);
    return world;
}

// 新的返回方式返回
napi_value HelloMethod(napi_env env, napi_callback_info info)
{
    return _create_String(env,"world");
}
  • 支持中文 文本返回

  • 导出一个文本类型的内容

// 导出类型是一个文本类型
#define ADD_NAPI_METHOD_Str_VALUE(name, value)                        \
    {                                                                 \
        name, 0, 0, 0, 0, _create_String(env, value), napi_default, 0 \
    }

//使用:
// ADD_NAPI_METHOD_Str_VALUE ("version", "helloNapi@1.0.00")
  napi_property_descriptor BIND_NAPI_METHOD[] = {
        ADD_NAPI_METHOD_Str_VALUE("version", "helloNapi@1.0.00"),
        DECLARE_NAPI_METHOD("HelloMethod", HelloMethod),
    };

看看效果

image.png