NAPI Data Type Convresion Overview
OpenHarmony NAPI encapsulates ECMAScript standard data types including Boolean, Null, Undefined, Number, BigInt, String, Symbol, Object, and Function into the unified napi_value type. This type handles data exchange between ArkUI applications and native code.
This implementation demonstrates a synchronous Add(num1, num2) interface to illustrate the conversion process.
C++ Implementation
#include <string.h>
#include "napi/native_node_api.h"
#include "napi/native_api.h"
static napi_value ComputeSum(napi_env env, napi_callback_info info) {
size_t expectedArgs = 2;
size_t actualArgs = 2;
napi_value parameters[2] = {nullptr};
napi_status status = napi_get_cb_info(env, info, &actualArgs, parameters, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype paramType1;
napi_valuetype paramType2;
napi_typeof(env, parameters[0], ¶mType1);
napi_typeof(env, parameters[1], ¶mType2);
if (paramType1 != napi_number || paramType2 != napi_number) {
napi_throw_type_error(env, nullptr, "Invalid arguments. Expected 2 numbers.");
return nullptr;
}
double operand1, operand2;
napi_get_value_double(env, parameters[0], &operand1);
napi_get_value_double(env, parameters[1], &operand2);
napi_value result;
napi_create_double(env, operand1 + operand2, &result);
return result;
}
static napi_value RegisterModule(napi_env env, napi_value exports) {
napi_property_descriptor methods[] = {
{"calculateSum", nullptr, ComputeSum, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, sizeof(methods) / sizeof(methods[0]), methods);
return exports;
}
static napi_module calculatorModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = RegisterModule,
.nm_modname = "calculator",
.nm_priv = nullptr,
.reserved = {0},
};
extern "C" __attribute__((constructor)) void InitializeModule() {
napi_module_register(&calculatorModule);
}
Module Registration and Interface Declaration
static napi_value RegisterModule(napi_env env, napi_value exports) {
napi_property_descriptor methods[] = {
{"calculateSum", nullptr, ComputeSum, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, sizeof(methods) / sizeof(methods[0]), methods);
return exports;
}
static napi_module calculatorModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = RegisterModule,
.nm_modname = "calculator",
.nm_priv = nullptr,
.reserved = {0},
};
extern "C" __attribute__((constructor)) void InitializeModule() {
napi_module_register(&calculatorModule);
}
Parameter Retrieval and Type Conversion
static napi_value ComputeSum(napi_env env, napi_callback_info info) {
size_t expectedArgs = 2;
size_t actualArgs = 2;
napi_value parameters[2] = {nullptr};
napi_get_cb_info(env, info, &actualArgs, parameters, nullptr, nullptr);
napi_valuetype paramType1, paramType2;
napi_typeof(env, parameters[0], ¶mType1);
napi_typeof(env, parameters[1], ¶mType2);
if (paramType1 != napi_number || paramType2 != napi_number) {
napi_throw_type_error(env, nullptr, "Invalid arguments. Expected 2 numbers.");
return nullptr;
}
double operand1, operand2;
napi_get_value_double(env, parameters[0], &operand1);
napi_get_value_double(env, parameters[1], &operand2);
napi_value result;
napi_create_double(env, operand1 + operand2, &result);
return result;
}
Parameter Retrieval Function
The napi_get_cb_info function extracts parameter information from the callback context:
napi_status napi_get_cb_info(napi_env env,
napi_callback_info cbinfo,
size_t* argc,
napi_value* argv,
napi_value* this_arg,
void** data)
env: NAPI environment handllecbinfo: Callback information objectargc: Requested and actual parameter countargv: Parameter arraythis_arg: JavaScript 'this' objectdata: Context data pointer
JavaScript to C++ Type Conversion
NAPI provides conversion functions for different data types:
napi_get_value_doublenapi_get_value_int32napi_get_value_uint32napi_get_value_int64napi_get_value_boolnapi_get_value_string_latin1napi_get_value_string_utf8napi_get_value_string_utf16
Type checking is performed using napi_typeof:
napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result)
C++ to JavaScript Type Conversion
Conversion from C++ types to JavaScript values uses creation functions:
napi_create_doublenapi_create_int32napi_create_uint32napi_create_int64napi_create_string_latin1napi_create_string_utf8napi_create_string_utf16
ArkUI Application Implementation
import calculator from '@ohos.calculator'
@Entry
@Component
export struct CalculatorApp {
private inputController1: TextInputController = new TextInputController()
private inputController2: TextInputController = new TextInputController()
private title: string = 'C/C++ and JavaScript Data Type Conversion'
private description: string = 'Calculate X + Y'
private promptX: string = 'Enter X:'
private promptY: string = 'Enter Y:'
private resultLabel: string = 'Result:'
private calculateButton: string = 'Calculate'
@State result: number = 0.0
@State valueX: number = 0.0
@State valueY: number = 0.0
build() {
Row() {
Column() {
Row(){
Text(this.title)
.height('100%')
.align(Alignment.Center)
.fontSize(50)
.fontWeight(800)
}
.height('30%')
.width('100%')
.justifyContent(FlexAlign.Center)
Row(){
Text(this.description)
.height('100%')
.align(Alignment.Center)
.fontSize(35)
.fontWeight(500)
}
.height('15%')
.width('100%')
.justifyContent(FlexAlign.Center)
Row(){
Text(this.promptX)
.fontColor(Color.Black)
.fontSize('65px')
.width('30%')
.height('100%')
.margin({left:30})
TextInput({ placeholder: 'X', controller: this.inputController1})
.type(InputType.Number)
.height('100%')
.width('60%')
.margin({left:10, right:30})
.fontSize('25px')
.onChange(value => { this.valueX = parseFloat(value) })
}
.height('6%')
.width('100%')
.justifyContent(FlexAlign.Start)
Row(){
Text(this.promptY)
.fontColor(Color.Black)
.fontSize('65px')
.width('30%')
.height('100%')
.margin({left:30})
TextInput({ placeholder: 'Y', controller: this.inputController2})
.type(InputType.Number)
.height('100%')
.width('60%')
.margin({left:10, right:30})
.fontSize('25px')
.onChange(value => { this.valueY = parseFloat(value) })
}
.height('6%')
.width('100%')
.margin({top:20})
Row(){
Text(this.resultLabel)
.fontColor(Color.Black)
.fontSize(35)
.width('40%')
.height('100%')
.margin({left:30})
Text('' + this.result)
.fontColor(Color.Black)
.fontSize(35)
.width('60%')
.height('100%')
}
.height('10%')
.width('100%')
.touchable(false)
Row(){
Button(this.calculateButton)
.fontSize(37)
.fontWeight(FontWeight.Bold)
.margin({top:5})
.height(80)
.width(200)
.onClick(() => {
this.result = calculator.calculateSum(this.valueX, this.valueY)
})
}
.height('30%')
.width('100%')
.justifyContent(FlexAlign.Center)
}
.width('100%')
}
.height('100%')
}
}
TypeScript Interface Definition
declare namespace calculator {
export const calculateSum: (x: number, y: number) => number;
}
export default calculator;