1. HarmonyOS ArkTS与C++数据类型转换
本文介绍了C++与TS各自数据类型与互相之间的数据类型转换,在需要使用C++模块时可以快速上手对各种数据类型进行转换。
1.1. 概述
HarmonyOS的主力开发语言是ArkTS,也提供了C++语言的支持,对于一些能力,比如音视频编解码等,HarmonyOS 提供的也只有C++ API,对于一些其他平台现有能力的迁移,C++也是最快捷高效的,所以对于一个HarmonyOS 开发者,掌握ArkTS与C++交互成了一项必备技能。
&emsp每种编程语言都有自己定义的数据类型,不同编程语言之间互相调用就涉及到了数据类型的转换,ArkTS与C++的转换主要有Node-API接口提供,本文介绍ArkTS与C++互相转换的接口和最佳实践。
做过Android JNI开发的小伙伴对Java和C++的互相调用有所了解,JNI提供了Java和C++的类型转换,与JNI不同的是NAPI中,TS调用C++的参数都封装到了一起:
javascript
static napi_value add(napi_env env, napi_callback_info info)
{
}
不管要传递多少个参数,都封装在napi_callback_info中,可以从napi_callback_info中获取全部参数信息:
javascript
size_t argc = 7;//参数个数
napi_value args[7] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
1.2. 创建Native C++ Module
1.2.1. 右键项目->new->module

1.2.2. 修改build-profile.json5配置
javascript
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-v -DOHOS_STL=c++_shared",
"abiFilters": [
// "armeabi-v7a",
// "x86_64",
"arm64-v8a"
],
"cppFlags": ""
}
1.2.3. CMakeLists.txt 配置
javascript
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MyApplication43)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(application SHARED SRRtcVideoEngineNapi.cpp SRRtcRoomCallBackNapi.cpp)
target_link_libraries(application PUBLIC libace_napi.z.so)
1.3. 代码实现
1.3.1. 主调接口实现
NAPI中缓存回调接口的变量,便于后面回调给TS
javascript
napi_value SRRtcVideoEngineNapi::setRRoomCallBack(napi_env env, napi_callback_info info) {
LogE("setRRoomCallBack---一个参数:ISRoomCallBack");
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (status != napi_ok) {
napi_throw_error(env, "", "");
return nullptr;
}
// 缓存回调函数全局变量,回调ets用
if (SRGlobalvar::napi_CallbackReference == nullptr) {
LogE("setRRoomCallBack===new NapiCallBack()");
SRGlobalvar::napi_CallbackReference = new NapiCallBack(); // 创建缓存函数
}
napi_create_reference(env, args[0], 1, &SRGlobalvar::napi_CallbackReference->roomCallBack_napi);
SRGlobalvar::napi_CallbackReference->env = env;
// 调用 底层sdk : RRoomControlMgr.setCallBack
RResult rResult = sr_engineSdk->setRRoomCallBackRtcEngine();
return SRGlobalvar::returnResult(env, rResult);
}
1.3.2. 回调接口实现
通过缓存的env,callback对象,调用napi_call_function方法将数据传回给ts
javascript
void SRRtcRoomCallBackNapi::onRoomJoinConfirm(RResult rResult, const RRoomInfo &roomInfo) {
// 处理 onRoomJoinConfirm 通知
LogE("回调消息---SRRtcRoomCallBack:onRoomJoinConfirm ");
// 转换N-API对象
napi_value roomInfo_napi = SRGlobalvar::convertToSRRoomInfo(SRGlobalvar::napi_CallbackReference->env, roomInfo);
napi_value rResult_napi = SRGlobalvar::convertToSRResult(SRGlobalvar::napi_CallbackReference->env, rResult);
// 传递给TS
napi_value callback;
napi_get_reference_value(SRGlobalvar::napi_CallbackReference->env,
SRGlobalvar::napi_CallbackReference->roomCallBack_napi, &callback);
napi_value jsMethod;
napi_get_named_property(SRGlobalvar::napi_CallbackReference->env, callback, "onRoomJoinConfirm", &jsMethod);
napi_value argv[] = {rResult_napi, roomInfo_napi};
napi_value callbackResult = nullptr;
napi_call_function(SRGlobalvar::napi_CallbackReference->env, nullptr, jsMethod, 2, argv, &callbackResult);
}
1.4. ets的接收c++传回的数据
1.4.1. index.d.ts 代码增加接口
javascript
function setRRoomCallBack(sroomCallback: ISRoomCallBack): SRReult
1.4.2. 回调接口SRoomCallBack.ets
javascript
export class SRoomCallBack implements ISRoomCallBack {
onRoomJoinConfirm(rResult: SRReult, roomInfo: SRRoomInfo) {
SRLog.i(TAG, `onRoomJoinConfirm==回调测试完成=rResult:${JsonUtil.jsonToString(rResult)}\n roomInfo:${JsonUtil.jsonToString(roomInfo)}`)
}
}
1.4.3. 调用
javascript
import srrtcNapi from 'librtcvideo.so';
setRRoomCallBackRtcEngine(callback: ISRoomCallBack) {
let srResult = srrtcNapi.setRRoomCallBack(callback)
SRLog.i(TAG, "setRRoomCallBackRtcEngine===srresult:" + JsonUtil.jsonToString(srResult))
}
1.5. 数据转换
1.5.1. ArkTS转C++类型
** TS基本数据类型:**
(1)数字类型: number
(2)字符串类型 :string
(3)布尔类型: boolean
(4)任意精度整型: bigint
(5)对象类型: object
C++基本数据类型:
(6)整型i:nt、short、long、long long
(7)浮点型:float、double、long double
(8)字符型: char
(9)布尔型: bool
1.5.2. 基本数据类型转换
NAPI提供了上面两种语言对应的类型的转换:
(1)转换为布尔类型:napi_get_value_bool
(2)转换为int32:napi_get_value_int32
(3)转换为int64:napi_get_value_int64
(4)转换为无符号32位:napi_get_value_uint32
(5)转换为double:napi_get_value_double
(6)bitint 64位:napi_get_value_bigint_int64
(7)bitint 无符号64位:`napi_get_value_bigint_uint64
除了bool类型,其他基本类型就是数值类型,TS中的数值类型对应C++各种细分类型,分别调用上面不同函数即可,调用方式:
javascript
int intValue;
napi_get_value_int32(env, args[0], &intValue);
上面代码通过napi_get_value_int32将TS中的number转换为int赋值给intValue变量。
1.5.3. 字符串类型转换
对于字符串和object对象处理稍微复杂些,通过napi_get_value_string_utf8将js的字符串对象转换为c++的std::string对象。但是要创建std:string需要先知道TS中传来的字符串的长度,看napi_get_value_string_utf8函数说明:
javascript
napi_status napi_get_value_string_utf8(napi_env env,
napi_value value,
char* buf,
size_t bufsize,
size_t* result)
in\] env: The environment that the API is invoked under.
\[in\] value: napi_value representing JavaScript string.
\[in\] buf: Buffer to write the UTF8-encoded string into. If NULL is passed in, the length of the string in bytes and excluding the null terminator is returned in result.
\[in\] bufsize: Size of the destination buffer. When this value is insufficient, the returned string is truncated and null-terminated.
\[out\] result: Number of bytes copied into the buffer, excluding the null terminator.
Returns napi_ok if the API succeeded. If a non-string napi_value is passed in it returns napi_string_expected.
我们需要先创建一个char类型的空间去接收转换后的字符串,创建char空间需要指定大小,可以先调用一次napi_get_value_string_utf8,buf传入空获取到传入的数据大小,然后创建对应大小buf,再次调用napi_get_value_string_utf8获取转换后的字符串:
```javascript
void JsValueToString(const napi_env &env, const napi_value &value, std::string &target) {
size_t result = 0;
napi_get_value_string_utf8(env, value, nullptr, 0, &result);
std::unique_ptr