• node-addon-api


    hello world

    #include <napi.h>
    
    using namespace Napi;
    
    String Method(const CallbackInfo& info) {
      Env env = info.Env();
      return String::New(env, "world"); // 返回数据
    }
    
    Object Init(Env env, Object exports) {
      // 导出
      exports.Set(String::New(env, "hello"), Function::New(env, Method));
      return exports;
    }
    
    NODE_API_MODULE(hello, Init)
    
    const addon = require("./build/Release/addon");
    console.log( addon.hello() );
    

    args

    info.Length()
    
    info[0].IsNumber()
    
    double arg0 = info[0].As<Napi::Number>().DoubleValue();
    
    std::string str = info[0].ToString().Utf8Value();
    
    // 和js一样模糊判断
    Boolean b = opt.Get("b").ToBoolean();
    if(b)...
    
    env.Null();
    env.Undefined();
    Napi::Boolean::New(env, true);
    

    callback

      Napi::Function cb = info[0].As<Napi::Function>();
      cb.Call(env.Global(), { Napi::String::New(env, "hello world") });
    

    return function

    String MyFunction(const CallbackInfo& info) {
      Env env = info.Env();
      return String::New(env, "hello world");
    }
    
    Function CreateFunction(const CallbackInfo& info) {
      Env env = info.Env();
      Function fn = Function::New(env, MyFunction, "funName");
      return fn;
    }
    

    Wrap 获取传入的c++类

    MyObject* obj1 = Napi::ObjectWrap<MyObject>::Unwrap( info[0].As<Napi::Object>() );
    

    接收arraybuffer

    #include <napi.h>
    
    using namespace Napi;
    
     Napi::Value a(const Napi::CallbackInfo& info) {
      Napi::ArrayBuffer buf = info[0].As<Napi::ArrayBuffer>();
      uint32_t* n = (uint32_t*)buf.Data();
      printf("%d
    ", *n); // 10
      return info.Env().Undefined();
    }
    
    Napi::Object Init(Napi::Env env, Napi::Object exports) {
      exports["a"] = Napi::Function::New(env, a);
      return exports;
    }
    
    NODE_API_MODULE(hello, Init)
    
    const array = new Uint8Array([0x0A, 0, 0, 0]);
    addon.a(array.buffer)
    

    返回array_buffer

    let r = addon.test()
    console.log(r); // ArrayBuffer { [Uint8Contents]: <0a 00 00 00>, byteLength: 4 }
    console.log( new Uint8Array(r)[0] ); // 10
    
      Env env = info.Env();
      DWORD a = 10;
      auto buf = ArrayBuffer::New(env, 4);
      memcpy_s((void *)buf.Data(), 4, &a, 4);
      return buf;
    

    接收 TypedArray

    let r = addon.test(new Uint8Array([0x0A, 0]));
    console.log(r); // 1
    
    Value test(const CallbackInfo &info)
    {
      auto env = info.Env();
      auto ta = info[0].As<TypedArray>();
      auto buf = ta.Get("buffer").As<ArrayBuffer>();
      return Number::From(env, *(WORD*)buf.Data());
    }
    

    接收 async function

    nw.test(async function () {
      return 100;
    });
    
    Napi::Value test(const Napi::CallbackInfo &info)
    {
      Napi::Env env = info.Env();
    
      auto promise = info[0].As<Napi::Function>().Call({}).As<Napi::Promise>();
      auto thenFunc = promise.Get("then").As<Napi::Function>();
      auto v = thenFunc.Call(promise, {Napi::Function::New(env, [](const Napi::CallbackInfo &info)
                                                           { printf("%d
    ", info[0].ToNumber().Int32Value()); /* 100 */ })});
      return env.Undefined();
    }
    

    event

    Napi::Value a(const Napi::CallbackInfo& info) {
      Napi::Env env = info.Env();
      Napi::Function emit = info[0].As<Napi::Function>();
      emit.Call({ Napi::String::New(env, "start") });
      emit.Call({ Napi::String::New(env, "data"), Napi::Number::New(env, 1) });
      emit.Call({ Napi::String::New(env, "end") });
      emit.Call({ Napi::String::New(env, "ok") });
    }
    
    const EventEmitter = require("events").EventEmitter;
    const emitter = new EventEmitter();
    emitter.on("start", () => {
      console.log("### START ...");
    });
    emitter.on("data", (evt) => {
      console.log(evt);
    });
    emitter.on("end", () => {
      console.log("### END ###");
    });
    
    addon.a(emitter.emit.bind(emitter));
    

    保存callback函数不被垃圾回收

    #include <napi.h>
    
    class NativeAddon : public Napi::ObjectWrap<NativeAddon> {
    public:
      static Napi::Object Init(Napi::Env env, Napi::Object exports)
      {
        Napi::Function func =
          DefineClass(env,
            "NativeAddon",
            { InstanceMethod("tryCallByStoredReference",
                            &NativeAddon::TryCallByStoredReference),
             InstanceMethod("tryCallByStoredFunction",
                            &NativeAddon::TryCallByStoredFunction) });
    
        constructor = Napi::Persistent(func);
        constructor.SuppressDestruct();
    
        exports.Set("NativeAddon", func);
        return exports;
      }
    
      NativeAddon(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NativeAddon>(info) {
        jsFnRef = Napi::Persistent(info[0].As<Napi::Function>()); // use Persistent
        jsFn = info[1].As<Napi::Function>();
      }
    
    private:
      static Napi::FunctionReference constructor;
      Napi::FunctionReference jsFnRef;
      Napi::Function jsFn;
    
      void TryCallByStoredReference(const Napi::CallbackInfo& info)
      {
        // Napi::Env env = info.Env();
        jsFnRef.Call({});
      }
      void TryCallByStoredFunction(const Napi::CallbackInfo& info)
      {
        // Napi::Env env = info.Env();
        jsFn.Call({});
      }
    };
    Napi::FunctionReference NativeAddon::constructor;
    Napi::Object Init(Napi::Env env, Napi::Object exports) {
      NativeAddon::Init(env, exports);
      return exports;
    }
    NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
    
    const { NativeAddon } = require("./build/Release/addon");
    
    const addon = new NativeAddon(
      function () {
        console.log("JSFnRef");
      },
      function JSFn() {
        console.log("JSFn");
      }
    );
    
    addon.tryCallByStoredReference(); // ok
    addon.tryCallByStoredFunction(); // err
    

    继承 EventEmitter

    #include <napi.h>
    
    class NativeEmitter : public Napi::ObjectWrap<NativeEmitter> {
    public:
      static Napi::Object Init(Napi::Env env, Napi::Object exports)
      {
        Napi::Function func =
          DefineClass(env,
            "NativeEmitter",
            { InstanceMethod("callAndEmit",
                            &NativeEmitter::CallAndEmit) });
    
        constructor = Napi::Persistent(func);
        constructor.SuppressDestruct();
    
        exports.Set("NativeEmitter", func);
        return exports;
      }
      NativeEmitter(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NativeEmitter>(info) {}
    
    private:
      static Napi::FunctionReference constructor;
    
      Napi::Value CallAndEmit(const Napi::CallbackInfo& info)
      {
        Napi::Env env = info.Env();
        Napi::Function emit =
          info.This().As<Napi::Object>().Get("emit").As<Napi::Function>();
        emit.Call(info.This(), { Napi::String::New(env, "start") });
        for (int i = 0; i < 3; i++) {
          std::this_thread::sleep_for(std::chrono::seconds(1));
          emit.Call(
            info.This(),
            { Napi::String::New(env, "data"), Napi::String::New(env, "data ...") });
        }
        emit.Call(info.This(), { Napi::String::New(env, "end") });
        return Napi::String::New(env, "OK");
      }
    };
    Napi::FunctionReference NativeEmitter::constructor;
    
    Napi::Object Init(Napi::Env env, Napi::Object exports) {
      NativeEmitter::Init(env, exports);
      return exports;
    }
    
    NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
    
    const { NativeEmitter } = require("./build/Release/addon");
    const EventEmitter = require("events").EventEmitter;
    
    const inherits = require("util").inherits;
    inherits(NativeEmitter, EventEmitter);
    
    const emitter = new NativeEmitter();
    
    emitter.on("start", () => {
      console.log("### START ...");
    });
    
    emitter.on("data", (evt) => {
      console.log(evt);
    });
    
    emitter.on("end", () => {
      console.log("### END ###");
    });
    
    emitter.callAndEmit();
    

    c++ 返回 promise

    Value a(const CallbackInfo& info)
    {
      Env env = info.Env();
      auto re = Promise::Deferred::New(env);
      re.Resolve(String::New(env, "str"));
      return re.Promise();
    }
    
    addon.a().then((e) => {
      console.log(e); // str
    });
    

    主线程同步回调

    struct TsfnContext
    {
      TsfnContext(Napi::Env env, const Napi::CallbackInfo &info) : env_(env), cb(Persistent(info[0].As<Function>())){};
      FunctionReference cb;
      Napi::Env env_;
    };
    
    uintptr_t WINAPI threadEntry(void *hwnd, TsfnContext *context)
    {
      return context->cb.Call({Number::New(context->env_, (uintptr_t)hwnd)}).ToNumber().Int64Value();
    }
    
    Napi::Value CreateTSFN(const Napi::CallbackInfo &info)
    {
      Napi::Env env = info.Env();
      auto testData = new TsfnContext(env, info);
      BOOL r = EnumWindows((WNDENUMPROC)threadEntry, (LPARAM)testData);
      return Number::New(env, r);
    }
    
    let r = addon.createTSFN((data) => {
      return false;
    });
    

    对象包装

    类属性和描述符

    在子线程中调用jscallback

    addon.test(() => {
      console.log("ok"); // ok 10
    });
    
    struct TsfnContext
    {
      TsfnContext(const CallbackInfo &info, Napi::Env env){};
      Napi::ThreadSafeFunction tsfn;
      HANDLE hThread;
    };
    
    void mythread(TsfnContext*context)
    {
      auto callback = [](Napi::Env env, Napi::Function jsCallback, void *data) {
        jsCallback.Call({Number::New(env, (int)data)});
      };
      napi_status status = context->tsfn.BlockingCall((void *)10, callback);
      if (status != napi_ok)
        Napi::Error::Fatal("ThreadEntry", "err.");
      context->tsfn.Release();
    }
    
    void FinalizerCallback(Napi::Env env, void *finalizeData, TsfnContext*context)
    {
      CloseHandle(context->hThread);
      delete context;
    }
    
    void test(const CallbackInfo &info)
    {
      Napi::Env env = info.Env();
      auto testData = new TsfnContext(info, env);
      testData->tsfn = Napi::ThreadSafeFunction::New(
          env,                          // Environment
          info[0].As<Napi::Function>(), // JS function from caller
          "name",                       // Resource name
          0,                            // Max queue size (0 = unlimited).
          1,                            // Initial thread count
          testData,                     // Context,
          FinalizerCallback,            // Finalizer
          (void *)nullptr               // Finalizer data
      );
      testData->hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)mythread, testData, 0, 0);
    }
    

    获取global对象

      napi_value g;
      napi_get_global(env, &g);
      auto global = Object(env, g);
      auto str = global.Get("name").ToString().Utf8Value();
      printf("str: %s
    ", str.c_str()); // str: ajanuw
    
    name = "ajanuw";
    addon.test();
    

    运行js字符串

    globalThis.num = 1;
    console.log(nw.test());
    console.log(globalThis.num); // 2
    
      Napi::String jsStr = Napi::String::New(env, "num++");
      napi_value result;
      napi_run_script(env, jsStr, &result);
      return Napi::Value::From(env, result);
    

    可以这样运行函数

    globalThis.xx = () => {
      return 233;
    }
    console.log(nw.test()); // 233
    
    Napi::String jsStr = Napi::String::New(env, "xx()");
    

    使用eval

    globalThis.num = 1;
    console.log(nw.test());
    console.log(globalThis.num); // 2
    
      auto eval = env.Global().Get("eval").As<Napi::Function>();
      return eval.Call(env.Global(), {Napi::String::New(env, "num++")});
    
  • 相关阅读:
    Linux08:帮助与常用快捷键
    Android : 跟我学Binder --- (5) C++实现
    Linux应用调试 :使用gdb和gdbserver进行远程调试
    Mosquitto-1.5在Linux上的安装以及Android客户端的实现
    MySQL-8.0.15在Win10和Ubuntu上安装&使用
    Android : 跟我学Binder --- (4) 驱动情景分析
    Android : Android Studio 更新至gradle 4.10.1后Variants API变化
    Android : 跟我学Binder --- (3) C程序示例
    Android : 关于HTTPS、TLS/SSL认证以及客户端证书导入方法
    Android : 跟我学Binder --- (2) AIDL分析及手动实现
  • 原文地址:https://www.cnblogs.com/ajanuw/p/14404060.html
Copyright © 2020-2023  润新知