鸿蒙系列--动态共享包的依赖与使用

一、前言

HarmonyOS的共享包相当于Android的Library,在HarmonyOS中,给开发者提供了两种共享包,HAR(Harmony Archive)静态共享包,和HSP(Harmony Shared Package)动态共享包

区别:

  • 静态共享包中的代码和资源跟随使用方编译,如果有多个使用方,它们的编译产物中会存在多份相同拷贝
  • 动态共享包中的代码和资源可以独立编译,运行时在一个进程中代码也只会存在一份

动态共享包解决的问题:

  • 多个使用方引用相同的共享包,导致的APP包大小膨胀问题
  • 多个使用方引用相同的共享包,共享包中的一些状态变量无法共享的问题

两者的使用场景:

  • 仅用于应用内部代码、资源的共享,建议使用动态共享包
  • 作为应用模块的依赖项被引用,就可以选择静态共享包

二、共享包的创建

File -> New -> Module

有两种共享包,一种是一种是动态共享包Shared Library,一种是静态共享包Static Library

选择一种共享包,点击Next

设置共享包的name,点击Finish,即可完成共享包的创建

动态共享包创建完毕之后,其type类型为【shared】,如果你创建的是静态共享包,这里的类型就是【har】

**三、**动态共享包添加依赖

动态共享包创建完成之后,有两个Module,主Module【entry】和动态共享包【Common】

如何在【entry】中调用【Common】模块中的代码和资源文件等,需要让【entry】关联依赖上【Common】

要使用HSP中的接口,首先需要在使用方的oh-package.json5中配置对它的依赖

1、依赖方式一

在【entry】中的oh-package.json5 文件中,在dependencies中引入共享包【Common】

引入格式:

'folder ': "file:../folder"

描述:

  • 后面的folder就是创建的共享包名称,比如这里的Common
  • 前面的folder是用来生成的映射目录,可与共享包名称,也可以自行定义

添加了之后需要同步项目,点击【Sync Now 】即可,也可以点击提示信息下的【Run 'ohpm install'】

同步之后,该模块就会被映射到Module【entry】的oh_modules目录下

2、依赖方式二

也可以使用@xx/xx来添加依赖

引入格式:

"@xx/xx": "file:../Common"

比如:import { add } from '@ohos/Common'

同步之后会在oh_modules目录下创建ohos>Common

3、依赖方式三

除了以上手动方式添加依赖之外,也可以使用命令的方式进行实现,命令行中或在IDE Terminal窗口中,目录进入到主模块下,执行ohpm install ../folder 命令,folder是你的共享包

apple@lengfeng MyApplication % cd entry

apple@lengfeng entry % ohpm install ../Common

**注意:**需要提前配置ohpm

命令执行完毕之后,也会自动的在oh-package.json5里添加依赖,并生成映射文件

四、动态共享包调用方式

1.方法调用

在创建的共享包Common中,有一个自动创建一个工具类Calc,里面有一个求和方法add

使用的时候需要引入:

import { add } from 'common/src/main/ets/utils/Calc'

//或者第二种依赖方式导包

import { add } from '@ohos/Common'

使用如下:

TypeScript 复制代码
import { add } from 'common/src/main/ets/utils/Calc'
//或者
//import { add } from '@ohos/Common'
//或者
//import { add } from 'common'


@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            var result = add(1, 2)
            this.message = "result=" + result
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

案例中是给一个Text增加一个点击事件,然后调用【Common】中的Calc类的add方法,返回一个结果,并显示更新Text

预览是一片空白的,没关系,直接运行到模拟器,或者HarmonyOS手机上查看,没想到报错了

根据报错信息提示:未执行部署多个包,由于增加了一个【Common】共享包,解决方案是

选择上面运行模块,选择Edit Configurations

Deploy Multi Hap 标签页,勾选**Deploy Multi Hap Packages,**然后选择新增的共享包即可,将entry和library模块一起运行

然后就能正常运行了

点击文本,就能看到计算后的结果了

2.类的调用

调用共享包中的工具类

在共享包中定义一个工具类Log.ts,需要用export关键字进行对外暴露

TypeScript 复制代码
export class Log {
  static i(msg: string) {
    console.info(msg)
  }

  static e(msg: string) {
    console.error(msg)
  }
}

然后在【common】的Index添加导出Log,对外暴露的接口,需要在入口文件index.ets中声明

在【entry】中导入类,就可以直接使用了

TypeScript 复制代码
import { add,Log } from 'common'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            var result = add(1, 2)
            this.message = "result=" + result
            Log.i("----------------")
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

点击Text后打印出日志:

3.组件的调用

组件的调用跟类的调用一致

先export导出,然后import导入

TypeScript 复制代码
@Component
export struct CommonText {
  @State message: string = '我是Common模块中的组件'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.Red)
      }
      .width('100%')
    }
  }
}
TypeScript 复制代码
import { add, Log, CommonText } from 'common'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            var result = add(1, 2)
            this.message = "result=" + result
            Log.info("----------------")
          })
        CommonText()
      }
      .width('100%')
    }
    .height('100%')
  }
}

效果图:

4.页面路由跳转

想在【entry】模块中,添加一个按钮跳转至【Common】模块中的CommonIndex页面(路径为:Common/src/main/ets/pages/CommonIndex.ets),那么可以在使用方的代码(entry模块下的Index.ets,路径为:entry/src/main/ets/pages/Index.ets)里这样使用:

TypeScript 复制代码
import { add, Log, CommonText } from 'common'
import router from '@ohos.router'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            var result = add(1, 2)
            this.message = "result=" + result
            Log.info("----------------")
          })
        CommonText()
          .onClick(() => {
            router.pushUrl({ url: '@bundle:com.lf.myapplication/Common/ets/pages/CommonIndex' })
              .then(() => {
                console.log("push page success");
              })
              .catch(err => {
                console.error(`pushUrl failed, code is ${err.code}, message is ${err.message}`);
              })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

其中router.pushUrl方法的入参中url的内容为:

'@bundle:com.lf.myapplication/Common/ets/pages/CommonIndex'

内容格式为:

'@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)'

包名的查看路径:

AppScope -> app.json5中可以查看app的信息,包括包名,版本code、name等

效果图:

点击 CommonText()组件跳转到【Common】模块中的CommonIndex页面

5.资源访问

创建资源目录:

选择模块名 > 右击 > New > Resource File

  • 可同时创建资源目录和资源文件,文件默认创建在base目录的对应资源组。如果选择了限定词,则会按照命名规范自动生成限定词和资源组目录,并将文件创建在限定词目录中
  • 图中File name为需要创建的文件名。Resource type为资源组类型,默认是element。Root Element为资源类型。Avaliable qualifiers为供选择的限定词目录,通过右边的小箭头可添加或者删除
创建资源文件

在资源目录(element、media、profile)的右键菜单选择"New > XXX Resource File",即可创建对应资源组目录的资源文件。例如,在element目录下可新建Element Resource File

资源包内资源访问
  • 对于应用资源,在工程中,通过"$r('app.type.name')"形式引用。其中,app为应用内resources目录中定义的资源;type为资源类型或资源的存放位置,取值包含"color"、"float"、"string"、"plural"、"media";name为资源命名,由开发者定义资源时确定

  • 对于rawfile目录资源,通过"$rawfile('filename')"形式引用。其中,filename为rawfile目录下文件的相对路径,文件名需要包含后缀,路径开头不可以以"/"开头

  • 对于rawfile目录的descriptor,可通过资源管理的getRawId接口引用,其返回值descriptor.fd为hap包的fd。此时,访问rawfile文件需要结合{fd, offset, length}一起使用

TypeScript 复制代码
Text($r('app.string.string_hello'))
  .fontColor($r('app.color.color_hello'))
  .fontSize($r('app.float.font_hello'))


//引用string.json资源。Text中$r的第一个参数指定string资源,第二个参数用于替换string.json文件中的%s
//"这是原文本,可以拼接一个:%s"
Text($r('app.string.message_arrive', "拼接文本"))

// media资源的$r引用
Image($r('app.media.my_background_image'))  

// rawfile$r引用rawfile目录下图片
Image($rawfile('test.png'))                 

// rawfile$r引用rawfile目录下图片
Image($rawfile('newDir/newTest.png'))       
  • 对于系统资源,可以通过"$r('sys.type.resource_id')"的形式引用。其中,sys为系统资源;type为资源类型,取值包括"color"、"float"、"string"、"media";resource_id为资源id
TypeScript 复制代码
Text('Hello')
  .fontColor($r('sys.color.ohos_id_color_emphasize'))
  .fontSize($r('sys.float.ohos_id_text_size_headline1'))
  .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
  .backgroundColor($r('sys.color.ohos_id_color_palette_aux1'))

Image($r('sys.media.ohos_app_icon'))
  .border({
    color: $r('sys.color.ohos_id_color_palette_aux1'),
    radius: $r('sys.float.ohos_id_corner_radius_button'), width: 2
  })
  .margin({
    top: $r('sys.float.ohos_id_elements_margin_horizontal_m'),
    bottom: $r('sys.float.ohos_id_elements_margin_horizontal_l')
  })
  .height(200)
  .width(300)
跨包访问资源

**注意:**HarmonyOS目前还不支持资源跨包调用

如果确实需要使用共享包中的资源,可以另辟蹊径。

既然资源不能暴露,但是类和方法可以暴露,也就是可以把资源中的属性,通过工具类做一层中转即可

1.定义资源

在【Common】中有一个字符串资源message_arrive,想要在【entry】中使用,如何实现呢?

2.定义工具类

定义一个工具类中转 StringUtil.ets,就可以拿到对应的资源文件了

TypeScript 复制代码
export class StringUtil {
  static getArriveMessage(): Resource {
    return $r('app.string.message_arrive')
  }
}
3.调用

按照之前的方式导包,然后调用工具类的方法即可

Text(StringUtil.getArriveMessage('可以拼接文本'))

TypeScript 复制代码
import { add, Log, CommonText, StringUtil } from 'common'
import router from '@ohos.router'

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            var result = add(1, 2)
            this.message = "result=" + result
            Log.info("----------------")
          })
        CommonText()
          .onClick(() => {
            router.pushUrl({ url: '@bundle:com.lf.myapplication/Common/ets/pages/CommonIndex' })
              .then(() => {
                console.log("push page success");
              })
              .catch(err => {
                console.error(`pushUrl failed, code is ${err.code}, message is ${err.message}`);
              })
          })

        Text(StringUtil.getArriveMessage('可以拼接文本'))
      }
      .width('100%')
    }
    .height('100%')
  }
}

效果图:

五、跨包使用需要注意点:

  • 要使用HSP中的接口,需要在使用方的oh-package.json5中配置对它的依赖
  • 跨包使用的接口都需要添加export。对外暴露的接口,需要在入口文件index.ets中声明,同一个类的多个方法,可以写在一起,用,隔开
  • 新增的共享包需要跨包调用,需要在Edit Configurations中添加新增的共享包
相关推荐
小冷爱学习!42 分钟前
华为动态路由-OSPF-完全末梢区域
服务器·网络·华为
2501_904447741 小时前
华为发力中端,上半年nova14下半年nova15,大力普及原生鸿蒙
华为·智能手机·django·scikit-learn·pygame
MarkHD2 小时前
第十八天 WebView深度优化指南
华为·harmonyos
塞尔维亚大汉3 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI CSI】
harmonyos·领域驱动设计
别说我什么都不会3 小时前
鸿蒙轻内核M核源码分析系列十五 CPU使用率CPUP
操作系统·harmonyos
feiniao86514 小时前
2025年华为手机解锁BL的方法
华为·智能手机
塞尔维亚大汉5 小时前
OpenHarmony(鸿蒙南向)——平台驱动开发【I3C】
harmonyos·领域驱动设计
VVVVWeiYee5 小时前
BGP配置华为——路径优选验证
运维·网络·华为·信息与通信
今阳7 小时前
鸿蒙开发笔记-6-装饰器之@Require装饰器,@Reusable装饰器
android·app·harmonyos
余多多_zZ7 小时前
鸿蒙初学者学习手册(HarmonyOSNext_API14)_组件截图(@ohos.arkui.componentSnapshot (组件截图) )
学习·华为·harmonyos·鸿蒙·鸿蒙系统