#星光计划2.0# OpenHarmony 源码解析之JavaScriptAPI-NAPI实践 原创 精华
作者:卞绍雷
【本文正在参与51CTO HarmonyOS技术社区创作者激励计划-星光计划2.0】
1 简介
开源鸿蒙(OpenHarmony)的APP开发框架是ACE,开发语言是JS/eTS。有时候需要增加一些额外功能,依赖现有的C/C++ 开源库,或者遇到一些CPU密集计算的场合,就需要使用C/C++ 语言来编写更底层的函数,供上层JS调用。
OpenHarmony提供了统一的NAPI接口函数,通过编译系统的裁剪,方便增加新的JS功能模块。
本文以最简单的NAPI接口函数为例,详细说明在OpenHarmony系统如何编写模块文件、本地调试、系统集成、上机测试。
1.1 UI架构相关系列
《OpenHarmony 源码解析之ACE (JavaScript运行环境初始化)》
《OpenHarmony 源码解析之JavaScript API框架(NAPI)》
《OpenHarmony 源码解析之JavaScript API框架(NAPI-C接口)》
《OpenHarmony 源码解析之JavaScript API框架(NAPI实践)》
《OpenHarmony 源码解析之JavaScript(文件管理API)》
1.2 OpenHarmony架构图
1.3 JS UI架构
JS UI框架包括应用层(Application)、前端框架层(Framework)、引擎层(Engine)和平台适配层(Porting Layer),其架构如下图所示:
2 快速实现
建立模块目录,编写基础编译文件
-
模块目录理论上可以建立在OpenHarmony代码库的任何地方,为行文方便,假设OpenHarmony代码库的目录为
OHOS_SRC
,在OHOS_SRC
目录下,建立此次测试模块目录:myapp
。 -
此时,
OHOS_SRC
目录下应该有 ark, foundation, device, …, myapp 等目录,其中myapp就是刚刚建立的,在myapp目录下,建立以下文件:|-- BUILD.gn |-- app.cpp |-- ohos.build
-
import("//build/ohos.gni") ohos_shared_library("myapp") { # 指定编译源文件 sources = [ "app.cpp", ] # 指定编译依赖,如果依赖第三方库,需要在此添加 deps = [ "//foundation/ace/napi:ace_napi" ] # 指定库生成的路径 relative_install_dir = "module" # 子系统及其组件,后面会引用 subsystem_name = "myapp" part_name = "myapp_part" }
-
最终会生成
system/lib/module/libmyapp.z.so
,并且在APP中:import myapp from '@ohos.myapp'
-
这几处的myapp都是统一名称:
“module_list”: [ “//myapp:myapp” ]
//myapp
指的是myapp
目录,:myapp
指的是上面BUILD.gn
中的目标ohos_shared_library("myapp")
-
ohos.build:
{ "subsystem": "myapp", "parts": { "myapp_part": { "module_list": [ "//myapp:myapp" ], "test_list": [ ] } } }
-
app.cpp:
#include <assert.h> #include "napi/native_api.h" #include "napi/native_node_api.h" static napi_value Method(napi_env env, napi_callback_info info) { napi_status status; napi_value world; status = napi_create_string_utf8(env, "Hello, world!", 13, &world); assert(status == napi_ok); return world; } static napi_value Init(napi_env env, napi_value exports) { napi_status status; napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("hello", Method), }; status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); assert(status == napi_ok); return exports; } NAPI_MODULE(myapp, Init)
-
这里只简单写了一个JS模块,只有一个hello函数,返回"Hello, world!"
字符串。
3 本地测试
-
利用
node-gyp
进行本地测试,先确保系统安装了node.js
。node --version
-
在myapp目录下,建立test目录,然后编写binding.gyp和test.js文件:
|-- BUILD.gn |-- app.cpp |-- ohos.build `-- test |-- binding.gyp `-- test.js
-
binding.gyp:
按自己系统的实际情况,填写编译器、源代码(sources)、头文件目录(include_dirs)、依赖库(dependencies)、编译参数(cflags、cflags_cc)、链接参数(link_settings: libraries)。
这里的目标名称(target_name)就是下一步test.js引用测试的名称。
{ 'targets': [ { 'cc': 'clang', 'c++': 'clang++', 'target_name': 'test-native', 'sources': [ '../app.cpp'], 'include_dirs': ["/OHOS_SRC/foundation/ace/napi/interfaces/kits"], 'dependencies': [], 'cflags!': [ '-DTESTDEBUG', '-std=gnu2x' ], 'cflags_cc': [ '-DTESTDEBUG', '-std=c++17' ], 'link_settings': { 'libraries': [''] }, } ] }
-
接下来,确保系统安装了
node-gyp
node-gyp --version
如果系统没有安装,那么在测试目录下临时安装也是可以的。
cd OHOS_SRC/myapp/test
npm install node-gyp
./node_modules/.bin/node-gyp --version运行如下命令,确保app.cpp文件无语法错误,可以正确通过编译链接。
cd OHOS_SRC/myapp/test
node-gyp configure
node-gyp build之后如果修改了
binding.gyp
文件,需要node-gyp rebuild
, -
test.js:
var myapp = require('./build/Release/test-native') console.log(myapp) console.log(myapp.hello) console.log(myapp.hello())
-
如果编译正常,那么就可以进行本地测试了:
node test.js
4 集成
集成到系统,在本地测试通过后,各种功能看起来正常,那么就可以集成到OpenHarmony系统,烧录上机测试了。
集成到OpenHarmony的步骤参考鸿蒙子系统的集成步骤:标准系统编译构建指导
这里简单描述一下:
-
在
OHOS_SRC/build/subsystem_config.json
文件中,增加(注意前后逗号,保持文件格式正确):"myapp": { "project": "hmf/myapp", "path": "myapp", "name": "myapp", "dir": "" }
-
在产品配置中添加上述子系统的功能模块,编译到产品产出文件中(注意前后逗号,保持文件格式正确)
OHOS_SRC/productdefine/common/products/产品名称.json
“myapp:myapp_part”:{}
-
即可开始编译。
./build.sh --product-name 产品名称
-
编译完成后,可以在
OHOS_SRC/out
目录找到生成的.so
文件。root@1fe862aba551:/home/openharmony# find out -name 'libmyapp*' out/ohos-arm-release/packages/phone/NOTICE_FILES/system/lib/module/libmyapp.z.so.txt out/ohos-arm-release/packages/phone/system/lib/module/libmyapp.z.so out/ohos-arm-release/lib.unstripped/myapp/myapp_part/libmyapp.z.so out/ohos-arm-release/myapp/myapp_part/libmyapp.z.so
镜像输出在 out/ohos-arm-release/packages/phone/images/
目录下。
5 上机测试及小技巧
第一次编写完成后,需要烧录镜像文件。之后再修改,就可以利用hdc
工具,只上传.so
文件覆盖原文件即可。
hdc.exe file send libmyapp.z.so system/lib/module/libmyapp.z.so
编写测试HAP:
import myapp from '@ohos.myapp'
export default {
testGetAppName() {
console.log(myapp.hello())
}
}
假设测试APP的包是com.example.testmyapp,可以使用hdc工具很方便进行的安装、启动、关闭APP等操作。
安装:
hdc install -r 安装包的本地路径.hap
卸载:
hdc uninstall com.example.testmyapp
列出已经安装的包:
hdc shell bm dump -a
启动:
hdc shell aa start -b com.example.testmyapp -a com.example.testmyapp.MainAbility
关闭:
hdc shell killall com.example.testmyapp
hdc工具查看日志,可以根据进程号只看测试进程的,这样就更清晰方便了。:
hdc.exe shell
ps -elf |grep com.example.testmyapp # 输出的第二列是pid
hilog -P pid #这里的pid是上面第二列的数字
6 小结
OpenHarmony系统的ACE框架已经具备了基础的APP功能,可以很方便的利用NAPI扩展来增强APP,补充JS的不足之处。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
感谢老师分享
请问为啥第一次需要完整烧录,系统内部是如何加载js的相关方法的? 我看了下源码,就是在system/lib/module 中直接加载的相关方法的,不知道理解有没有后问题。
对着文章测试发现 app.cpp文件里:
要把 下面二个路径写全 才编译成功;
#include "napi/native_api.h" 改成实际的路径
#include "napi/native_node_api.h" 改成实际的路径
你是怎么改的,我编译的时候说napi/native_api.h文件不存在。