文档

快速开始

更新时间:

本文介绍如何将 H5 容器组件接入到 HarmonyOS NEXT 客户端。您可以基于已有工程使用 ohpmrc 方式接入 H5 容器 SDK 到客户端。

前置条件

添加 H5 容器 SDK 之前,请您确保已经将工程接入到 mPaaS。更多信息请参见 基于已有工程使用 ohpmrc 接入

引入依赖

  1. 在项目的.ohpmrc文件中添加如下仓库:

    @mpaas:registry=https://mpaas-ohpm.oss-cn-hangzhou.aliyuncs.com/meta
  2. 使用 ohpm install @mpaas/hriver 安装 H5 容器的依赖。

添加 SDK

oh-package.json5 中配置所需依赖,具体版本号请参考开发指南手册基于已有工程使用 ohpmrc 接入中“添加 mPaaS 组件依赖”的组件列表

{
  "license": "",
  "devDependencies": {},
  "author": "",
  "name": "entry",
  "description": "Please describe the basic information.",
  "main": "",
  "version": "1.0.0",
  "dependencies": {
    "@mpaas/hriver": "0.0.5-2406300000"
  }
}

配置权限

module.json5 中配置所需权限。

"requestPermissions":[
  {
  "name" : "ohos.permission.GET_NETWORK_INFO",
  },
  {
  "name" : "ohos.permission.INTERNET",
  }
]

使用 SDK

初始化

在 mPaaS 框架初始化完成之后,初始化 HRiver。代码如下:

HRiver.init();

使用 SDK 之前必须初始化 mPaaS 框架,设置 userId 和 appsecret,其中 appsecret 从 AppCenter 后台获取,具体查看开发指南手册获取 Harmony config 配置文件(beta) 。代码示例如下:

import AbilityStage from '@ohos.app.ability.AbilityStage';
import { MPFramework } from '@mpaas/framework';

export default class ModuleEntry extends AbilityStage {
  async onCreate() {
    MPFramework.create(this.context);
    
    MPFramework.instance.userId = 'MPTestCase'
    MPFramework.instance.appSecret = "12a711d78980f661aca5401788fdf09a";
  }
}

打开离线包

初始化 HRiver 之后调用 startApp 打开离线包。

import { HRiver } from '@mpaas/hriver'

/**
* 打开离线包
* @param appId: 离线包id
* @param startParams: 启动参数,可以不传。控制TitleBar、指定页面等
*/
HRiver.startApp(appId: string, startParams?: Map<string, Object>)

代码示例如下:

import { HRiver } from '@mpaas/hriver'

// 示例1:
HRiver.startApp('20190517') // 直接启动离线包

// 示例2: 
let startParams: Map<string, Object> = new Map();
startParams.set('defaultTitle', '默认标题') //加载阶段显示默认标题
HRiver.startApp('20190517', startParams)

打开在线页面

初始化 HRiver 之后调用 startUrl 打开在线页面。

import { HRiver } from '@mpaas/hriver'

/**
* 打开在线页面
* @param url: 在线地址
* @param startParams: 启动参数。可以不传,控制TitleBar、指定页面等
*/
HRiver.startUrl(url: string, startParams: Map<string, Object>)

注册自定义 JSAPI

初始化 HRiver 之后调用 registerPlugin 注册自定义 JSAPI。

import { HRiver } from '@mpaas/hriver'

/**
* 注册自定义 JSApi 实现
* @param pluginClass: pluginClass列表,如 registerPlugin({CustomPlugin1, CustomPlugin2}, HRiver.SCOPE_PAGE)
* @param scope: 可以不传。默认HRiver.SCOPE_PAGE。HRiver.SCOPE_APP表示离线包App级别生命周期;HRiver.SCOPE_PAGE表示页面级别生命周期
*/
HRiver.registerPlugin(pluginClass: ESObject, scope: string)

代码示例:

HRiver.registerPlugin({H5CustomPlugin, H5Custom1Plugin})

plugin 实现代码示例如下:

import { HRiver, H5SimplePlugin, H5EventFilter, H5Event, H5BridgeContext } from '@mpaas/hriver'

class H5CustomPlugin extends H5SimplePlugin {
  onPrepare(filter: H5EventFilter): void {
    filter.addAction('myapi1')
  }

  handleEvent(event: H5Event, context: H5BridgeContext): Boolean {
    if ('myapi1' == event.action) {
      context.sendBridgeResult({
        success: true,
        data: 'myapi1调用成功'
      })
      return true
    }
    return super.handleEvent(event, context);
  }
}

class H5Custom1Plugin extends H5SimplePlugin {
  onPrepare(filter: H5EventFilter): void {
    filter.addAction('myapi2')
  }

  handleEvent(event: H5Event, context: H5BridgeContext): Boolean {
    if ('myapi2' == event.action) {
      context.sendBridgeResult({
        success: true,
        data: 'myapi2调用成功'
      })
      return true
    }
    return super.handleEvent(event, context);
  }
}

Native 调用 H5

Native 调用 H5 有以下两种方法。

  • 在自定义 JSAPI 中通过 H5BridgeContext.sendToWeb 方法调用 H5。

    import { H5BridgeContext, H5Event, H5EventFilter, H5SimplePlugin, HRiver } from '@mpaas/hriver';
    class H5CustomPlugin extends H5SimplePlugin {
      handleEvent(event: H5Event, context: H5BridgeContext): Boolean {
        // native 调用 h5
        context.sendToWeb('customCallWeb', {
            data: 'abc'
        })
    
        ... // 其他代码
      }
    }
  • 在 Native 代码中获取 TopAppactivityPage,获得最新的页面,通过页面调用 sendToWeb 方法。

    import { HRiver,
      XRiverProxy,
      getProxy,
      AppManager,
      AppNode,
      Page
    } from '@mpaas/hriver';
    {
      let appManager = getProxy(XRiverProxy.AppManager) as AppManager
      let appNode: AppNode | null = appManager.findTopApp()
      if (appNode != null) {
        let page: Page | null = appNode.getActivePage()
        if (page != null) {
          page.sendToWeb('testAction', {data: ''})
        }
      }
    }

加载内置离线包

加载所有内置离线包,包括内置的公共离线包。

初始化 HRiver 之后调用 loadOfflineResource 加载内置离线包。

import { HRiver } from '@mpaas/hriver'

/**
* 加载内置离线包
* @param jsonFileName: 内置离线包的 h5_json.json 的文件名,放到rawfile目录中。如:h5_json.json。
* @param callback: 格式 (result: string) => {}。内置离线包加载完成回调的 Function
*/
HRiver.loadOfflineResource(jsonFileName: string, callback: Function)

代码示例如下:

  1. entry/src/main/resources/rawfile 下添加 h5_json.json(文件从 Appcenter 后台下载即可)。

    {
       "config":{
          "updateReqRate":16400,
          "limitReqRate":13600,
          "appPoolLimit":3,
          "versionRefreshRate":86400
       },
       "data":[
          {
             "app_desc":"离线包1",
             "app_id":"20180910",
             "auto_install":1,
             "fallback_base_url":"https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/570DA89281533-default/20180910/1.0.0.3_all/nebula/fallback/",
             "global_pack_url":"",
             "icon_url":"",
             "installType":1,
             "main_url":"/www/index.html",
             "name":"离线包1",
             "online":1,
             "package_url":"https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/570DA89281533-default/20180910/1.0.0.3_all/nebula/20180910_1.0.0.3.amr",
             "patch":"",
             "sub_url":"",
             "version":"1.0.0.3",
             "vhost":"https://20180910.h5app.com"
          },
            {
                "app_desc":"离线包2",
                "app_id":"20190517",
                "auto_install":1,
                "fallback_base_url":"https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/570DA89281533-default/20190517/1.0.0.0_all/nebula/fallback/",
                "global_pack_url":"",
                "icon_url":"",
                "installType":1,
                "main_url":"/www/index.html",
                "name":"离线包2",
                "online":1,
                "package_url":"https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/570DA89281533-default/20190517/1.0.0.0_all/nebula/20190517_1.0.0.0.amr",
                "patch":"",
                "sub_url":"",
                "version":"1.0.0.0",
                "vhost":"https://20190517.h5app.com"
            }
       ],
       "resultCode":100,
       "resultMsg":"操作成功",
       "state":"success"
    }
  2. 下载 amr 并命名为 ${appid}_${version}.amr

    image

  3. 调用 API。

    import { HRiver } from '@mpaas/hriver'
    
    HRiver.loadOfflineResource('h5_json.json', (result: string) => {
      this.resultText = this.resultText + `\n${result} 预加载成功`
    })

更新离线包

import { HRiver } from '@mpaas/hriver'

/**
 * 批量更新离线包
 * @param appIds: 需要更新离线包的appId列表
 * @param updateCallback: 格式必须 (result: boolean, code: number) => {}。更新接口返回后回调的Function
 */
HRiver.updateApp(appIds?: Array<string>, updateCallback?: Function)

/**
 * 更新所有离线包。
 * @param updateCallback: 格式必须 (result: boolean, code: number) => {}。更新接口返回后回调的Function
 */
HRiver.updateAll(updateCallback: Function)

/**
 * 批量更新离线包
 * @param appIds: 离线包的appId和version的map
 * @param updateCallback: 格式必须 (result: boolean, code: number) => {}。更新接口返回后回调的Function
 */
HRiver.updateAppWithVersion(appIds?: Map<string, string>, updateCallback?: Function)

代码示例如下:

import { HRiver } from '@mpaas/hriver'

HRiver.updateApp(['90000002'], (result: boolean, code: number) => {
  this.resultText = `90000002更新结果: ${result}`
})

配置公共离线包

  1. 设置 H5CommonAppProvider

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    /**
    * 配置公共离线包 Provider,必须在 HRiver.init() 之前调用
    */
    HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
    说明

    setProvider 必须在 HRiver.init() 之前调用。

  2. 实现 H5AppCommonProviderImpl.etsgetCommonResourceAppList 方法。

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    export class H5AppCommonProviderImpl extends H5CommonAppProvider {
      getCommonResourceAppList(): Array<string> {
        return ['20220719'] // 返回公共离线包id列表
      }
    }

设置 UserAgent

import { HRiver } from '@mpaas/hriver'

HRiver.setUserAgent(userAgent)
说明

setUserAgentHRiver.init() 之后调用,会在默认 UserAgent 之后拼接设置的 useragent

设置离线包默认更新频率

  1. 设置 H5CommonAppProvider

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    /**
    * 配置公共离线包Provider、离线包更新频率等功能,必须在HRiver.init()之前调用
    */
    HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
    说明

    setProvider 必须在 HRiver.init() 之前调用。

  2. 实现 H5CommonAppProviderconfigJSON 方法,代码示例如下。

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    export class H5AppCommonProviderImpl extends H5CommonAppProvider {
      ... // 其他配置
    
      // configJson,配置更新频率等
      configJSON(): string {
        return JSON.stringify({
          h5_nbmngconfig: "{\"config\":{\"al\":\"3\",\"pr\":{\"4\":\"86400\",\"common\":\"864000\"},\"ur\":\"1\",\"fpr\":{\"common\":\"3888000\"}},\"switch\":\"yes\"}"
        })
      }
    }

    具体参数如下:

    h5_nbmngconfig: "{\"config\":{\"al\":\"3\",\"pr\":{\"4\":\"86400\",\"common\":\"864000\"},\"ur\":\"1800\",\"fpr\":{\"common\":\"3888000\"}},\"switch\":\"yes\"}"

    其中的 ur: 1800 表示更新频率为 1800 秒,使用时修改 ur 的值即可。

配置离线包签名校验

  1. 设置 H5CommonAppProvider

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    /**
    * 配置公共离线包Provider、离线包更新频率、签名校验等功能,必须在HRiver.init()之前调用
    */
    HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
    说明

    setProvider 必须在 HRiver.init() 之前调用。

  2. 实现 H5CommonAppProvidershouldVerifypubKey 方法,代码示例如下:

    import { HRiver, H5CommonAppProvider } from '@mpaas/hriver'
    
    export class H5AppCommonProviderImpl extends H5CommonAppProvider {
     ... // 其他配置 
    
     /**
     * 是否开启离线包校验,默认关闭
     * return: true表示开启,false表示关闭
     */
     shouldVerify(): boolean {
     return false
     }
    
     // 离线包校验的公钥,如果shouldVerify为false 则无需设置,否则必须设置公钥
     pubKey(): string {
     return ''
     }
    }

开启调试模式

HRiver.enableDebug(true)

自定义导航栏

  1. 初始化完成后通过 provider 设置自定义导航栏。

    import {HRBuilder, RouterUtils, HRiver, H5CommonAppProvider, H5RouterNavStackProvider,
      CustomUIBuilderProvider,
      H5CacheProvider
    } from '@mpaas/hriver'
    
    HRiver.setProvider(CustomUIBuilderProvider.name, new CustomUIBuilderProviderImpl())
  2. 实现 CustomUIBuilderProviderImpl

    import { CustomUIBuilderProvider, Page } from '@mpaas/hriver';
    import { CustomUIBuilder } from '../pages/CustomTitleBarComponent';
    
    export class CustomUIBuilderProviderImpl extends CustomUIBuilderProvider {
      getCustomUIBuilder(): WrappedBuilder<[string, Page]> {
        return wrapBuilder(CustomUIBuilder);
      }
    }

    其中 CustomUIBuilder 为业务自定义 titlebar 组件的全局 Builder。实现参考如下:

    /**
    *  name: 自定义组件的名称
    *  page: 自定义titlebar对应的页面Page
    */
    @Builder
    export function CustomUIBuilder(name: string, p: Page) {
      if (name === 'titleBar') {
        CustomTitleBarComponent({page: p, titleBarData: p.titleBarData})
      }
    }

    CustomTitleBarComponent 为具体的标题组件,titleBarData 为标题栏所需要的数据,数据发生变化会实时刷新。示例参考如下:

    import { H5NavMenuItemData, HRiverUtil, Page, TitleBarData } from '@mpaas/hriver'
    
    const TAG: string = "CustomTitleBarComponent"
    
    
    const MENU_MARGIN: number = 5
    const DEFAULT_MARGIN: number = 12
    
    @Builder
    export function CustomUIBuilder(name: string, p: Page) {
      if (name === 'titleBar') {
        CustomTitleBarComponent({page: p, titleBarData: p.titleBarData})
      }
    }
    
    @Component
    export struct CustomTitleBarComponent {
      page: Page | null = null
      @Prop titleBarData: TitleBarData
    
      aboutToAppear(): void {
      }
    
      build() {
        RelativeContainer() {
          Button() {
            Image(this.getBackIconImage())
              .id('titlebar_back_img')
              .width(12)
              .height(20)
          }
          .width(48)
          .height('100%')
          .borderRadius(0)
          .backgroundColor(Color.Transparent)
          .align(Alignment.Center)
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top }
          })
          .id("h5_nav_close")
          .onClick((event) => {
            if (this.page != null) {
              this.page.backClickEvent()
            }
          })
    
          Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {
            //如果设置了图片标题就只显示图片
            if (this.titleBarData.titleImage) {
              Image(this.titleBarData.titleImage)
                .id('titlebar_title_image')
                .height(36).onClick(() => {
                this.onTitleClick()
              })
            } else {
              Flex({ justifyContent: FlexAlign.Start,direction: FlexDirection.Row }){
                Text(this.titleBarData.title)
                  .fontSize(18)
                  .textAlign(TextAlign.Start)
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .maxLines(1)
                  .fontColor(this.titleBarData.titleColor)
                  .onClick(() => {
                    this.onTitleClick()
                  })
                if(this.titleBarData.showTitleLoading ){
    
                  Image(this.getTitleBarLoadingIcon()).width(18).height(18)
                    .id('titlebar_progress_img')
                    .margin({left:5,top:1})
                    .rotate({ angle: this.titleBarData.loadingRotateAngle })
                    .animation({
                      duration:3000,
                      curve: Curve.Linear,
                      delay: 0,
                      iterations: -1,
                      playMode: PlayMode.Normal,
                    }).onAppear(()=>{
                    this.titleBarData.loadingRotateAngle = 360
                  })
    
                }
    
              }
    
              if (this.titleBarData.subtitle) {
                Text(this.titleBarData.subtitle)
                  .textAlign(TextAlign.Start)
                  .fontColor(this.titleBarData.titleColor)
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .maxLines(1)
                  .fontSize(18)
                  .onClick(() => {
                    this.onTitleSubtitleClick()
                  })
              }
            }
    
          }.id("h5_tv_title")
          .height("100%")
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },
            left: { anchor: 'h5_nav_close', align: HorizontalAlign.End },
            right: { anchor: "h5_nav_options", align: HorizontalAlign.Start }
          })
    
          if (this.titleBarData.optionMenuState) {
            if (this.titleBarData.menuType == TitleBarData.MENU_TYPE_TITLE) {
              Text(this.titleBarData.menuTitle)
                .fontSize(16)
                .align(Alignment.Center)
                .textAlign(TextAlign.Center)
                .fontColor(this.titleBarData.menuColor)
                .height('100%')
                .id("h5_nav_options")
                .alignRules({
                  top: { anchor: '__container__', align: VerticalAlign.Top },
                  right: { anchor: '__container__', align: HorizontalAlign.End }
                })
                .onClick(() => {
                  this.onMoreClick(false, 0)
                })
                .margin({
                  right: DEFAULT_MARGIN
                })
            } else if (this.titleBarData.menuType == TitleBarData.MENU_TYPE_ICON) {
              Button() {
                Image(HRiverUtil.getIconImage(this.titleBarData.menuIcon))
                  .id('titlebar_right_icon')
                  .width(22)
                  .height(22)
                  .objectFit(ImageFit.Contain)
              }
              .width(30)
              .borderRadius(0)
              .backgroundColor(Color.Transparent)
              .align(Alignment.Center)
              .id("h5_nav_options")
              .height("100%")
              .onClick(() => {
                this.onMoreClick(false, 0)
              })
              .alignRules({
                top: { anchor: '__container__', align: VerticalAlign.Top },
                right: { anchor: '__container__', align: HorizontalAlign.End }
              })
              .margin({
                right: DEFAULT_MARGIN
              })
            } else if (this.titleBarData.menuType == TitleBarData.MENU_TYPE_MORE) {
              Button() {
                Image(HRiverUtil.getIconImage('more'))
                  .id('titlebar_right_more')
                  .width(22)
                  .height(22)
                  .objectFit(ImageFit.Contain)
              }
              .width(48)
              .borderRadius(0)
              .backgroundColor(Color.Transparent)
              .align(Alignment.Center)
              .id("h5_nav_options")
              .height("100%")
              .margin({
                right: DEFAULT_MARGIN
              })
              .alignRules({
                top: { anchor: '__container__', align: VerticalAlign.Top },
                right: { anchor: '__container__', align: HorizontalAlign.End }
              }).onClick(() => {
                if (!this.titleBarData.preventDefault) {
                  this.titleBarData.customPopup = !this.titleBarData.customPopup
                }
    
                this.onMoreClick(true, 0)
              })
              .bindPopup(this.titleBarData.customPopup , {
                builder: this.MenuBuilder,
                placement:Placement.BottomLeft,
                popupColor:"#fff",
                onStateChange: (e) => {
                  console.info(JSON.stringify(e.isVisible))
                  if (!e.isVisible) {
                    this.titleBarData.customPopup = false
                  }
                }
              })
            }
    
            if (this.titleBarData.menuType1 == TitleBarData.MENU_TYPE_TITLE) {
              Text(this.titleBarData.menuTitle1)
                .fontSize(16)
                .align(Alignment.Center)
                .textAlign(TextAlign.Center)
                .fontColor(this.titleBarData.menuColor1)
                .height('100%')
                .id("h5_nav_options1")
                .alignRules({
                  top: { anchor: '__container__', align: VerticalAlign.Top },
                  right: { anchor: 'h5_nav_options', align: HorizontalAlign.Start }
                })
                .margin({
                  right: MENU_MARGIN
                })
                .onClick(()=> {
                  this.onMoreClick(false, 1)
                })
            } else if (this.titleBarData.menuType1 == TitleBarData.MENU_TYPE_ICON) {
              Button() {
                Image(HRiverUtil.getIconImage(this.titleBarData.menuIcon1))
                  .id('titlebar_right_icon1')
                  .width(22)
                  .height(22)
                  .objectFit(ImageFit.Contain)
              }
              .width(30)
              .borderRadius(0)
              .backgroundColor(Color.Transparent)
              .align(Alignment.Center)
              .id("h5_nav_options1")
              .height("100%")
              .onClick(()=> {
                this.onMoreClick(false, 1)
              })
              .alignRules({
                top: { anchor: '__container__', align: VerticalAlign.Top },
                right: { anchor: 'h5_nav_options', align: HorizontalAlign.Start }
              })
              .margin({
                right: MENU_MARGIN
              })
            } else if (this.titleBarData.menuType1 == TitleBarData.MENU_TYPE_MORE) {
              Button() {
                Image(HRiverUtil.getIconImage('more'))
                  .id('titlebar_right_more1')
                  .width(22)
                  .height(22)
                  .objectFit(ImageFit.Contain)
              }
              .width(48)
              .borderRadius(0)
              .backgroundColor(Color.Transparent)
              .align(Alignment.Center)
              .id("h5_nav_options1")
              .height("100%")
              .margin({
                right: MENU_MARGIN
              })
              .alignRules({
                top: { anchor: '__container__', align: VerticalAlign.Top },
                right: { anchor: 'h5_nav_options', align: HorizontalAlign.Start }
              }).onClick(() => {
                if (!this.titleBarData.preventDefault) {
                  this.titleBarData.customPopup1 = !this.titleBarData.customPopup1
                }
    
                this.onMoreClick(true, 1)
              })
              .bindPopup(this.titleBarData.customPopup1 , {
                builder: this.MenuBuilder,
                placement:Placement.BottomLeft,
                popupColor:"#fff",
                onStateChange: (e) => {
                  console.info(JSON.stringify(e.isVisible))
                  if (!e.isVisible) {
                    this.titleBarData.customPopup1 = false
                  }
                }
              })
            }
    
          }
    
    
    
        }.height(this.titleBarData.showTitleBar ? 48 : 0)
      }
    
      getTitleBarLoadingIcon(): Resource | string {
        return $rawfile(`icon/h5_title_bar_progress_bg.webp`)
      }
    
      getIconImage(icon: string): Resource | string {
        return HRiverUtil.getIconImage(icon)
      }
    
      getBackIconImage(): Resource | string {
        return $rawfile(`icon/hriverback.webp`)
      }
    
      onTitleClick() {
        if (this.page != null) {
          this.page.titleBarClickEvent()
        }
    
      }
    
      onTitleSubtitleClick() {
        if (this.page != null) {
          this.page.subTitleBarClickEvent()
        }
    
      }
    
      onMoreClick(fromMenu:boolean, index: number) {
    
        if (this.page != null) {
          this.page.onMoreClick(fromMenu, index)
        }
    
      }
      onMoreItemClick(tag: string, name: string,isShowPopMenu:boolean) {
        if (this.page != null) {
          this.page.onMoreItemClick(tag, name, isShowPopMenu)
        }
    
      }
    
      @Builder
      MenuBuilder() {
        Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
          ForEach(this.titleBarData.h5NavMenuItemList, (item: H5NavMenuItemData, index) => {
            Column() {
              Row() {
                Image(item.icon).width(20).height(20).margin({ right: 5 })
                Text(item.name).fontSize(16)
              }
              .width('100%')
              .height(30)
              .padding({ left: 10 })
              .justifyContent(FlexAlign.Start)
              .align(Alignment.Center)
              .onClick(() => {
                if (item) {
                  this.onMoreItemClick(item.tag || '', item.name || '',false)
                  this.titleBarData.customPopup = false
                  this.titleBarData.customPopup1 = false
                }
    
              })
    
              if (index != this.titleBarData.h5NavMenuItemList.length - 1) {
                Divider().height(10).width('90%').color('#ccc')
              }
            }.padding(5).height(40)
          })
        }.width(150).height(165).backgroundColor("#fff")
    
      }
    
    }

页面路由支持 Navigation

默认页面路由使用 router 方式,鸿蒙 router 方式不支持关闭栈中某个页面,只能一级级回退。离线包支持 Navigation 模式:

  1. 支持关闭栈中页面

  2. 支持分栏模式

全局 Navigation 模式

  1. HRiver 初始化完成后,在启动离线包之前,需设置 H5RouterNavStackProvider

    HRiver.setProvider(H5RouterNavStackProvider.name, new NavStackProvider(this.pageInfos))
    import { H5RouterNavStackProvider } from '@mpaas/hriver';
    
    export class NavStackProvider extends H5RouterNavStackProvider {
      navStack: NavPathStack // 全局的navPathStack栈
    
      constructor(navStack: NavPathStack) {
        super();
        this.navStack = navStack;
      }
    
      getNavPathStack(): NavPathStack {
        return this.navStack
      }
    }
  2. navDestination 中配置 builderbuilder 中加载 mPaaS 全局 Builder。

    import {HRBuilder, RouterUtils, HRiver, H5RouterNavStackProvider} from '@mpaas/hriver'
    
    let mPaaSHRiverBuilder: WrappedBuilder<[string, ESObject]> = wrapBuilder(HRBuilder);
    
    @Builder
    PagesMap(name: string, params: ESObject) {
      if (RouterUtils.isMPHRiverPage(name)) {
        mPaaSHRiverBuilder.builder(name, params)
      } else if (name == 'xxx') {
        // 其他业务的页面
      }
    }
    
    build() {
        Navigation(this.pageInfos) {
          Row() {
            Column() {
              // 业务页面
              MainPage()
            }
            .width('100%')
          }
        }.navDestination(this.PagesMap)
      }

离线包独立使用 Navigation 模式

  1. HRiver.startApp/HRiver.startUrl 的第三个参数传入 NavPathStack 即可。

  2. 参考 全局 Navigation 模式 中的步骤 2。