本文包含鸿蒙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
@Component
struct 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相关平台目录
创作不易,赠人玫瑰,手有余香,觉得有用,点个赞吧
🈶任何问题可以私信