1# NDK开发常见问题 2 3## 以libstd为例,C++的标准库放在哪里了,有没有打到hap包中?(API 10) 4 5**解决方案** 6 7libc++_shared.so被打包到应用目录下了,每个应用都有一份独立的libc++_shared.so (/data/storage/el1/bundle/libs/${arch}) 8 9## C/C++的三方开源库如何迁移到系统下运行?(API 10) 10 11**解决方案** 12 13当前官方SDK只支持Cmake构建,同时对于依赖GN构建的场景提供了迁移指导 14 15**参考资料** 16 171. GN构建: 18 19 [基于gn_example编译三方库代码](https://gitee.com/openharmony/build/wikis/gn%E6%9E%84%E5%BB%BA%E4%B8%89%E6%96%B9%E5%BA%93/%E5%9F%BA%E4%BA%8Egn_example%E7%BC%96%E8%AF%91%E4%B8%89%E6%96%B9%E5%BA%93%E4%BB%A3%E7%A0%81) 20 21 [基于三方编译框架移植OHOS](https://gitee.com/openharmony/build/wikis/gn%E6%9E%84%E5%BB%BA%E4%B8%89%E6%96%B9%E5%BA%93/%E5%9F%BA%E4%BA%8E%E4%B8%89%E6%96%B9%E7%BC%96%E8%AF%91%E6%A1%86%E6%9E%B6%E7%A7%BB%E6%A4%8DOHOS) 22 232. CMake构建: 24 25 linux:[HOW TO USE NDK (linux)](https://gitee.com/openharmony/build/wikis/NDK/HOW%20TO%20USE%20NDK%20(linux)) 26 27 windows:[HOW TO USE NDK (windows)](https://gitee.com/openharmony/build/wikis/NDK/HOW%20TO%20USE%20NDK%20(windows)) 28 29## 开发者使用napi扩展TS接口时,常用的属性和实现接口的基本用法是什么?例如怎么获取env,怎么实现callback和promise,怎么使用libuv?(API 10) 30 31 32 33**解决方案** 34 351. env是使用napi的模块化编程,注册模块之后,调用回调的时候会通过回调函数调用过来: 36 37 ```cpp 38 static napi_value CallNapi(napi_env env, napi_callback_info info) 39 { 40 size_t argc = 1; 41 napi_value object = nullptr; 42 napi_status status; 43 status = napi_get_cb_info(env, info, &argc, &object, nullptr, nullptr); 44 return object; 45 } 46 NAPI_MODULE_INIT() 47 { 48 napi_property_descriptor desc[] = { 49 {"callNapi", nullptr, CallNapi, nullptr, nullptr, nullptr, napi_default, nullptr}}; 50 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 51 return exports; 52 } 53 ``` 54 552. callback实现: 56 57 ```cpp 58 #include "napi/native_api.h" 59 #include <assert.h> 60 static napi_value NativeCall(napi_env env, napi_callback_info info) 61 { 62 size_t argc = 1; 63 napi_value args[1] = {nullptr}; 64 napi_status status; 65 status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 66 assert(status == napi_ok); 67 68 napi_valuetype valuetype; 69 napi_typeof(env, args[0], &valuetype); 70 if (valuetype != napi_valuetype::napi_function) 71 { 72 napi_throw_type_error(env, nullptr, "napi_function is expected"); 73 } 74 napi_value cb = args[0]; 75 76 napi_value undefined; 77 status = napi_get_undefined(env, &undefined); 78 assert(status == napi_ok); 79 80 napi_value argv[2] = {nullptr}; 81 status = napi_create_int32(env, 1, &argv[0]); 82 assert(status == napi_ok); 83 status = napi_create_int32(env, 2, &argv[1]); 84 assert(status == napi_ok); 85 86 napi_value result; 87 status = napi_call_function(env, undefined, cb, 2, argv, &result); 88 assert(status == napi_ok); 89 90 return nullptr; 91 } 92 EXTERN_C_START 93 static napi_value Init(napi_env env, napi_value exports) 94 { 95 napi_property_descriptor desc[] = { 96 {"nativeCall", nullptr, NativeCall, nullptr, nullptr, nullptr, napi_default, nullptr}}; 97 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 98 return exports; 99 } 100 EXTERN_C_END 101 static napi_module module = { 102 .nm_version = 1, 103 .nm_flags = 0, 104 .nm_filename = nullptr, 105 .nm_register_func = Init, 106 .nm_modname = "callback", 107 .nm_priv = nullptr, 108 .reserved = {0}, 109 }; 110 extern "C" __attribute__((constructor)) void RegisterCallbackModule(void) 111 { 112 napi_module_register(&module); 113 } 114 ``` 115 1163. promise实现参考: 117 118 ```cpp 119 #include "napi/native_api.h" 120 121 // Empty value so that macros here are able to return NULL or void 122 #define NAPI_RETVAL_NOTHING // Intentionally blank 123 124 #define GET_AND_THROW_LAST_ERROR(env) 125 do 126 { 127 const napi_extended_error_info *errorInfo = nullptr; 128 napi_get_last_error_info((env), &errorInfo); 129 bool isPending = false; 130 napi_is_exception_pending((env), &isPending); 131 if (!isPending && errorInfo != nullptr) 132 { 133 const char *errorMessage = 134 errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; 135 napi_throw_error((env), nullptr, errorMessage); 136 } 137 } while (0) 138 139 #define NAPI_ASSERT_BASE(env, assertion, message, retVal) 140 do { 141 if (!(assertion)) 142 { 143 napi_throw_error((env), nullptr, "assertion(" #assertion ") failed : " message); 144 return retVal; 145 } 146 } while (0) 147 148 #define NAPI_ASSERT(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, nullptr) 149 150 #define NAPI_ASSERT_RETURN_VOID(env, assertion, message) 151 NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING) 152 153 #define NAPI_CALL_BASE(env, theCall, retVal) 154 do 155 { 156 if ((theCall) != napi_ok) 157 { 158 GET_AND_THROW_LAST_ERROR((env)); 159 return retVal; 160 } 161 } while (0) 162 163 #define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) 164 165 #define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING) 166 167 struct AsyncData{ 168 napi_deferred deferred; 169 napi_async_work work; 170 171 int32_t arg; 172 double retVal; 173 }; 174 175 double DoSomething(int32_t val) 176 { 177 if (val != 0) 178 { 179 return 1.0 / val; 180 } 181 return 0; 182 } 183 184 void ExecuteCallback(napi_env env, void *data) 185 { 186 AsyncData* asyncData = reinterpret_cast<AsyncData*>(data); 187 asyncData->retVal = DoSomething(asyncData->arg); 188 } 189 190 void CompleteCallback(napi_env env, napi_status status, void *data) 191 { 192 AsyncData* asyncData = reinterpret_cast<AsyncData*>(data); 193 194 napi_value retVal; 195 if (asyncData->retVal == 0) 196 { 197 NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, "arg can't be zero", NAPI_AUTO_LENGTH, &retVal)); 198 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, asyncData->deferred, retVal)); 199 } 200 else 201 { 202 NAPI_CALL_RETURN_VOID(env, napi_create_double(env, asyncData->retVal, &retVal)); 203 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, asyncData->deferred, retVal)); 204 } 205 206 NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, asyncData->work)); 207 asyncData->work = nullptr; 208 asyncData->deferred = nullptr; 209 delete asyncData; 210 } 211 212 static napi_value NativeCall(napi_env env, napi_callback_info info) 213 { 214 size_t argc = 1; 215 napi_value args[1] = {nullptr}; 216 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); 217 218 int32_t arg; 219 NAPI_CALL(env, napi_get_value_int32(env, args[0], &arg)); 220 221 // Create promise 222 napi_deferred deferred; 223 napi_value promise; 224 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); 225 226 AsyncData *data = new AsyncData; 227 data->deferred = deferred; 228 data->arg = arg; 229 230 napi_async_work work; 231 napi_value workName; 232 napi_create_string_utf8(env, "promise", NAPI_AUTO_LENGTH, &workName); 233 NAPI_CALL(env, napi_create_async_work(env, nullptr, workName, 234 ExecuteCallback, CompleteCallback, data, &work)); 235 236 data->work = work; 237 NAPI_CALL(env, napi_queue_async_work(env, work)); 238 239 return promise; 240 } 241 242 EXTERN_C_START 243 static napi_value Init(napi_env env, napi_value exports) 244 { 245 napi_property_descriptor desc[] = { 246 {"nativeCall", nullptr, NativeCall, nullptr, nullptr, nullptr, napi_default, nullptr} 247 }; 248 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 249 return exports; 250 } 251 EXTERN_C_END 252 253 static napi_module demoModule = { 254 .nm_version = 1, 255 .nm_flags = 0, 256 .nm_filename = nullptr, 257 .nm_register_func = Init, 258 .nm_modname = "promise", 259 .nm_priv = nullptr, 260 .reserved = {0}, 261 }; 262 263 extern "C" __attribute__((constructor)) void RegisterPromiseModule(void) 264 { 265 napi_module_register(&demoModule); 266 } 267 ``` 268 2694. libuv使用:可以直接导入libuv三方库使用 270 271## pthread创建的线程中如何读取rawfile?(API 10) 272 273**解决方案** 274 275可在线程安全函数中读取: 2761. UI 主线程中获取并保存资源文件对象; 2772. 创建线程安全函数; 2783. 在非UI主线程中调用线程安全函数; 2794. 在线程安全函数中,读取rawfile下的文件资源。 280 281## ArkTS线程通过napi创建的C++线程的处理结果如何返回ArkTS线程?(API 10) 282 283**解决方案** 284 285采用napi_create_threadsafe_function在ArkTS线程创建可被任意线程调用的函数,在C++线程调用napi_call_threadsafe_function可以将结果回调给主线程。 286 287**参考链接** 288 289[使用Node-API接口进行线程安全开发](../napi/use-napi-thread-safety.md) 290 291## 由napi_create_object创建,或者作为参数传下来的JS对象,如果想持久持有,需要怎么做?(API 10) 292 293**问题描述** 294 295以及,怎么主动销毁或减少引用计数? 296 297**解决方案** 298 299持久持有一个对象,可以通过napi_create_reference创建一个强引用,然后将这个ref保存下来使用;主动销毁可以使用napi_delete_reference,减少或者增加引用计数可以通过napi_reference_unref或者napi_reference_ref。 300 301## 在ArkTS层往C++层注册一个对象或函数,C++层可以按需往这个回调上进行扔消息同步到上层应用么?(API 11) 302 303**问题描述** 304 305以及,在注册对象或函数时,napi_env是否可以被长时持有?扔消息同步到上层应用时,是否需要在特定线程? 306 307**解决方案** 308 309纯在ArkTS侧不可以往C++层注册对象或者函数,开发者需要回到C++层自己处理;env可以长期持有,不过使用env时,需要在特定的线程,使用env时需要在创建该env的ArkTS线程使用。 310 311**参考资料** 312 3131. [Native与ArkTS对象绑定](../napi/use-napi-object-wrap.md) 314