前言
关于NAPI接口相关知识,之前我们介绍过NAPI同步异步接口使用方法、应用启动触发的ArkUI ets_runtime启动流程,从NAPI使用到整体流程给大家做了介绍,本次我们针对NAPI模块注册流程做深入介绍,给大家后续工作中开发、使用NAPI接口提供指导。
一、模块注册简介
NAPI模块注册是在系统框架层 与 应用层的相互配合下完成的,下面简要介绍一下大致流程。
首先,提供NAPI接口定义给应用层,一般是打包到SDK中,供应用开发者查询使用;
其次,NAPI接口在框架层实现其业务逻辑代码后,
最后,在编译脚本中定义模块对外接口方法,可以是静态库或者动态库,也可以是可执行文件方式,当前OpenHarmony库中NAPI模块,大多通过动态库方式加载。
对于应用层,首先引用需要的NAPI所在的库名,然后通过库名调用模块内相应的接口;
上面我们简要介绍了NAPI模块注册的流程,接下来我们对应用层如何触发NAPI模块加载、模块注册,以及系统框架层在收到加载、注册请求后如何处理,进而调用到引擎层面。
二、注册流程详解
1、模块注册
Ability线程初始化
应用hap包安装到设备后,启动应用程序时,通过foundation进程fork出应用进程,应用进程的主线程,根据包中的应用类型(FA或Stage)、 UI风格(js或ets)初始化Ability,我们以FA模型、ets UI为例,展开描述。
Ability初始化时,会判断当前Ability类型(AceAbility、PageAbility、ServiceAblity等),进而调用相应类型Ability的初始化,在AceAbility初始化时,需要先创建AceContainer,后续可以通过AceContainer获取包信息、窗口信息。
创建AceContainer时,需要初始化UI前端,以及初始化引擎,引擎初始化时,前端会拉起js线程,进而进入UI后端引擎初始化流程。
js线程初始化
js线程进行后端引擎初始化时,首先进行js Runtime初始化,在运行环境中创建js虚拟机vm,根据虚拟机创建NativeEngine。
NativeEgine会根据后端引擎类型,调用相应的子类NativeEgine,目前标准系统支持的后端引擎:QuickJS引擎、Ark引擎,编译选项可自定义引擎类型,此处我们以ark引擎为例讲解。
应用代码中的:
import XXX from "@ohos.xxx"
经过前端处理打包后,生成的代码为映射为:
globalThis.requireNapi("xxx")
创建后端ark引擎时,会定义requireNapi接口,接口中通过模块管理器加载模块。
加载模块时,首先从缓存中查找已加载的模块是否匹配,首次加载的模块缓存中是不存在的,查找失败;
缓存中查找失败后,则从硬盘中加载,首次加载均是从硬盘加载。
库加载成功后,根据已加载的nativeModule回调NAPI模块注册时定义的回调函数。
2、模块选择
模块选择时,首先从缓存的已加载模块中匹配是否存在需要的模块,若存在则直接用缓存的进行后续接口查找;
否则从硬盘中加载库,根据注册信息获取模块信息;
(1)FindNativeModuleByCache
从缓存中查找模块时,根据import模块名查找是否被load过(nm_modname),若查找不成功,则从硬盘中加载库;
否则,继续检查模块是否被加载过,若被加载过,则返回模块信息,进行后续接口处理;若未被加载,则要查找的模块插入已加载模块链表尾部;进行后续从硬盘中加载库;
(2)FindNativeModuleByDisk
从硬盘中加载库时,首先调用GetNativeModulePath获取对应的库路径,选路径时,首先将要查找的库名进行小写处理,然后获取匹配首选路径、备选路径(首先路径_napi),然后依次匹配,若查找成功,则会调用dlopen打开库,首次dlopen时,会调用库的构造回调进行已加载模块注册处理,将模块信息写到已加载模块链表中;
至此模块注册、查找流程结束。
总结
本文介绍了NAPI模块注册流程,后续大家开发中需要注意以下几点:
1.库名一定要小写。
2.模块名与库名要一致,大小写可不一致。
3.库名AA、AA_napi均能匹配成功,优先匹配AA。
4.应用首次调用接口时触发模块注册。