如何提供Harmony的HAR包(仿Android开发中提供的jar或者aar包,及控制台Log查看C++中日志)

623 阅读6分钟

生成Harmony的library包在另外的Harmony HAP项目中使用

在Android开发中会使用到第三方提供的jar或者aar包,Harmony开发中也有类似的使用,是HSP或HAR包。HAP、HSP和HAR具体看官方说明developer.huawei.com/consumer/cn…

  1. 直接上流程,
  • 先新建一个har的工程吧,这里Static Library对应的输出是HAR,贴图了

image.png

Next到下一步,按照图中打开Enable native,因为本文案例所提供的HAR包中包含了C++代码的so库文件作为HAR的功能提供给另外的项目工程使用 image.png

新建的工程模块下目录结构如下截图,其中红色框框为本文要写的几处代码(同时也要新建ets和cpp代码文件,后面会介绍),项目比较简单。 image.png

还是先简单介绍一下新建好的工程吧,工程里面有cpp下有一个Add方法的demo,在Arkts侧的MainPage.ets中有调用。鸿蒙官网有说明如何实现的逻辑,具体可以看一下cpp下的代码和结构,以及模块级别的oh-package.json5文件配置。 这里就要交代一下原文

HAR虽然不支持在配置文件中声明pages页面,但是可以包含pages页面,并通过命名路由的方式进行跳转。

  1. 开始写代码
  • 首先工程配置上,在某块级别的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,如图 WechatIMG17.jpg

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’,就可以看到下图

image.png

大功告成了,但是我们的Har包中的C++的opt方法是要给另外鸿蒙工程中的ArkTs使用,在我们的Har中我们还是要对外提供ArkTs的方法,所以我们还要包一层调用Native C++的opt的ArkTs代码。

在目录src/main/ets下新建目录utils,在utils目录下New->ArkTS File,命名Calc。Calc.ets代码直接贴图: image.png 现在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。

  1. 现在创建一个新的鸿蒙工程(Empty Ability)TestApplication,在entry下新建一个libs目录,把上面的library.har复制到libs下。然后在模块级别的entry下oh-package.json5文件加入dependencies

image.png 在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,完整代码如下 image.png

在Calculator.cpp中使用日志#include <hilog/log.h>,代码截图 image.png

现在再次选中library模块然后Bulid-〉Make Module ‘library’,在build/default/outputs/default得到library.har。重新把library.har复制到TestApplication鸿蒙工程的libs下。

这里先File->Sync and Refresh Project一下。

run到模拟器中。Log日志 image.png 结束!