当前位置:首页 » 《关于电脑》 » 正文

鸿蒙ArkTs加载各种so动态链接库教程,包括适用于鸿蒙的动态库和通用linux动态链接库,堕胎级教程,一篇就够了,玩转so加载

24 人参与  2024年03月29日 14:40  分类 : 《关于电脑》  评论

点击全文阅读


本文包含鸿蒙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里捕获
一些错误示例
1
你可能你的so非linux/android的库,比如适用于drwin的so

在这里插入图片描述
你的so库依赖别的库,需要将错误提示中的相关库一并丢/libs/arm64-v8a相关平台目录

创作不易,赠人玫瑰,手有余香,觉得有用,点个赞吧
?任何问题可以私信


点击全文阅读


本文链接:http://zhangshiyu.com/post/87684.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1