annidy / notes

0 stars 0 forks source link

NAPI 异步回调 ArkUI #192

Open annidy opened 5 months ago

annidy commented 5 months ago
struct CallbackContext {
    napi_env env = nullptr;
    napi_ref recvCallbackRef = nullptr;
    napi_async_work work;
    double value0 = 0;
    double value1 = 0;
};

void callbackDone(napi_env env, napi_status status, void *data)
{
    CallbackContext* context = (CallbackContext*)data;
    napi_value recvCallback= nullptr;

    napi_get_reference_value(context->env, context->recvCallbackRef, &recvCallback);
    napi_value argv[1];
    //argv[0] = thisArg;
    napi_value ret;

    napi_create_double(env, context->sum, &argv[0]);
    napi_call_function(env, nullptr, recvCallback, 1, argv, &ret);

    napi_delete_reference(context->env, context->recvCallbackRef);
    napi_delete_async_work(context->env, context->work);
    delete context;
}

void callbackPreDo(napi_env env, void *data)
{
    CallbackContext* context = (CallbackContext*)data;
    context->sum = context->value0 + context->value1;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void callbackExec(CallbackContext* context)
{
    napi_value resource;
    napi_create_string_latin1(context->env, "mqttAPI", NAPI_AUTO_LENGTH, &resource);
    napi_create_async_work(context->env, nullptr, resource, callbackPreDo, callbackDone, context, &context->work);
    napi_queue_async_work(context->env, context->work);//实现在UI主线程调用
}

static napi_value AsyncAdd(napi_env env, napi_callback_info info)
{
    size_t requireArgc = 3;
    size_t argc = 3;
    napi_value args[3] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_ref recvCallbackRef;
    napi_create_reference(env, args[2], 1, &recvCallbackRef);

    CallbackContext *context = new CallbackContext;
    context->env = env;
    context->recvCallbackRef = recvCallbackRef;
    context->value0 = value0;
    context->value1 = value1;

    callbackExec(context);

    return nullptr;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "async_add", nullptr, AsyncAdd, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}

index.d.ts

export const async_add: (a: number, b: number, c: (number) => void) => number;

index.ets

import hilog from '@ohos.hilog';
import entry from 'libentry.so'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Button("Async")
          .onClick(() => {
              entry.async_add(3, 4, (value) => {
                hilog.info(0x0000, 'testTag', 'Async 3 + 4 = %{public}d', value);
              })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}
annidy commented 5 months ago

在这里有原始的基于libuv的示例js_callback.cpp 新的napi引入了NativeAsyncWork对象,进一步包装了libuv,增加了cancel、defer等回调