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