快速開始
本文介紹如何將 H5 容器組件接入到 HarmonyOS NEXT 客戶端。您可以基于已有工程使用 ohpmrc 方式接入 H5 容器 SDK 到客戶端。
前置條件
添加 H5 容器 SDK 之前,請您確保已經(jīng)將工程接入到 mPaaS。更多信息請參見 接入 mPaaS 能力。
引入依賴
在項(xiàng)目的.ohpmrc
文件中添加如下倉庫:
@mpaas:registry=https://mpaas-ohpm.oss-cn-hangzhou.aliyuncs.com/meta
添加 SDK
通過 使用 mppm 工具 安裝 H5 容器組件。
配置權(quán)限
在 module.json5
中配置所需權(quán)限。
"requestPermissions":[
{
"name" : "ohos.permission.GET_NETWORK_INFO",
},
{
"name" : "ohos.permission.INTERNET",
}
]
使用 SDK
初始化
在 mPaaS 框架初始化完成之后,初始化 HRiver
。代碼如下:
HRiver.init();
使用 SDK 之前必須初始化 mPaaS 框架,設(shè)置 userId 和 appsecret,其中 appsecret 從 AppCenter 后臺(tái)獲取,具體查看 獲取 HarmonyOS NEXT 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
后調(diào)用 startApp
打開離線包。
import { HRiver } from '@mpaas/hriver'
/**
* 打開離線包
* @param appId: 離線包id
* @param startParams: 啟動(dòng)參數(shù),可以不傳。控制TitleBar、指定頁面等
*/
HRiver.startApp(appId: string, startParams?: Map<string, Object>)
代碼示例如下:
import { HRiver } from '@mpaas/hriver'
// 示例1:
HRiver.startApp('20190517') // 直接啟動(dòng)離線包
// 示例2:
let startParams: Map<string, Object> = new Map();
startParams.set('defaultTitle', '默認(rèn)標(biāo)題') //加載階段顯示默認(rèn)標(biāo)題
HRiver.startApp('20190517', startParams)
打開在線頁面
初始化 HRiver
之后調(diào)用 startUrl
打開在線頁面。
import { HRiver } from '@mpaas/hriver'
/**
* 打開在線頁面
* @param url: 在線地址
* @param startParams: 啟動(dòng)參數(shù)。可以不傳,控制TitleBar、指定頁面等
*/
HRiver.startUrl(url: string, startParams: Map<string, Object>)
注冊自定義 JSAPI
初始化 HRiver
之后調(diào)用 registerPlugin
注冊自定義 JSAPI。
import { HRiver } from '@mpaas/hriver'
/**
* 注冊自定義 JSApi 實(shí)現(xiàn)
* @param pluginClass: pluginClass列表,如 registerPlugin({CustomPlugin1, CustomPlugin2}, HRiver.SCOPE_PAGE)
* @param scope: 可以不傳。默認(rèn)HRiver.SCOPE_PAGE。HRiver.SCOPE_APP表示離線包App級別生命周期;HRiver.SCOPE_PAGE表示頁面級別生命周期
*/
HRiver.registerPlugin(pluginClass: ESObject, scope: string)
代碼示例:
HRiver.registerPlugin({H5CustomPlugin, H5Custom1Plugin})
plugin 實(shí)現(xiàn)代碼示例如下:
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調(diào)用成功'
})
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調(diào)用成功'
})
return true
}
return super.handleEvent(event, context);
}
}
Native 調(diào)用 H5
Native 調(diào)用 H5 有以下兩種方法。
在自定義 JSAPI 中通過
H5BridgeContext.sendToWeb
方法調(diào)用 H5。import { H5BridgeContext, H5Event, H5EventFilter, H5SimplePlugin, HRiver } from '@mpaas/hriver'; class H5CustomPlugin extends H5SimplePlugin { handleEvent(event: H5Event, context: H5BridgeContext): Boolean { // native 調(diào)用 h5 context.sendToWeb('customCallWeb', { data: 'abc' }) ... // 其他代碼 } }
在 Native 代碼中獲取
TopApp
的activityPage
,獲得最新的頁面,通過頁面調(diào)用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: ''}) } } }
加載內(nèi)置離線包
加載所有內(nèi)置離線包,包括內(nèi)置的公共離線包。
初始化 HRiver
之后調(diào)用 loadOfflineResource
加載內(nèi)置離線包。
import { HRiver } from '@mpaas/hriver'
/**
* 加載內(nèi)置離線包
* @param jsonFileName: 內(nèi)置離線包的 h5_json.json 的文件名,放到rawfile目錄中。如:h5_json.json。
* @param callback: 格式 (result: string) => {}。內(nèi)置離線包加載完成回調(diào)的 Function
*/
HRiver.loadOfflineResource(jsonFileName: string, callback: Function)
代碼示例如下:
在
entry/src/main/resources/rawfile
下添加h5_json.json
(文件從 Appcenter 后臺(tái)下載即可)。{ "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" }
下載 amr 并命名為
${appid}_${version}.amr
。調(diào)用 API。
import { HRiver } from '@mpaas/hriver' HRiver.loadOfflineResource('h5_json.json', (result: string) => { this.resultText = this.resultText + `\n${result} 預(yù)加載成功` })
更新離線包
import { HRiver } from '@mpaas/hriver'
/**
* 批量更新離線包
* @param appIds: 需要更新離線包的appId列表
* @param updateCallback: 格式必須 (result: boolean, code: number) => {}。更新接口返回后回調(diào)的Function
*/
HRiver.updateApp(appIds?: Array<string>, updateCallback?: Function)
/**
* 更新所有離線包。
* @param updateCallback: 格式必須 (result: boolean, code: number) => {}。更新接口返回后回調(diào)的Function
*/
HRiver.updateAll(updateCallback: Function)
/**
* 批量更新離線包
* @param appIds: 離線包的appId和version的map
* @param updateCallback: 格式必須 (result: boolean, code: number) => {}。更新接口返回后回調(diào)的Function
*/
HRiver.updateAppWithVersion(appIds?: Map<string, string>, updateCallback?: Function)
代碼示例如下:
import { HRiver } from '@mpaas/hriver'
HRiver.updateApp(['90000002'], (result: boolean, code: number) => {
this.resultText = `90000002更新結(jié)果: ${result}`
})
配置公共離線包
設(shè)置
H5CommonAppProvider
。import { HRiver, H5CommonAppProvider } from '@mpaas/hriver' /** * 配置公共離線包 Provider,必須在 HRiver.init() 之前調(diào)用 */ HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
說明setProvider
必須在HRiver.init()
之前調(diào)用。實(shí)現(xiàn)
H5AppCommonProviderImpl.ets
的getCommonResourceAppList
方法。import { HRiver, H5CommonAppProvider } from '@mpaas/hriver' export class H5AppCommonProviderImpl extends H5CommonAppProvider { getCommonResourceAppList(): Array<string> { return ['20220719'] // 返回公共離線包id列表 } }
支持 fallback 邏輯
保持和 iOS/Android 一致,離線包沒下載成功情況下優(yōu)先打開 fallback 在線地址。
該功能默認(rèn)關(guān)閉,可以通過以下開關(guān)打開:
實(shí)現(xiàn) H5CommonAppProvider 的 configJSON 方法,增加 enableFallback 參數(shù)。
export class H5AppCommonProviderImpl extends H5CommonAppProvider {
... // 其他配置
// configJson,配置更新頻率等
configJSON(): string {
return JSON.stringify({
enableFallback: 'YES',
xxx // 其他配置
})
}
}
設(shè)置 UserAgent
import { HRiver } from '@mpaas/hriver'
HRiver.setUserAgent(userAgent)
setUserAgent
在 HRiver.init()
之后調(diào)用,會(huì)在默認(rèn) UserAgent
之后拼接設(shè)置的 useragent
。
設(shè)置離線包默認(rèn)更新頻率
設(shè)置
H5CommonAppProvider
。import { HRiver, H5CommonAppProvider } from '@mpaas/hriver' /** * 配置公共離線包Provider、離線包更新頻率等功能,必須在HRiver.init()之前調(diào)用 */ HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
說明setProvider
必須在HRiver.init()
之前調(diào)用。實(shí)現(xiàn)
H5CommonAppProvider
的configJSON
方法,代碼示例如下。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\"}" }) } }
具體參數(shù)如下:
h5_nbmngconfig: "{\"config\":{\"al\":\"3\",\"pr\":{\"4\":\"86400\",\"common\":\"864000\"},\"ur\":\"1800\",\"fpr\":{\"common\":\"3888000\"}},\"switch\":\"yes\"}"
其中的
ur: 1800
表示更新頻率為 1800 秒,使用時(shí)修改ur
的值即可。
配置離線包簽名校驗(yàn)
設(shè)置
H5CommonAppProvider
。import { HRiver, H5CommonAppProvider } from '@mpaas/hriver' /** * 配置公共離線包Provider、離線包更新頻率、簽名校驗(yàn)等功能,必須在HRiver.init()之前調(diào)用 */ HRiver.setProvider(H5CommonAppProvider.name, new H5AppCommonProviderImpl())
說明setProvider
必須在HRiver.init()
之前調(diào)用。實(shí)現(xiàn)
H5CommonAppProvider
的shouldVerify
和pubKey
方法,代碼示例如下:import { HRiver, H5CommonAppProvider } from '@mpaas/hriver' export class H5AppCommonProviderImpl extends H5CommonAppProvider { ... // 其他配置 /** * 是否開啟離線包校驗(yàn),默認(rèn)關(guān)閉 * return: true表示開啟,false表示關(guān)閉 */ shouldVerify(): boolean { return false } // 離線包校驗(yàn)的公鑰,如果shouldVerify為false 則無需設(shè)置,否則必須設(shè)置公鑰 pubKey(): string { return '' } }
開啟調(diào)試模式
HRiver.enableDebug(true)
監(jiān)聽頁面生命周期
初始化完成后設(shè)置 provider。
import {H5PageLifeCycleProvider} from '@mpaas/hriver';
HRiver.setProvider(H5PageLifeCycleProvider.name, new H5PageLifeCycle())
H5PageLifeCycle
import { H5PageLifeCycleProvider, Page } from '@mpaas/hriver';
import { hilog } from '@kit.PerformanceAnalysisKit';
export class H5PageLifeCycle extends H5PageLifeCycleProvider {
onPageShow(routerName: string, page?: Page | undefined): void {
super.onPageShow(routerName, page);
hilog.debug(1, 'H5PageLifeCycle', "pageshow: " + page?.pageUrl)
}
onPageHide(routerName: string, page?: Page | undefined): void {
super.onPageHide(routerName, page);
hilog.debug(1, 'H5PageLifeCycle', "onPageHide: " + page?.pageUrl)
}
onPageCreate(page?: Page | undefined): void {
super.onPageCreate(page);
hilog.debug(1, 'H5PageLifeCycle', "onPageCreate: " + page?.pageUrl)
}
onPageExit(page?: Page | undefined): void {
super.onPageExit(page);
hilog.debug(1, 'H5PageLifeCycle', "onPageExit: " + page?.pageUrl)
}
onBackPress(page?: Page | undefined): boolean {
hilog.debug(1, 'H5PageLifeCycle', "onBackPress: " + page?.pageUrl)
return super.onBackPress(page);
}
}
支持注銷 Plugin
通過 Page 的 Page.ets 實(shí)現(xiàn)注銷。
// 根據(jù)action注銷
unregisterPluginByAction(action: string);
// 根據(jù)pluginName注銷
unregisterPluginByPluginName(name: string);
示例如下:
支持頁面嵌入模式
頁面嵌入模式基于 Navigation 實(shí)現(xiàn)。
創(chuàng)建離線包需要的 NavPathStack。
pageInfos: NavPathStack = new NavPathStack()
在頁面需要嵌入的位置添加空白組件,以下為示例:
重要mode 必須使用
NavigationMode.Stack
,否則橫豎屏/折疊屏切換有問題。Navigation(this.pageInfos) { Column() { // 空白頁面用于嵌入離線包頁面, 不用填任何內(nèi)容 }.width('100%') // 寬度根據(jù)需要 .backgroundColor(Color.Red) // 只是示例 .height(500) // 高度根據(jù)實(shí)際 }.navDestination(this.PagesMap) .mode(NavigationMode.Stack) // pagesMap實(shí)現(xiàn): 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') { // 其他業(yè)務(wù)的頁面 } }
啟動(dòng)離線包和在線頁面時(shí),需要添加第三個(gè)參數(shù)并傳入步驟 1 中創(chuàng)建的 NavPathStack,增加 embedPage 參數(shù)用來表示內(nèi)嵌頁面。
let param: Map<string, Object> = new Map<string, Object>() param.set('embedPage', 'YES') HRiver.startUrl('https://www.baidu.com', param, this.pageInfos) // HRiver.startApp('90000000', param, this.pageInfos)
添加返回事件攔截。
HRiver.setProvider(H5PageLifeCycleProvider.name, new H5PageLifeCycle())
import { H5PageLifeCycleProvider, Page } from '@mpaas/hriver'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { router } from '@kit.ArkUI'; export class H5PageLifeCycle extends H5PageLifeCycleProvider { onPageShow(routerName: string, page?: Page | undefined): void { super.onPageShow(routerName, page); hilog.debug(1, 'H5PageLifeCycle', "onPageShow: " + page?.pageUrl) } onPageHide(routerName: string, page?: Page | undefined): void { super.onPageHide(routerName, page); hilog.debug(1, 'H5PageLifeCycle', "onPageHide: " + page?.pageUrl) } onPageCreate(page?: Page | undefined): void { super.onPageCreate(page); hilog.debug(1, 'H5PageLifeCycle', "onPageCreate: " + page?.pageUrl) } onPageExit(page?: Page | undefined): void { super.onPageExit(page); hilog.debug(1, 'H5PageLifeCycle', "onPageExit: " + page?.pageUrl) } onBackPress(page?: Page | undefined): boolean { hilog.debug(1, 'H5PageLifeCycle', "onBackPress: " + page?.pageUrl) let navPathStack: NavPathStack|undefined = page?.getSession()?.getRouter()?.getNavPathStack() if (navPathStack && page && page.embedPage && navPathStack.size() == 1) { router.back() return true; } return super.onBackPress(page); } }
UI 定制
自定義導(dǎo)航欄
初始化完成后通過
provider
設(shè)置自定義導(dǎo)航欄。import {HRBuilder, RouterUtils, HRiver, H5CommonAppProvider, H5RouterNavStackProvider, CustomUIBuilderProvider, H5CacheProvider } from '@mpaas/hriver' HRiver.setProvider(CustomUIBuilderProvider.name, new CustomUIBuilderProviderImpl())
實(shí)現(xiàn)
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
為業(yè)務(wù)自定義titlebar
組件的全局 Builder。實(shí)現(xiàn)參考如下:/** * name: 自定義組件的名稱 * page: 自定義titlebar對應(yīng)的頁面Page */ @Builder export function CustomUIBuilder(name: string, p: Page) { if (name === 'titleBar') { CustomTitleBarComponent({page: p, titleBarData: p.titleBarData}) } }
CustomTitleBarComponent
為具體的標(biāo)題組件,titleBarData
為標(biāo)題欄所需要的數(shù)據(jù),數(shù)據(jù)發(fā)生變化會(huì)實(shí)時(shí)刷新。示例參考如下: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 }) { //如果設(shè)置了圖片標(biāo)題就只顯示圖片 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") } }
自定義離線包加載頁/錯(cuò)誤頁
初始化完成之后設(shè)置 Provider。
import { CustomLoadingBuilderProvider} from '@mpaas/hriver'; HRiver.setProvider(CustomLoadingBuilderProvider.name, new CustomLoadingBuilderProviderImpl())
實(shí)現(xiàn)
CustomLoadingBuilderProviderImpl
類。import { CustomLoadingBuilderProvider, H5Router, HRLoadingData } from '@mpaas/hriver'; import { CustomUIBuilder } from './CustomLoadingComponent'; export class CustomLoadingBuilderProviderImpl extends CustomLoadingBuilderProvider { getCustomUIBuilder(): WrappedBuilder<[string, HRLoadingData, H5Router]> { return wrapBuilder(CustomUIBuilder); } }
實(shí)現(xiàn)
CustomLoadingComponent.ets
類,其中通過loadingStatus
控制加載狀態(tài)。import { H5Router, HRLoadingData, LoadingStatus } from '@mpaas/hriver' const TAG: string = "CustomLoadingComponent" export const Loading_STATE_Init = 0 export const Loading_STATE_Start = 1 export const Loading_STATE_End = 2 export const Loading_STATE_Err = 3 @Builder export function CustomUIBuilder(name: string, loadingData: HRLoadingData, h5Router: H5Router) { if (name === 'loading') { CustomLoadingComponent({loadingStatus: loadingData.loadingStatus, h5Router: h5Router}) } } @Component export struct CustomLoadingComponent { @ObjectLink loadingStatus: LoadingStatus h5Router?: H5Router aboutToAppear(): void { } build() { Row() { Column() { Flex({ direction: FlexDirection.Row }) { //返回按鈕 Button() { Image($rawfile("icon/hriverback.webp")) .width(12) .height(20) } .width(48) .height('100%') .borderRadius(0) .backgroundColor(Color.Transparent) .align(Alignment.Center) .onClick((event) => { this.h5Router?.routerBack() }) }.width('100%') .height(48) Image(this.loadingStatus.icon ? this.loadingStatus.icon : $rawfile("icon/hriverloading.webp")) .width(40) .height(40) .margin({top: 38}) if (this.loadingStatus.state == Loading_STATE_Err || this.loadingStatus.state == Loading_STATE_Start){ Text(this.loadingStatus.state == Loading_STATE_Err ? `網(wǎng)絡(luò)不給力,請稍后再試 \n(${this.loadingStatus.code} ${this.loadingStatus.msg})` : this.loadingStatus.title) .fontSize(18) .margin({top: 15}) .textAlign(TextAlign.Center) } } .width('100%') .margin({ top: 48 }) } } }
自定義在線 URL 加載失敗的錯(cuò)誤頁
設(shè)置 Provider 攔截網(wǎng)頁錯(cuò)誤回調(diào)。
HRiver.setProvider(H5WebClientProvider.name, new H5WebClientProviderImpl());
在
H5WebClientProviderImpl
中實(shí)現(xiàn)onErrorReceive
方法。import { MPFramework } from '@mpaas/framework'; import { H5WebClientProvider, Page } from '@mpaas/hriver'; import { util } from '@kit.ArkTS'; export class H5WebClientProviderImpl extends H5WebClientProvider{ onErrorReceive(page: Page | undefined, request: WebResourceRequest | undefined, err: WebResourceError | undefined): boolean { let errorUrl = request?.getRequestUrl() let errorCode = err?.getErrorCode() if (errorCode == 403 || errorCode == 404) { // keep same with ios,not show errorPage for 404 and 403 // log(TAG, "ignoreErrorPage 404 or 403, return "); return true; } let lastUrl = page?.webcontroller?.getUrl() if (errorUrl == page?.pageUrl || errorUrl == `${page?.pageUrl}/`) { // 從rawfile中讀取自定義錯(cuò)誤頁面demo_custom_err.html let dataBytes = MPFramework.instance.context.resourceManager.getRawFileContentSync('demo_custom_err.html') let textDecoder = new util.TextDecoder("utf-8", { fatal: false, ignoreBOM: false }) let html = textDecoder.decodeWithStream(new Uint8Array(dataBytes), { stream: true }) page?.webcontroller?.loadData(html, "text/html", "utf-8", lastUrl) return true; } return false } }
在
demo_custom_err.html
文件中編寫錯(cuò)誤頁代碼。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="apple-mobile-web-app-capable" content="yes"/> <meta name="apple-mobile-web-app-status-bar-style" content="black"/> <meta name="format-detection" content="telephone=no"/> <meta name="format-detection" content="email=no"/> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0"/> <title>!!!!</title> <style type="text/css"> body { background-color: #FFF; } .am-page-result { text-align: center; } .am-page-result .am-page-result-pic { width: 135px; height: 135px; margin: 40px auto; } .am-page-result .am-page-result-pic img { width: 100%; height: 100%; } .am-page-result p { margin: 0; font-size: 16px; color: #999; } .am-page-result-button { margin-top: 25px; display: -webkit-box; display: -webkit-flex; display: flex; } .am-button { display: block; margin: 0 10px; padding: 0 10px; height: 42px; text-align: center; font-size: 18px; line-height: 42px; border-radius: 4px; outline: 0; -webkit-appearance: none; -webkit-box-flex: 1; -webkit-flex: 1; flex: 1; width: 50%; } .am-button[am-mode~=white] { border: 1px solid #DDD; color: #666; background-color: #FFF; } .am-button[am-mode~=white]:active { border-color: #D8D8D8; background-color: #F8F8F8; } .am-button[am-mode~=blue] { border: 1px solid #28F; color: #FFF; background-color: #39F; } .am-button[am-mode~=blue]:active { border-color: #17F; background-color: #28F; } .am-button[am-mode~=light], .am-button[am-mode~=light]:active { border: none; color: #39F; background-color: #FFF; } @media screen and (min-device-width: 375px) { .am-page-result .am-page-result-pic { width: 160px; height: 160px; margin: 45px auto; } .am-page-result-button { margin-top: 30px; } .am-button { margin: 0 20px; height: 44px; line-height: 44px; } } @media screen and (min-device-width: 414px) { .am-page-result .am-page-result-pic { width: 180px; height: 180px; margin: 50px auto; } .am-button { margin: 0 24px; height: 50px; line-height: 50px; } } </style> <body> <div class="am-page-result"> <div class="am-page-result-pic"> <img src="data:image/png;base64,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"/> </div> <p>這是自定義錯(cuò)誤頁面</p> </div> </body> <script> </script> </html>
設(shè)置和原生 View 一起滾動(dòng)
//在啟動(dòng)參數(shù)里添加
// scrollForward: 0: SELF_ONLY, 1: SELF_FIRST, 2: PARENT_FIRST, 3 : PARALLEL
// scrollBackward: 0: SELF_ONLY, 1: SELF_FIRST, 2: PARENT_FIRST, 3 : PARALLEL
param.set("scrollForward", 2)
param.set("scrollBackward", 1)
支持限制 Web 組件寬度
通過啟動(dòng)參數(shù)控制。
params.set('webWidth', xxx)。 // 參數(shù)支持string ('100%'百分比方式) 或者number (例如800表示800px)
動(dòng)態(tài)控制。
page.setWebWidth(webWidth: string | number)
鴻蒙 Web 行為定制
H5WebClientProvider
可以通過實(shí)現(xiàn) H5WebClientProvider
修改鴻蒙 H5 容器 Web 的一些默認(rèn)行為 API 。
HRiver.setProvider(H5WebClientProvider.name, new H5WebClientProviderImpl())
可定制的 API 如下:
export class H5WebClientProvider {
// 頁面http錯(cuò)誤回調(diào)
onHttpErrorReceive(page: Page | undefined, request: WebResourceRequest | undefined, response: WebResourceResponse | undefined) {
}
// 頁面下載回調(diào)
onDownloadStart(page: Page | undefined, url: string | undefined, userAgent: string | undefined, contentDisposition: string | undefined,
mimetype: string | undefined, contentLength: number | undefined) {
}
// 頁面ssl錯(cuò)誤回調(diào)
onSslErrorEventReceive(page: Page | undefined, handler: SslErrorHandler, error: SslError) {
}
// 頁面錯(cuò)誤回調(diào)
onErrorReceive(page: Page | undefined, request: WebResourceRequest | undefined, error: WebResourceError | undefined): boolean {
return false
}
// 全屏回調(diào)
onFullScreenEnter(page: Page | undefined, handler: FullScreenExitHandler) {
}
// 退出全屏回調(diào)
onFullScreenExit(page: Page | undefined) {
}
// web權(quán)限申請回調(diào)
onPermissionRequest(page: Page | undefined, request: PermissionRequest | undefined) {
}
// web screencapturerequest回調(diào)
onScreenCaptureRequest(page: Page | undefined, handler: ScreenCaptureHandler | undefined) {
}
onPageBegin(page: Page | undefined, url: string | undefined) {
}
onAppear(page: Page | undefined) {
}
// web scroll回調(diào)
onScroll(x: number, y: number, page: Page | undefined) {
}
getWindow(context: Context, page: Page | undefined): Promise<window.Window> | undefined {
return undefined
}
// web 長按菜單
onContextMenuShow(param: WebContextMenuParam | undefined, result: WebContextMenuResult | undefined) {
return false
}
// web 文件選擇回調(diào)
onShowFileSelector(fileSelector: FileSelectorParam, result: FileSelectorResult, page: Page | undefined) {
return false
}
// web 定位相關(guān)回調(diào)
onGeolocationShow(origin: string | undefined, geoLocation: JsGeolocation | undefined, page: Page | undefined) {
}
// web 定位相關(guān)回調(diào)
onGeolocationHide(page: Page | undefined) {
}
}
H5MixModeSettingProvider
可以通過 H5MixModeSettingProvider
設(shè)置 Web 支持 HTTP/HTTPS 的 MixedMode
,具體使用如下:
HRiver.setProvider(H5MixModeSettingProvider.name, new H5MixModeSettingProviderImpl()) // 業(yè)務(wù)實(shí)現(xiàn)H5MixModeSettingProviderImpl
export class H5MixModeSettingProviderImpl extends H5MixModeSettingProvider {
mixMode(page: Page | undefined): MixedMode {
// 根據(jù)業(yè)務(wù)實(shí)際情況返回對應(yīng)的MixedMode
return MixedMode.Compatible
}
}
鴻蒙系統(tǒng)不支持在 HTTPS 頁面加載地址為 HTTP 的 IP 鏈接,要么加載 HTTPS 的 IP 的鏈接,要么加載 HTTP 的非 IP 鏈接。
頁面路由支持 Navigation
默認(rèn)頁面路由使用 router 方式,鴻蒙 router 方式不支持關(guān)閉棧中某個(gè)頁面,只能一級級回退。離線包支持 Navigation 模式:
支持關(guān)閉棧中頁面
支持分欄模式
全局 Navigation 模式
HRiver 初始化完成后,在啟動(dòng)離線包之前,需設(shè)置
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 } }
在
navDestination
中配置builder
,builder
中加載 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') { // 其他業(yè)務(wù)的頁面 } } build() { Navigation(this.pageInfos) { Row() { Column() { // 業(yè)務(wù)頁面 MainPage() } .width('100%') } }.navDestination(this.PagesMap) }
離線包獨(dú)立使用 Navigation 模式
HRiver.startApp
/HRiver.startUrl
的第三個(gè)參數(shù)傳入 NavPathStack 即可。參考 全局 Navigation 模式 中的步驟 2。