应用间跳转

应用间跳转概念与场景

应用间跳转其实就是指从一个应用直接跳转至易外一个应用,传递相应的数据,执行特定的功能。应用间跳转优势:通过统一链接协议和系统级路由,实现一键直达,让用户流畅切换应用,不仅能提升效率和满意度,还提高了应用转化率与留存率。

典型场景一:社交分享跳转。用户在社交应用中看到感兴趣的内容(文章、图片、视频等),分享给好友,好友通过链接直接打开社交应用的指定页面。

典型场景二:广告跳转。用户在浏览器、社交媒体或其他渠道看到广告,点击后直达应用内的商品详情页。

典型场景三:特殊文本识别跳转。应用能识别聊天内容、邮件或文档中的特殊文本 (例如地址、电话号码、日期等),点击后直接调用相应系统应用进行操作。

应用间跳转实现方案

根据目标应用的确定性,应用间跳转可分为两大类:

  1. 拉起指定应用:直接跳转到指定应用及其具体页面。
  2. 拉起指定类型应用:按功能意图让系统推荐可承接任务的应用,用户自主选择。

拉起指定应用-应用链接跳转

拉起指定应用是指明确指定目标应用进行跳转的场景,系统提供了指定应用链接拉起应用的能力。应用链接是指可以将用户引导至应用内特定位置或相关网页的URL。按照校验机制分为App Linking和Deep Linking两种方式。

  • App Linking:其限定了链接格式必须为https,同时通过增加域名校验机制可以从已匹配到的应用中筛选过滤出目标应用,消除应用查询和定位中产生的歧义,直达受信的目标应用。
  • Deep Linking:通过链接跳转至应用特定页面的技术,其特点是支持开发者定义任意形式的链接格式。由于缺乏域名校验机制,容易被其他应用所仿冒。
实现机制:
  • 目标应用在配置文件中注册自己的URL,并对外提供URL。
  • 拉起方应用在跳转接口中传入目标应用的URL等信息。
  • 系统接收到URL等相关信息,会寻找对应匹配项,并跳转至目标应用。
跳转系统应用

为了让开发者快捷地实现系统应用跳转,系统提供了一些能力和接口,在确保访问安全的前提下,可以直接跳转系统应用,例如跳转设置、应用市场、钱包、电话、日历、联系人等系统应用。

提供以下两种实现方案:

方案一:使用系统Picker组件

相机、文件管理、联系人等系统应用提供了系统Picker组件,支持开发者无需申请权限,即可使用系统应用的一些常用功能,比如访问用户的资源文件。

方案二:使用特定接口

设置、电话、日历等应用提供了一些接口,例如:电话提供了makeCall接口,钱包提供了requestPayment接口,日历提供了addEvent接口等,通过这些接口可以直接跳转系统应用。

拉起指定类型应用

在某些场景下,开发者并不指定某个具体应用,而是希望基于用户意图而非特定应用实现功能,例如使用任意一款支持的地图应用导航。

拉起垂类面板实现方案:

通过startAbilityByType接口拉起垂类面板:调用startAbilityByType接口拉起对应的垂域面板(目前支持拉起导航、金融、邮件、航班、快递类应用面板),该面板将展示目标方接入的垂域应用,由用户选择打开指定应用以实现相应的垂类意图。

拉起其他应用:

通过mailto方式跳转电子邮件应用:通过mailto电子邮件协议,可以创建指向电子邮件地址的超链接,方便用户通过网页或应用中的超链接直接跳转电子邮件应用。

通过startAbility接口打开文件:开发者可以通过调用startAbility接口,由系统从已安装的应用中寻找符合要求的应用,打开特定类型的文件。

场景实现:社交分享

本节主要是学习App Linking的概念及开发步骤

AppLinking三种典型跳转场景

社交分享跳转的实现主要是依靠系统提供的App Linking技术,而AppLinking支持三种典型跳转场景,根据用户设备是否安装目标应用智能跳转。

场景一:目标应用已安装

用户点击分享链接后,系统直接拉起目标应用并定位到内容详情页,无需经过浏览器中转,实现一键直达,极大提高便捷度和转化率。

场景二:目标应用未安装,但开发者配置了直达应用市场功能

当用户未安装目标应用且开发者配置了直达应用市场功能时,点击链接将直接跳转到应用市场的应用详情页。安装完成后,首次打开应用将通过延迟链接功能自动导航至原始分享内容,无需用户重新搜索或操作。

场景三:目标应用未安装,未配置直达应用市场(有Web页面)

当用户未安装目标应用且开发者未配置直达应用市场功能时,用户点击链接后,系统通过浏览器打开Web页面,用户可直接查看内容。开发者在Web页面可提供“下载”按钮,引导用户安装应用获取更佳体验,安装后仍可通过延迟链接直达原内容。

App Linking实现原理

Stage模型应用程序包结构

为了让开发者能对应用程序包在不同阶段的形态有更加清晰的认知,分别对开发态、编译态、发布态的应用程序结构展开介绍。

开发态包结构

在DevEco Studio上创建项目工程,并尝试创建多个不同类型的Module。根据实际工程中的目录对照本章节进行学习,有助于理解开发态的应用程序结构。

图1 项目工程结构示意图(以实际为准)

说明

  • AppScope目录由DevEco Studio自动生成,该目录名称更改会导致当前目录下配置文件和资源加载失败,导致编译报错问题,因此该目录名称请勿修改。
  • Module目录名称可以由DevEco Studio自动生成(比如entry、library等),也可以自定义。为了便于说明,下表中统一采用ModuleName表示

工程结构主要包含的文件类型及用途如下:

文件类型 说明
配置文件

包括应用级配置信息、以及Module级配置信息:

AppScope > app.json5app.json5配置文件,用于声明应用的全局配置信息,比如应用Bundle名称、应用名称、应用图标、应用版本号等。

ModuleName > src > main > module.json5module.json5配置文件,用于声明Module基本信息、支持的设备类型、所含的组件信息、运行所需申请的权限等。

ArkTS源码文件 ModuleName > src > main > ets:用于存放Module的ArkTS源码文件(.ets文件)。
资源文件

包括应用级资源文件、以及Module级资源文件,支持图形、多媒体、字符串、布局文件等,详见资源分类与访问

AppScope > resources :用于存放应用需要用到的资源文件。

ModuleName > src > main > resources :用于存放该Module需要用到的资源文件。

其他配置文件

用于编译构建,包括构建配置文件、编译构建任务脚本、混淆规则文件、依赖的共享包信息等。

build-profile.json5工程级Module级的构建配置文件,包括应用签名、产品配置等。

hvigorfile.ts:工程级或Module级的编译构建任务脚本,开发者可以自定义编译构建工具版本、控制构建行为的配置参数。

obfuscation-rules.txt:混淆规则文件。混淆开启后,在使用Release模式进行编译时,会对代码进行编译、混淆及压缩处理,保护代码资产。

oh-package.json5:用于存放依赖库的信息,包括所依赖的三方库和共享包。

编译态包结构

不同类型的Module编译后会生成对应的HAP、HAR、HSP等文件,编译后可通过DevEco Studio或打包工具打包成APP包,用于上架应用市场。编译HAP和HSP时,会把它们所依赖的HAR直接编译到HAP和HSP中,因此打包成APP包后,编译打包视图中只有.hap和.hsp文件,没有.har文件。开发态视图与编译态视图的对照关系如下:

图2 开发态与编译态的工程结构视图

从开发态到编译态,Module文件变更如下

  • ets目录:ArkTS源码编译生成.abc文件。
  • resources目录:AppScope目录下的资源文件会合入到Module下面资源目录中,如果两个目录下存在重名文件,编译打包后只会保留AppScope目录下的资源文件。
  • module配置文件:AppScope目录下的app.json5文件字段会合入到Module下面的module.json5文件之中,编译后生成HAP或HSP最终的module.json文件。

发布态包结构

每个应用中至少包含一个.hap文件,可能包含若干个.hsp文件、也可能不含,一个应用中的所有.hap与.hsp文件合在一起称为Bundle,其对应的bundleName是应用的唯一标识(详见app.json5配置文件中的bundleName标签)。

当应用发布上架到应用市场时,需要将Bundle打包为一个.app后缀的文件用于上架,这个.app文件称为App Pack(Application Package),与此同时,DevEco Studio工具会自动生成一个pack.info文件。pack.info文件描述了App Pack中每个HAP和HSP的属性,包含APP中的bundleName和versionCode信息、以及Module中的name、type和abilities等信息。

说明

  • App Pack是发布上架到应用市场的基本单元。
  • 应用签名时,是以HAP/HSP/APP为单位进行签名的;在云端分发、端侧安装时,是以HAP/HSP为单位进行分发和安装的。

图3 编译发布与上架部署流程图

HSP

HSP(Harmony Shared Package)是动态共享包,包含代码、C++库、资源和配置文件,通过HSP可以实现代码和资源的共享。HSP不支持独立发布上架,而是跟随宿主应用的APP包一起发布,与宿主应用同进程,具有相同的包名和生命周期。

说明

  • 应用内HSP:在编译过程中与应用包名(bundleName)强耦合,只能给某个特定的应用使用。

  • 集成态HSP:构建、发布过程中,不与特定的应用包名耦合;使用时,工具链支持自动将集成态HSP的包名替换成宿主应用包名,并且会重新签名生成一个新的HSP包,作为宿主应用的安装包,这个新的HSP也属于宿主应用HAP的应用内HSP。

  • 指南和API参考文档中如无特殊说明,默认HSP都为应用内HSP。

使用场景

  • 多个HAP/HSP共用的代码和资源放在同一个HSP中,可以提高代码、资源的可重用性和可维护性,同时编译打包时也只保留一份HSP代码和资源,能够控制应用包的大小

  • HSP在运行时按需加载,有助于提升应用性能。

  • 同一个组织内部的多个应用之间,可以使用集成态HSP实现代码和资源的共享

约束限制

  • HSP不支持在设备上单独安装/运行,需要与依赖该HSP的HAP一起安装/运行。在安装或更新时,多模块之间存在校验,详情参考一致性校验。使用打包工具进行打包时,会进行合法性校验,详情请参考打包工具
  • 从API version 14开始HSP支持在配置文件中声明UIAbility组件,但不支持具有入口能力的UIAbility(即skill标签配置了entity.system.home和ohos.want.action.home)。配置UIAbility的方法参考模块中添加UIAbilityHSP中UIAbility的启动方式与应用内启动UIAbility方法相同。API version 13及之前版本,不支持在配置文件中声明UIAbility组件。
  • 从API version 18开始HSP支持在配置文件中声明ExtensionAbility组件,但不支持具有入口能力的ExtensionAbility(即skill标签配置了entity.system.home和ohos.want.action.home)。HSP中配置ExtensionAbility的方法参考模块中添加ExtensionAbility。 API version 17及之前版本,不支持在配置文件中声明ExtensionAbility组件。
  • HSP可以依赖其他HAR或HSP,也可以被HAP或者HSP依赖集成,但不支持循环依赖,也不支持依赖传递

说明

循环依赖:例如有三个HSP,HSP-A、HSP-B和HSP-C,循环依赖指HSP-A依赖HSP-B,HSP-B依赖HSP-C,HSP-C又依赖HSP-A。

依赖传递:例如有三个HSP,HSP-A、HSP-B和HSP-C,依赖关系是HSP-A依赖HSP-B,HSP-B依赖HSP-C。不支持传递依赖指HSP-A可以使用HSP-B的方法和组件,但是HSP-A不能直接使用HSP-C的方法和组件。

目录结构

使用DevEco Studio创建一个用于调用C++代码的HSP模块。并在“Configure New Module”页面中启用“Enable native”选项。详见创建HSP模块,以创建一个名为library的HSP模块为例。基本的工程目录结构如下:

MyApplication
├── library
│   ├── src
│   │   └── main
|   |       ├── cpp
|   |       |   ├── CMakeLists.txt    //C++代码编译的配置文件
|   |       |   └── napi_init.cpp     //NAPI模块初始化的C++文件
│   │       ├── ets
│   │       │   └── pages
│   │       │       └── index.ets     //模块library的页面文件
│   │       ├── resources             //模块library的资源目录
│   │       └── module.json5          //模块library的配置文件
│   ├── oh-package.json5              //模块级
│   ├── index.ets                     //入口文件index.ets
│   └── build-profile.json5           //模块级
└── build-profile.json5               //工程级

    NAPI模块必须是hsp模块

    在鸿蒙(HarmonyOS)应用开发中,包含NAPI原生C++代码的模块必须是HSP(Harmony Shared Package)模块。这主要是由模块的动态加载需求决定的。

    下面的表格整理了几个关键的模块类型及其与NAPI的关系:

    模块类型 后缀 是否支持NAPI 主要特点与应用场景
    HSP .hsp ✅ 支持 动态共享包。可以被多个HAP引用,运行时在进程内只有一份代码副本,是部署NAPI(C++代码编译为.so文件)的唯一选择
    HAR .har ❌ 不支持 静态共享包。代码和资源在编译时直接拷贝到依赖模块中,不支持原生C++代码的.so文件。
    HAP (entry/feature) .hap ❌ 不支持 应用部署包。entry是主模块,feature是功能模块。虽然可以使用NAPI功能,但必须通过依赖一个HSP模块来实现,不能自己直接包含NAPI代码。
    应用中使用NAPI步骤

    从以上表格可以看出,要在你的应用中使用NAPI,通常需要创建或引入一个HSP模块。

    具体的步骤如下表所示:

    步骤 操作
    1. 创建HSP模块 在DevEco Studio中,通过 File > New > Module,选择 “Shared Library” 模板来创建HSP模块。
    2. 启用原生支持 在模块创建向导或模块的 build-profile.json5 配置中,打开 “Enable native” 开关。这会在模块中生成 cpp 目录,用于编写C/C++代码。
    3. 编写NAPI代码 在 src/main/cpp/ 目录下编写你的C++实现。注册NAPI接口的核心函数通常在 napi_init.cpp 中。
    4. 在应用中集成 在你的主模块(entry)的 oh-package.json5 文件中,声明对这个HSP模块的依赖。这样,你的主模块就可以调用HSP中导出的NAPI方法了。

    核心概念区分:应用内HSP与集成态HSP

    在鸿蒙中,创建集成态HSP主要是为了解决开发调试阶段跨应用共享代码的签名与包名强耦合问题,它与普通HSP在设计目标和使用场景上存在核心区别。

    下面的表格清晰地概括了它们的关键差异:

    特性 普通HSP (应用内共享) 集成态HSP (跨应用共享)
    主要目的 同一个应用内实现模块化与代码复用。 不同应用或模块间(尤其调试阶段)实现代码和原生能力(NAPI)的免签名共享
    共享范围 仅限于相同 bundleName 和签名的模块。 可被不同签名、不同包名的宿主应用临时依赖和调用。
    产物形式 编译后直接打包进最终HAP。 一个独立的 .tgz压缩包文件。
    签名要求 必须与宿主应用使用完全一致的签名。 调试阶段无需签名一致,正式发布时需统一签名。
    生命周期 随应用安装、更新、卸载。 提前预置到设备,独立于应用存在,可被多个不同应用重复使用。
    典型场景 应用内部模块化,如将NAPI能力封装给主模块使用。 开发调试:如三方库、SDK开发者给客户提供带NAPI的调试包。跨应用共享:多个应用共用一套底层C++库。
    如何创建集成态HSP

    创建集成态HSP并非在IDE中直接新建一个模块,而是将一个已创建的普通HSP模块,编译和发布为集成态的.tgz。核心步骤如下:

    1. 前提:创建一个普通HSP模块
      在DevEco Studio中,通过 File > New > Module,选择 “Shared Library” 模板创建。确保它是一个可独立编译的HSP工程(包含oh-package.json5)。

    2. 关键:配置编译选项为“integrated”
      这是最关键的一步。在HSP模块的 build-profile.json5 文件中,将 artifactType 字段的值修改为 "integration"

      // build-profile.json5
      {
        "apiType": "stageMode",
        "buildModeSet": {
          "artifactType": "integration" // 关键配置:声明为集成态产物
        },
        // ... 其他配置
      }

      这个配置告知编译系统,你需要生成的是一个独立的 .tgz 包,而非直接打包进应用。

    3. 编译生成.tgz
      在DevEco Studio中,单独对该HSP模块进行编译(例如点击右侧Gradle工具栏中该模块的 build 任务)。编译成功后,你可以在该模块的 build/outputs/integration/ 目录下找到生成的 .tgz 文件(例如 MyNativeHSP-Integrating-1.0.0.tgz)。

    如何使用集成态HSP

    使用方(宿主应用)需要在自己的 oh-package.json5 文件中,通过 dependencies 声明对该 .tgz 包的本地路径依赖

    // 宿主应用的 oh-package.json5
    {
      "dependencies": {
        "my_native_hsp": "file:../MyNativeHSP/build/outputs/integration/MyNativeHSP-Integrating-1.0.0.tgz"
      }
    }

    添加依赖后,执行 ohpm install 命令,即可将该HSP集成到你的应用中。

    重要总结与注意事项
    • 核心目的:集成态HSP是开发调试和动态分发的利器,它解耦了签名和包名限制,极大地方便了SDK开发和联调。

    • 发布约束上架应用市场时,应用最终不能依赖集成态HSP。正式发布前,必须将依赖关系调整为使用相同签名、并最终打包在一起的普通HSP(将artifactType改回默认或移除),或采用其他合规的分发方式。

    • 版本管理.tgz包的版本号需在HSP模块的 oh-package.json5 中明确定义,使用方在更新包时需要同步修改依赖路径和版本。

    HSP中对外内容导出

    介绍如何导出HSP的ArkUI组件、接口、资源,供应用内的其他HAP/HSP引用

    导出ArkUI组件

    ArkUI组件可以通过export导出,例如:

    // library/src/main/ets/components/MyTitleBar.ets
    @Component
    export struct MyTitleBar {
      build() {
        Row() {
          Text($r('app.string.library_title'))
            .id('library')
            .fontFamily('HarmonyHeiTi')
            .fontWeight(FontWeight.Bold)
            .fontSize(32)
            .fontColor($r('app.color.text_color'))
        }
        .width('100%')
      }
    }

    在入口文件 index.ets 中声明对外暴露的接口。

    // library/index.ets
    export { MyTitleBar } from './src/main/ets/components/MyTitleBar';

    导出类和方法

    通过export导出类和方法,例如:

    // library/src/main/ets/utils/test.ets
    export class Log {
      static info(msg: string): void {
        console.info(msg);
      }
    }
    
    export function add(a: number, b: number): number {
      return a + b;
    }
    
    export function minus(a: number, b: number): number {
      return a - b;
    }

    在入口文件 index.ets 中声明对外暴露的接口。

    // library/index.ets
    export { Log, add, minus } from './src/main/ets/utils/test';

    导出native方法

    在HSP中也可以包含C++编写的so。对于so中的native方法,HSP通过间接的方式导出,以导出liblibrary.so的乘法接口multi为例:

    // library/src/main/ets/utils/nativeTest.ets
    import native from 'liblibrary.so';
    
    export function nativeMulti(a: number, b: number): number {
      let result: number = native.multi(a, b);
      return result;
    }

      在入口文件 index.ets 中声明对外暴露的接口。

      // library/index.ets
      export { nativeMulti } from './src/main/ets/utils/nativeTest';

      通过$r访问HSP中的资源

      在组件中,经常需要使用字符串、图片等资源。HSP中的组件需要使用资源时,一般将其所用资源放在HSP包内,而非放在HSP外部,以符合高内聚低耦合的原则

      在工程中,常通过$r/$rawfile的形式引用应用资源。可以用$r/$rawfile访问本模块resources目录下的资源,如访问resources目录下定义的图片src/main/resources/base/media/example.png时,可以用$r("app.media.example")。有关$r/$rawfile的使用方式,请参阅文档资源分类与访问中“资源访问-应用资源”小节。

      不推荐使用相对路径的方式,容易引用错误路径。例如:

      当要引用上述同一图片资源时,在HSP模块中使用Image("../../resources/base/media/example.png"),实际上该Image组件访问的是HSP调用方(如entry)下的资源entry/src/main/resources/base/media/example.png,找错了位置。

      // library/src/main/ets/pages/Index.ets
      // 正确用例
      Image($r('app.media.example'))
        .id('example')
        .borderRadius('48px')
      // // 错误用例
      Image("../../resources/base/media/example.png")
        .id('example')
        .borderRadius('48px')

      导出HSP中的资源

      跨包访问HSP内资源时,推荐实现一个资源管理类,以封装对外导出的资源。采用这种方式,具有如下优点:

      • HSP开发者可以控制自己需要导出的资源,不需要对外暴露的资源可以不用导出。
      • 使用方无须感知HSP内部的资源名称。当HSP内部的资源名称发生变化时,也不需要使用方跟着修改。

      其具体实现如下:

      将需要对外提供的资源封装为一个资源管理类:

      // library/src/main/ets/ResManager.ets
      export class ResManager{
        static getPic(): Resource{
          return $r('app.media.pic');
        }
        static getDesc(): Resource{
          return $r('app.string.shared_desc');
        }
      }

      在入口文件 index.ets 中声明对外暴露的接口。

      // library/index.ets
      export { ResManager } from './src/main/ets/ResManager';

        外部使用HSP

        介绍如何引用HSP中的接口,以及如何通过页面路由实现HSP的pages页面跳转与返回

        引用HSP中的接口

        要使用HSP中的接口,首先需要在使用方的 oh-package.json5 文件中配置对它的依赖。具体配置方法请参考引用动态共享包

        依赖配置成功后,就可以像使用HAR一样调用HSP的对外接口了。例如,上面的library已经导出了下面这些接口:

        // library/index.ets
        // ...
        export { Log, add, minus } from './src/main/ets/utils/test';
        // ...
        export { MyTitleBar } from './src/main/ets/components/MyTitleBar';
        // ...
        export { ResManager } from './src/main/ets/ResManager';
        // ...
        export { nativeMulti } from './src/main/ets/utils/nativeTest';

        在使用方的代码中,首先要导入模块,使用如同其他模块正常使用即可,代码可参考应用程序框架进阶——HSP

        页面跳转和返回

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

        .onClick(() => {
            this.pathStack.pushPathByName('library_menu', null)
        })

          在library下新增page文件(library/src/main/ets/pages/library_menu.ets),其中'back_to_index'的按钮返回上一页。

          @Builder
          export function PageOneBuilder() {
            Library_Menu()
          }
          
          @Entry
          @Component
          export struct Library_Menu {
            @State message: string = 'Hello World';
            pathStack: NavPathStack = new NavPathStack();
          
            build() {
              NavDestination() {
                Row() {
                  Column() {
                    Text(this.message)
                      .fontSize($r('app.float.page_text_font_size'))
                      .fontWeight(FontWeight.Bold)
                      .onClick(() => {
                        this.message = 'Welcome';
                      })
                    Button('back_to_index').fontSize(50).onClick(() => {
                      this.pathStack.pop();
                    })
                  }
                  .width('100%')
                }
                .height('100%')
              }.title('Library_Menu')
              .onReady((context: NavDestinationContext) => {
                this.pathStack = context.pathStack;
              })
            }
          }

          需要在library模块下新增route_map.json文件(library/src/main/resources/base/profile/route_map.json)。

          {
            "routerMap": [
              {
                "name": "library_menu",
                "pageSourceFile": "src/main/ets/pages/library_menu.ets",
                "buildFunction": "PageOneBuilder",
                "data": {
                  "description": "this is library_menu"
                }
              }
            ]
          }

          在library模块下的配置文件(library/src/main/module.json5)中配置json文件。

          {
            "module": {
              "name": "library",
              "type": "shared",
              "description": "$string:shared_desc",
              "deviceTypes": [
                "tablet",
                "2in1"
              ],
              "deliveryWithInstall": true,
              "pages": "$profile:main_pages",
              "routerMap": "$profile:route_map" // 新增配置,指向route_map.json文件
            }
          }

          页面跳转和页面返回都使用了Navigation的特性,详情参考Navigation跳转

          HAR

          HAR(Harmony Archive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。

          使用场景

          • 支持应用内共享,也可以作为二方库(SDK)、三方库(SDK)发布后供其他应用使用。
          • 作为二方库(SDK),发布到OHPM私仓,供公司内部其他应用使用。
          • 作为三方库(SDK),发布到OHPM中心仓,供其他应用使用。

          约束限制

          • HAR不支持在设备上单独安装或运行,只能作为应用模块的依赖项被引用。
          • 从API version 14开始,HAR支持在配置文件中声明UIAbility组件,配置UIAbility的方法参考在模块中添加Ability,拉起HAR中UIAbility的方式与启动应用内的UIAbility方法相同。

          说明

          如果使用startAbility接口拉起HAR中的UIAbility,接口参数中的moduleName取值需要为依赖该HAR的HAP/HSP的moduleName。

          • 从API version 18开始,HAR支持在配置文件中声明ExtensionAbility组件,但不支持具有入口能力的ExtensionAbility(即skill标签配置了entity.system.home和ohos.want.action.home)。HAR中配置ExtensionAbility的方法和支持的类型请参考模块中添加ExtensionAbility。API version 17及之前版本,不支持在配置文件中声明ExtensionAbility组件。
          • HAR不支持在配置文件中声明pages页面,但是可以包含pages页面,并通过Navigation跳转的方式进行跳转。
          • HAR不支持引用AppScope目录中的资源。在编译构建时,AppScope中的内容不会打包到HAR中,因此会导致HAR资源引用失败
          • 由于HSP仅支持应用内共享,如果HAR依赖了HSP,则该HAR文件仅支持应用内共享,不支持发布到二方仓或三方仓供其他应用使用,否则会导致编译失败。
          • 多包(HAP/HSP)引用相同的HAR时,会造成多包间代码和资源的重复拷贝,从而导致应用包变大
          • HAR可以依赖其他HAR或者HSP,但不支持循环依赖,也不支持依赖传递。
          • HAP引用HAR时,在编译构建过程中系统会自动合并两者的权限配置。因此开发者无需在HAP和HAR中重复申请相同权限

          说明

          循环依赖:例如有三个HAR,HAR-A、HAR-B和HAR-C,循环依赖指HAR-A依赖HAR-B,HAR-B依赖HAR-C,HAR-C又依赖HAR-A。

          依赖传递:例如有三个HAR,HAR-A、HAR-B和HAR-C,依赖关系是HAR-A依赖HAR-B,HAR-B依赖HAR-C。不支持传递依赖指HAR-A可以使用HAR-B的方法和组件,但是HAR-A不能直接使用HAR-C的方法和组件。

          创建

          开发者可以通过DevEco Studio创建一个用于调用C++代码的HAR模块,创建过程中需要在Configure New Module界面中开启Enable native。详见创建库模块

          HAR中对外内容导出

          介绍如何导出HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用。

          Index.ets文件是HAR导出声明文件的入口,HAR需要导出的接口,统一在Index.ets文件中导出。Index.ets文件是DevEco Studio默认自动生成的,开发者也可以自定义,在模块的oh-package.json5文件中的main字段配置入口声明文件,配置如下所示:

          {
            // ...
            "main": "Index.ets",
            // ...
          }

          说明

          HAR在和宿主应用一起编译时,会把HAR的代码直接编译到宿主应用中,HAR包是一个编译中间态产物,不是最终的运行实体。运行时,HAR运行的身份信息是其宿主应用,系统会以宿主应用的版本做行为区分。如果需要在HAR中区分宿主应用的版本做不同的行为区分,可以调用getBundleInfoForSelf接口,获取宿主应用的targetVersion,然后根据不同的targetVersion,做不同的逻辑处理。

          导出ArkUI组件

          通过export导出ArkUI组件,示例如下:

          // library/src/main/ets/components/mainpage/MainPage.ets
          @Component
          export struct MainPage {
            //...
          }

          HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:

          // library/Index.ets
          export { MainPage } from './src/main/ets/components/mainpage/MainPage';

          导出类和方法

          通过export导出类和方法,支持导出多个类和方法,示例如下所示:

          // library/src/main/ets/test.ets
          export class Log {
            static info(msg: string) {
              console.info(msg);
            }
          }
          
          export function func() {
            return 'har func';
          }
          
          export function func2() {
            return 'har func2';
          }

          HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:

          // library/Index.ets
          export { Log, func, func2 } from './src/main/ets/test';

            导出native方法

            在HAR中也可以包含C++编写的so(注意不是直接使用,因此我认为C++必须先使用NAPI封装)。对于so中的native方法,HAR通过以下方式导出,以导出liblibrary.so的加法接口add为例:

            // library/src/main/ets/utils/nativeTest.ets
            import native from 'liblibrary.so';
            
            export function nativeAdd(a: number, b: number): number {
              let result: number = native.add(a, b);
              return result;
            }

              HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:

              // library/Index.ets
              export { nativeAdd } from './src/main/ets/utils/nativeTest';

              导出资源

              在编译构建HAP时,DevEco Studio会从HAP模块及依赖的模块中收集资源文件,如果不同模块下的资源文件出现重名冲突时,DevEco Studio会按照以下优先级进行覆盖(优先级由高到低):

              • AppScope(仅Stage模型支持)。
              • HAP包自身模块。
              • 依赖的HAR模块,如果依赖的多个HAR之间有资源冲突,会按照工程oh-package.json5中dependencies下的依赖顺序进行覆盖,依赖顺序在前的优先级较高。例如下方示例中dayjs和lottie中包含同名文件时,会优先使用dayjs中的资源。

                说明

                如果在AppScope、HAP模块或HAR模块的国际化目录中配置了资源,在相同的国际化限定词下,合并的优先级也遵循上述规则。同时,国际化限定词中配置的优先级高于在base中的配置。例如,在AppScope的base中配置了资源字段,在HAR模块的en_US中配置了同样的资源字段,则在en_US的使用场景中,会更优先使用HAR模块中配置的资源字段。

              {
                // ...
                "dependencies": {
                  // ...
                  "dayjs": "file:../dayjs",
                  "lottie": "file:../lottie",
                },
              }

              使用HAR

              介绍调用方如何配置HAR依赖,并引用HAR的ArkUI组件、接口、资源

              引用HAR前,需要先配置对HAR的依赖,详见引用HAR文件和资源

              引用HAR的ArkUI组件

              HAR的依赖配置成功后,可以引用HAR的ArkUI组件。通过import引入HAR导出的ArkUI组件,示例如下所示:

              // entry/src/main/ets/pages/IndexSec.ets
              import { MainPage } from 'library';
              
              @Entry
              @Component
              struct IndexSec {
                build() {
                  Row() {
                    // 引用HAR的ArkUI组件
                    MainPage()
                  }
                  .height('100%')
                }
              }

              引用HAR的类和方法

              通过import引用HAR导出的类和方法,然后代码中正常使用即可。 代码可参考应用程序框架进阶——HAR

              引用HAR的native方法

              通过import引用HAR导出的native方法 ,然后代码中正常使用即可。 代码可参考应用程序框架进阶——HAR

              引用HAR的资源

              通过$r引用HAR中的资源,例如在HAR模块的src/main/resources里添加字符串资源(在string.json中定义,name:hello_har)和图片资源(icon_har.png),然后在Entry模块中引用该字符串和图片资源的示例如下所示:

              // 引用HAR的字符串资源
              Text($r('app.string.hello_har'))
              
              // 引用HAR的图片资源
              Image($r('app.media.icon_har'))
              

                  构建

                  详情请参见构建HAR

                  混淆配置

                  HAR可以作为二方库和三方库提供给其他应用使用,如果需要对代码资产进行保护,建议开启混淆

                  混淆能力开启后,DevEco Studio在构建HAR时,会对代码进行编译、混淆及压缩处理,保护代码资产

                  HAR模块原先默认开启混淆能力,会对API 10及以上的HAR模块,且编译模块为release时,自动进行简单的代码混淆;从DevEco Studio 5.0.3.600开始,新建工程默认关闭代码混淆功能,可以在HAR模块的build-profile.json5文件中的ruleOptions字段下的enable进行开启混淆,详情请见代码混淆,配置如下所示:

                  {
                    "apiType": "stageMode",
                    "buildOption": {
                      // ...
                    },
                    "buildOptionSet": [
                      {
                        "name": "release",
                        "arkOptions": {
                          "obfuscation": {
                            "ruleOptions": {
                              "enable": true,
                              "files": [
                                "./obfuscation-rules.txt"
                              ]
                            },
                            "consumerFiles": [
                              "./consumer-rules.txt"
                            ]
                          }
                        },
                        // ...
                      },
                    ],
                    "targets": [
                      {
                        "name": "default"
                      },
                      // ...
                    ]
                  }

                  发布

                  详见发布HAR

                  Logo

                  作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

                  更多推荐