开源鸿蒙PC三方库复现在 DevEco Studio 里调用三方 .so 库欢迎加入开源鸿蒙 PC 社区https://harmonypc.csdn.net/开源仓库地址https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mediainfo_windows当你手里已经有一个适配好的.so和头文件怎么在DevEco Studio的 Native C 工程里真正把它用起来。本篇思路参考了社区作者wei_shuo的实践https://weishuo.blog.csdn.net/article/details/161196629并以我自己的工程经验重新梳理。这篇要解决的问题交叉编译产出.so只是上半场。下半场是让鸿蒙应用ArkTS 写的 UI能真正调到这个 C/C 库的能力。这中间隔着一层NAPI 桥接。我用libplacebo一个视频渲染/色彩处理库作为例子它依赖极简、API 友好很适合用来打通整条链路。项目信息IDEDevEco Studio工程模板Native C示例库libplacebo v7.362.0目标设备HUAWEI MateBook ProHarmonyOS架构arm64-v8a我对整条调用链的理解刚接触时我也被绕晕过后来把它画成一条单向链路就清晰了ArkTS (Index.ets) → import libentry.so → NAPI 层 (napi_init.cpp) 把 JS 调用转成 C 调用 → C 调用三方库 API (libplacebo) → 结果原路返回到 UI说白了集成一个三方库本质只要把三件事告诉构建系统.so 在哪—— 打包时塞进 HAP运行时能被加载。头文件在哪—— 编译时 C 能#include到 API 声明。怎么链接—— 让自己的 native 模块和三方库产生符号引用。记住这三件事后面所有配置都是为它们服务的。拿到产物先别急着放先体检这是我吃过亏才养成的习惯。拿到.so先用 SDK 自带的llvm-readelf -d看两个字段NEEDED它运行时还依赖哪些 .so。系统自带的libc.so、libc_shared.so不用管非系统的必须一起打包。SONAME库的「内部名字」。最隐蔽的坑SONAME 带版本号如果.so文件名是libplacebo.so但内部 SONAME 是libplacebo.so.362运行时dlopen会按 SONAME 去找libplacebo.so.362结果找不到、加载失败。表现出来往往是个让人摸不着头脑的Cannot read property xxx of undefined。我的修法是用 Python 直接在二进制里把 SONAME 字符串改成跟文件名一致注意保持字节长度不变用\x00补齐不破坏 ELF 结构dataopen(libplacebo.so,rb).read()datadata.replace(blibplacebo.so.362\x00,blibplacebo.so\x00\x00\x00\x00\x00)open(libplacebo.so,wb).write(data)改完再llvm-readelf -d复核一遍。这条经验对任何带版本号 SONAME 的库都通用。文件该放哪DevEco 的 Native C 工程有约定俗成的位置entry/ ├── libs/arm64-v8a/libplacebo.so ← .so 放这按架构分目录 └── src/main/cpp/ ├── include/libplacebo/*.h ← 头文件放这需手动建 include ├── CMakeLists.txt ← 改 ├── napi_init.cpp ← 改 └── types/libentry/Index.d.ts ← 改 └── src/main/ets/pages/Index.ets ← 改放文件这一步不需要写任何代码纯粹是「摆位置」。真正要动手改的是后面四个文件。四个文件怎么改1. CMakeLists.txt —— 告诉构建系统库在哪、怎么链核心就是把三方库声明成一个IMPORTED外部已有不用编译的库set(LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}) add_library(placebo SHARED IMPORTED) set_target_properties(placebo PROPERTIES IMPORTED_LOCATION ${LIBS_DIR}/libplacebo.so) include_directories(${NATIVERENDER_ROOT_PATH}/include) add_library(entry SHARED napi_init.cpp) target_link_libraries(entry PUBLIC libace_napi.z.so placebo)我自己记这段的逻辑add_library(IMPORTED)是「声明有这么个外部库」IMPORTED_LOCATION是「它在磁盘哪个位置」include_directories解决头文件搜索target_link_libraries把它和我的模块绑起来。换别的库只要替换库名和文件名即可。2. napi_init.cpp —— 写桥接函数这一层是体力活把每个想暴露给 ArkTS 的功能写成一个napi_value函数内部调用三方库 API再用napi_create_string_utf8之类把结果转回 JS 类型。最后在Init里用napi_property_descriptor数组把它们注册出去。我的建议是先只暴露一个最简单的「拿版本号」函数把链路打通确认能跑了再逐个加别一上来写一大堆。3. Index.d.ts —— 类型声明给 native 模块写 TS 声明函数名必须和 C 里注册的完全一致。不写也能跑但 ArkTS 里调用会是any类型没提示也没检查体验很差。4. Index.ets —— 前端调用importplfromlibentry.so;// ...this.reportpl.runAllTests();import xxx from libentry.so这个写法第一次见会有点意外记住「模块名 .so 后缀」即可。构建与真机验证Build Build Hap(s)然后 USB 连真机Run。几个高频报错我列一下对照报错我的判断config.h: No such file or directory头文件路径没配对检查include_directoriescannot find -lplacebo.so路径不对检查IMPORTED_LOCATIONundefined reference to pl_version链接漏了检查target_link_libraries运行时Cannot read property xxx of undefined八成是 SONAME 没修应用闪退.so的 NEEDED 依赖没打全我提炼的通用流程不管换成 OpenCV 还是 FFmpeg这套步骤都成立1. llvm-readelf -d 检查 NEEDED 和 SONAME 2. 修 SONAME带版本号的话 3. .so → entry/libs/arm64-v8a/ 4. 头文件 → entry/src/main/cpp/include/ 5. CMakeLists.txt 声明 IMPORTED 库 6. napi_init.cpp 写桥接 7. Index.d.ts 写类型 8. Index.ets 导入调用 9. Build Run小结这一篇把「产物 → 应用可用」的最后一公里走通了。和上一篇的交叉编译合起来就是一个三方库进入鸿蒙生态的完整闭环编出来 → 调进去。下一篇我会聊另一种集成场景——不在 DevEco而是在鸿蒙 PC 的 CodeArts IDE 里直接编译、签名、运行 libplacebo。感谢原创适配作者wei_shuo的分享。
开源鸿蒙PC三方库复现:在 DevEco Studio 里调用三方 .so 库
发布时间:2026/6/16 1:06:55
开源鸿蒙PC三方库复现在 DevEco Studio 里调用三方 .so 库欢迎加入开源鸿蒙 PC 社区https://harmonypc.csdn.net/开源仓库地址https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mediainfo_windows当你手里已经有一个适配好的.so和头文件怎么在DevEco Studio的 Native C 工程里真正把它用起来。本篇思路参考了社区作者wei_shuo的实践https://weishuo.blog.csdn.net/article/details/161196629并以我自己的工程经验重新梳理。这篇要解决的问题交叉编译产出.so只是上半场。下半场是让鸿蒙应用ArkTS 写的 UI能真正调到这个 C/C 库的能力。这中间隔着一层NAPI 桥接。我用libplacebo一个视频渲染/色彩处理库作为例子它依赖极简、API 友好很适合用来打通整条链路。项目信息IDEDevEco Studio工程模板Native C示例库libplacebo v7.362.0目标设备HUAWEI MateBook ProHarmonyOS架构arm64-v8a我对整条调用链的理解刚接触时我也被绕晕过后来把它画成一条单向链路就清晰了ArkTS (Index.ets) → import libentry.so → NAPI 层 (napi_init.cpp) 把 JS 调用转成 C 调用 → C 调用三方库 API (libplacebo) → 结果原路返回到 UI说白了集成一个三方库本质只要把三件事告诉构建系统.so 在哪—— 打包时塞进 HAP运行时能被加载。头文件在哪—— 编译时 C 能#include到 API 声明。怎么链接—— 让自己的 native 模块和三方库产生符号引用。记住这三件事后面所有配置都是为它们服务的。拿到产物先别急着放先体检这是我吃过亏才养成的习惯。拿到.so先用 SDK 自带的llvm-readelf -d看两个字段NEEDED它运行时还依赖哪些 .so。系统自带的libc.so、libc_shared.so不用管非系统的必须一起打包。SONAME库的「内部名字」。最隐蔽的坑SONAME 带版本号如果.so文件名是libplacebo.so但内部 SONAME 是libplacebo.so.362运行时dlopen会按 SONAME 去找libplacebo.so.362结果找不到、加载失败。表现出来往往是个让人摸不着头脑的Cannot read property xxx of undefined。我的修法是用 Python 直接在二进制里把 SONAME 字符串改成跟文件名一致注意保持字节长度不变用\x00补齐不破坏 ELF 结构dataopen(libplacebo.so,rb).read()datadata.replace(blibplacebo.so.362\x00,blibplacebo.so\x00\x00\x00\x00\x00)open(libplacebo.so,wb).write(data)改完再llvm-readelf -d复核一遍。这条经验对任何带版本号 SONAME 的库都通用。文件该放哪DevEco 的 Native C 工程有约定俗成的位置entry/ ├── libs/arm64-v8a/libplacebo.so ← .so 放这按架构分目录 └── src/main/cpp/ ├── include/libplacebo/*.h ← 头文件放这需手动建 include ├── CMakeLists.txt ← 改 ├── napi_init.cpp ← 改 └── types/libentry/Index.d.ts ← 改 └── src/main/ets/pages/Index.ets ← 改放文件这一步不需要写任何代码纯粹是「摆位置」。真正要动手改的是后面四个文件。四个文件怎么改1. CMakeLists.txt —— 告诉构建系统库在哪、怎么链核心就是把三方库声明成一个IMPORTED外部已有不用编译的库set(LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}) add_library(placebo SHARED IMPORTED) set_target_properties(placebo PROPERTIES IMPORTED_LOCATION ${LIBS_DIR}/libplacebo.so) include_directories(${NATIVERENDER_ROOT_PATH}/include) add_library(entry SHARED napi_init.cpp) target_link_libraries(entry PUBLIC libace_napi.z.so placebo)我自己记这段的逻辑add_library(IMPORTED)是「声明有这么个外部库」IMPORTED_LOCATION是「它在磁盘哪个位置」include_directories解决头文件搜索target_link_libraries把它和我的模块绑起来。换别的库只要替换库名和文件名即可。2. napi_init.cpp —— 写桥接函数这一层是体力活把每个想暴露给 ArkTS 的功能写成一个napi_value函数内部调用三方库 API再用napi_create_string_utf8之类把结果转回 JS 类型。最后在Init里用napi_property_descriptor数组把它们注册出去。我的建议是先只暴露一个最简单的「拿版本号」函数把链路打通确认能跑了再逐个加别一上来写一大堆。3. Index.d.ts —— 类型声明给 native 模块写 TS 声明函数名必须和 C 里注册的完全一致。不写也能跑但 ArkTS 里调用会是any类型没提示也没检查体验很差。4. Index.ets —— 前端调用importplfromlibentry.so;// ...this.reportpl.runAllTests();import xxx from libentry.so这个写法第一次见会有点意外记住「模块名 .so 后缀」即可。构建与真机验证Build Build Hap(s)然后 USB 连真机Run。几个高频报错我列一下对照报错我的判断config.h: No such file or directory头文件路径没配对检查include_directoriescannot find -lplacebo.so路径不对检查IMPORTED_LOCATIONundefined reference to pl_version链接漏了检查target_link_libraries运行时Cannot read property xxx of undefined八成是 SONAME 没修应用闪退.so的 NEEDED 依赖没打全我提炼的通用流程不管换成 OpenCV 还是 FFmpeg这套步骤都成立1. llvm-readelf -d 检查 NEEDED 和 SONAME 2. 修 SONAME带版本号的话 3. .so → entry/libs/arm64-v8a/ 4. 头文件 → entry/src/main/cpp/include/ 5. CMakeLists.txt 声明 IMPORTED 库 6. napi_init.cpp 写桥接 7. Index.d.ts 写类型 8. Index.ets 导入调用 9. Build Run小结这一篇把「产物 → 应用可用」的最后一公里走通了。和上一篇的交叉编译合起来就是一个三方库进入鸿蒙生态的完整闭环编出来 → 调进去。下一篇我会聊另一种集成场景——不在 DevEco而是在鸿蒙 PC 的 CodeArts IDE 里直接编译、签名、运行 libplacebo。感谢原创适配作者wei_shuo的分享。