生成Harmony的library包在另外的Harmony HAP项目中使用
在Android开发中会使用到第三方提供的jar或者aar包,Harmony开发中也有类似的使用,是HSP或HAR包。HAP、HSP和HAR具体看官方说明developer.huawei.com/consumer/cn…
- 直接上流程,
- 先新建一个har的工程吧,这里Static Library对应的输出是HAR,贴图了
Next到下一步,按照图中打开Enable native,因为本文案例所提供的HAR包中包含了C++代码的so库文件作为HAR的功能提供给另外的项目工程使用
新建的工程模块下目录结构如下截图,其中红色框框为本文要写的几处代码(同时也要新建ets和cpp代码文件,后面会介绍),项目比较简单。
还是先简单介绍一下新建好的工程吧,工程里面有cpp下有一个Add方法的demo,在Arkts侧的MainPage.ets中有调用。鸿蒙官网有说明如何实现的逻辑,具体可以看一下cpp下的代码和结构,以及模块级别的oh-package.json5文件配置。 这里就要交代一下原文
HAR虽然不支持在配置文件中声明pages页面,但是可以包含pages页面,并通过命名路由的方式进行跳转。
- 开始写代码
- 首先工程配置上,在某块级别的build-profile.json5文件中abiFilters增加 "x86_64"和"arm64-v8a"(Mac端鸿蒙模拟器为x86),不配置的话根据官网说明默认是arm64-v8a。
buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
"abiFilters": [
"x86_64",
"arm64-v8a"
]
}
- 本文的HAR提供给另外鸿蒙项目点啥呢,整个两个数字的加减乘除运算吧
运算方法我用C++提供方法吧(毕竟C++干计算有优势),然后由Node-API作为接口,交给HAR的ArkTs侧提供给另外的鸿蒙项目使用。
首先在cpp/types/liblibrary/Index.d.ts里面按照add的葫芦写一下(会报红,先不管),opt就是我们要提供给ArkTs侧调用的方法,接收三个参数数字a,代表运算类型的字符串,数字b,返回一个运算结果
export const opt: (a: number,o: string, b: number) => number;
然后在cpp/napi_init.cpp中,继续按照里面的Add方法仿写,写一个Opt吧。这里也先说一下我的理解吧,首先这里#include "napi/native_api.h"是引入N-API相关头文件,结合Add的注释(见官网developer.huawei.com/consumer/cn…
)可以看出,napi_init.cpp(napi/native_api.h)中要干的事情就是把arkts的数据和c++的数据做转换/翻译,arkts给几个、什么类型的数据给C++了,并且转换成C++的数据类型。然后C++什么数据类型翻译成arkts的数据类型。
所以在napi_init.cpp中我只做翻译数据的工作,不做其他业务逻辑(加减乘除运算),业务逻辑交给处理业务逻辑C++文件代码干吧。
在下cpp目录下新建目录com/jee两个目录,然后在jee下面New->C++ Calss,命名Calculator,如图
C++的代码可以自行搜索一下C++入门之类的。Calculator.h和Calculator.cpp中代码如下
#ifndef MYAPPLICATION_CALCULATOR_H
#define MYAPPLICATION_CALCULATOR_H
class Calculator {
public:
Calculator();
double opt(double x,char *o, double y);
};
#endif //MYAPPLICATION_CALCULATOR_H
#include "Calculator.h"
#include <cstring> //strcmp 字符串比较
/**
* 构造函数
*/
Calculator::Calculator(){
}
/**
* C++ 计算
* @param x 第一个数字
* @param optChar 运算符
* @param y 第二个数字
* @return 计算结果
*/
double Calculator::opt(double x,char *optChar, double y){
double res = 0;
if (strcmp(optChar, "/") == 0) {
res = x/y;
} else if (strcmp(optChar, "+") == 0) {
res = x+y;
} else if (strcmp(optChar, "*") == 0) {
res = x*y;
} else if (strcmp(optChar, "-") == 0) {
res = x-y;
}
return res;
}
下面在napi_init.cpp中仿照里面的Add写一个Opt方法(我把Add的示例代码都删了),代码如下
#include "napi/native_api.h"// 引入N-API相关头文件。
#include "com/jee/Calculator.h"
/**
* 数据翻译工作
* @param env
* @param info
* @return
*/
static napi_value Opt(napi_env env, napi_callback_info info)
{
// 期望从ArkTS侧获取的参数的数量,这里是3个,两个数字,一个运算符(+、-、*、/)
size_t argc = 3;
napi_value args[3] = {nullptr};
// 从info中,拿到从ArkTS侧传递过来的参数,
//此处获取了三个ArkTS参数,即arg[0]第一个数字、arg[1]运算符和arg[2]第二个数字。
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
//要给Calculator传递的第一个数字valueFirst
double valueFirst;
napi_get_value_double(env, args[0], &valueFirst);
//获取字符串参数的长度
size_t typeLen = 0;
napi_get_value_string_utf8(env, args[1], nullptr, 0, &typeLen);
//要给Calculator传递的运算符optBuf
char *optBuf = new char[typeLen + 1];
napi_get_value_string_utf8(env, args[1], optBuf, typeLen + 1, &typeLen);
//要给Calculator传递的第一个数字valueSecond
double valueSecond;
napi_get_value_double(env, args[2], &valueSecond);
//创建一个Calculator对象calculator,
Calculator calculator;
//调用calculator的运算方法opt
double optSum = calculator.opt(valueFirst, optBuf, valueSecond);
//要返回给ArkTs侧的结果sum
napi_value sum;
//native侧业务逻辑处理结果optSum转换为ArkTS侧sum
napi_create_double(env, optSum, &sum);
return sum;
}
napi_init.cpp中还有一个重要代码,在Init方法中,需要我们的Opt方法暴露给ArkTs侧使用,代码如下
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "opt", nullptr, Opt, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
此时会发现cpp/types/liblibrary/Index.d.ts里面之前会报红的opt已经不报错了。还没完,此时Bulid-〉Make Module ‘library’依然会报错,需要在CMakeLists.txt里面add_library我们的Calculator.cpp源码,配置代码add_library(library SHARED napi_init.cpp com/jee/Calculator.cpp),其他不变。现在选中library模块然后Bulid-〉Make Module ‘library’,就可以看到下图
大功告成了,但是我们的Har包中的C++的opt方法是要给另外鸿蒙工程中的ArkTs使用,在我们的Har中我们还是要对外提供ArkTs的方法,所以我们还要包一层调用Native C++的opt的ArkTs代码。
在目录src/main/ets下新建目录utils,在utils目录下New->ArkTS File,命名Calc。Calc.ets代码直接贴图:
现在Calc.ets怎么暴露给另外的鸿蒙工程呢,继续看看“葫芦”(MainPage.ets)吧,这个MainPage.ets是如何暴露的。模块级别的library下有个Index.ets文件,仿照MainPage写个吧,代码
export { opt } from './src/main/ets/utils/Calc'
交代一下,这个Index.ets是被配置在模块级别library下的oh-package.json5,"main": "Index.ets"。
上面我们的so库文件和Index.d.ts是被配置在src/main/cpp/types/liblibrary/oh-package.json5,可以自己去鸿蒙官网看一下说明。
现在再次选中library模块然后Bulid-〉Make Module ‘library’,在build/default/outputs/default得到library.har。
- 现在创建一个新的鸿蒙工程(Empty Ability)TestApplication,在entry下新建一个libs目录,把上面的library.har复制到libs下。然后在模块级别的entry下oh-package.json5文件加入dependencies
在src/main/ets/pages/Index.ets中代码调用
import { opt } from 'library';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State x: number = 4;
@State y: number = 12;
@State opt: string = '+';
build() {
RelativeContainer() {
Text(this.message)
.id('HelloWorld')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
}).onClick(()=>{
this.message = `${this.x}${this.opt}${this.y}=${opt(this.x,this.opt,this.y)}`
})
}
.height('100%')
.width('100%')
}
}
run到模拟器中结果显示就是4+12=16.
C++中的日志
这里我想看一下C++中的日志,怎么办。就需要在提供HAR包的工程中使用到libhilog_ndk.z.so
src/main/cpp/CMakeLists.txt中target_link_libraries加上libhilog_ndk.z.so,完整代码如下
在Calculator.cpp中使用日志#include <hilog/log.h>,代码截图
现在再次选中library模块然后Bulid-〉Make Module ‘library’,在build/default/outputs/default得到library.har。重新把library.har复制到TestApplication鸿蒙工程的libs下。
这里先File->Sync and Refresh Project一下。
run到模拟器中。Log日志
结束!