本文包含鸿蒙ArkTs加载适用于鸿蒙os专用的so库与Linux/Android通用so库两部分
如果你手上有c源代码参考笔者这篇文章编译一份适用于鸿蒙ArkTs的so动态库教学,提供给第三方导入并使用
如果你手上的so库是适用于ArkTs的(类似于Node的 C/C++ addons with N-API),直接在代码中使用
import xxx from 'libxxx.so'
如果没报错且xxx是个空对象那么恭喜你,你手上的那份so并非适用于鸿蒙os且看下文指引
鸿蒙ArkTs加载通用Linux/Android so动态链接库
1.准备工作:
一份通用Linux/Android so动态库。
如果已经有了跳到第2步
以cJson为例,拷贝代码并打开目录
linux环境下
gcc -march=armv8-a -fPIC -shared -o cjosn.so cJSON.c
得到一份armv8-a平台的cjson.so linux通用so库
2.创建一个鸿蒙工程并导入so库
可以选择native模版创建也可以创建普通工程,将native需要的文件都复制过去
把你的so库甩到libs目录对应平台下不要尝试把x86_64的so库丢进去arm目录去,回天乏力了,救救孩子吧
官方的说明,我们是导入linux通用so,所以无视他
3.编写胶水层,用来连接你的ArkTs与so库的c function
打开/src/main/cpp/CMakeLists.txt
# the minimum version of CMake.cmake_minimum_required(VERSION 3.4.1)project(loadSo)set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include)#你的模块名叫hello最终会生成一个libhello.so的动态库#从hello.c编译出动态库#在ArkTs中使用import xxx from 'libhello.so' 来导入你的胶水层并使用add_library(hello SHARED hello.c)#链接你的hello使用n-api库target_link_libraries(hello PUBLIC libace_napi.z.so)
打开你的/src/main/cpp/hello.c(鸿蒙navtive工程模版),修改代码
#include "napi/native_api.h"#include <dlfcn.h>typedef struct cJSON { /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *next; struct cJSON *prev; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ struct cJSON *child; /* The type of the item, as above. */ int type; /* The item's string, if type==cJSON_String and type == cJSON_Raw */ char *valuestring; /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ int valueint; /* The item's number, if type==cJSON_Number */ double valuedouble; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string;} cJSON;static napi_value Add(napi_env env, napi_callback_info info) { /*接收来之ArkTs传递过来的参数,我们没有,注释掉size_t requireArgc = 2; size_t argc = 2; napi_value args[2] = {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);*/ napi_value result; ///加载cjson.so void *hande = dlopen("cjson.so", RTLD_LAZY); if (!hande) { //加载失败 char *fail = "死翘翘了"; napi_create_string_utf8(env, fail, strlen(fail), &result); //将加载失败原因甩到ArkTs层,可以在try catch中获捕到 napi_throw_error(env, NULL, dlerror()); return result; } // cjson.c 的cJSON_CreateObject函数 cJSON *(*cJSON_CreateObject)(void) = (cJSON * (*)()) dlsym(hande, "cJSON_CreateObject"); //调用cJSON_CreateObject cJSON *cObject = (*cJSON_CreateObject)(); char *returnStr = "你很棒呀!加油打工人"; cObject->valuestring = returnStr; //创建一个ArkTs object napi_create_object(env, &result); napi_value type; napi_create_int32(env, cObject->type, &type); napi_value valueint; napi_create_int32(env, cObject->valueint, &valueint); napi_value valuestring; napi_create_string_utf8(env, cObject->valuestring ? cObject->valuestring : "", strlen(cObject->valuestring), &valuestring); napi_value string; if (cObject->string) { napi_create_string_utf8(env, cObject->string, strlen(cObject->string), &string); } napi_value valuedouble; napi_create_double(env, cObject->valuedouble, &valuedouble); //把相应值丢到ArkTs object中 napi_set_named_property(env, result, "type", type); napi_set_named_property(env, result, "valueint", valueint); napi_set_named_property(env, result, "valuestring", valuestring); napi_set_named_property(env, result, "string", (cObject->string)? string:NULL); napi_set_named_property(env, result, "valuedouble", valuedouble); //返回这个ArkTs object return result;}static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { //这里是暴露给ArkTs可以直接调用的函数 {"cJSON_CreateObject", NULL, Add, NULL, NULL, NULL, napi_default, NULL}}; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports;}static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = NULL, .nm_register_func = Init, //按官方说法名字一致 .nm_modname = "hello", .nm_priv = ((void *)0), .reserved = {0},};//入口函数__attribute__((constructor)) void RegisterEntryModule(void) { //给ArkTs注册可以直接调用的函数列表 napi_module_register(&demoModule);}
鸿蒙官方文档: Native API在应用工程中的使用指导
鸿蒙官方文档: Node-Api
Node官方文档: C/C++ addons with N-API这份文档仅供参考,鸿蒙并没有完全实现里面所有接口,且底层实现不一致。
使用胶水层
import hello from 'libhello.so'@Entry@Componentstruct Index { @State message: string = 'Hello World' aboutToAppear() { try { const cObject = hello.cJSON_CreateObject(); this.message = cObject.valuestring; } catch (e: any) { this.message = e.toString(); } } build() { Text(this.message) }}
不出意外的话,你的胶水已经粘牢了
当然!你也可能出现各种意外,毕竟你使用了来历不明的so库。
错误可以在catch里捕获
一些错误示例
你可能你的so非linux/android的库,比如适用于drwin的so
你的so库依赖别的库,需要将错误提示中的相关库一并丢/libs/arm64-v8a相关平台目录
创作不易,赠人玫瑰,手有余香,觉得有用,点个赞吧
?任何问题可以私信