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

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

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

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

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值