类似于Android中的WebView,加载网页用的。需添加网络权限:ohos.permission.INTERNET,导包
ts
import { webview } from '@kit.ArkWeb';
一 web 生命周期
组件的aboutToAppear(和Web无关)
一般建议在此设置WebDebug调试模式 setWebDebuggingAccess
、设置Web内核自定义协议URL的跨域请求与fetch请求的权限 customizeSchemes
、设置Cookie configCookie
等。
ts
aboutToAppear(): void {
console.error(`aboutToAppear 到达这里的时间:${Date.now() - this.currentTimestamp}`)
try {
// 设置调试
webview.WebviewController.setWebDebuggingAccess(true);
// 设置cookie
webview.WebCookieManager.configCookieSync('https://www.example.com', 'a=b')
// 设置Web内核自定义协议URL的跨域请求与fetch请求的权限 customizeSchemes
let scheme1: webview.WebCustomScheme = { schemeName: "name1", isSupportCORS: true, isSupportFetch: true };
let scheme2: webview.WebCustomScheme = { schemeName: "name2", isSupportCORS: true, isSupportFetch: true };
let scheme3: webview.WebCustomScheme = { schemeName: "name3", isSupportCORS: true, isSupportFetch: true };
webview.WebviewController.customizeSchemes([scheme1, scheme2, scheme3]);
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}
onControllerAttached事件
当Controller成功绑定到Web组件时触发该回调,推荐在此事件中注入JS对象registerJavaScriptProxy(这种注册必须在调用refresh)
、设置自定义用户代理setCustomUserAgent
,可以在回调中使用loadUrl
,getWebId
等操作网页不相关的接口。但因该回调调用时网页还未加载,因此无法在回调中使用有关操作网页的接口,例如zoomIn
、zoomOut
等。
ts
Web({ src: this.url, controller: this.controller })
.onControllerAttached(() => {
// 注册 jsbridge,类,h5中的名字,注册的方法
this.controller.registerJavaScriptProxy(this.webTestObj, "objTestName", ["webTest"]);
// 这种注册必须调用refresh
this.controller.refresh()
// 拿到当前的UserAgent
let userAgent = this.controller.getUserAgent() + ' appVersion/1.0.0';
console.log(`userAgent=> ${userAgent}}`)
// 设置新的UserAgent
this.controller.setCustomUserAgent(userAgent);
})
onLoadIntercept
事件:当Web组件加载url之前触发该回调,用于判断是否阻止此次访问。默认允许加载。 可以拿到当前的url,等一下信息,当点击网页中的链接需要跳转到应用内其他页面时,可以通过使用Web组件的onLoadIntercept()接口来实现 官房推荐用这个
,不要用onOverrideUrlLoading了
ts
.onLoadIntercept((event) => {
if (event) {
console.log('--------------- onLoadIntercept start ---------------')
console.log('onLoadIntercept url:' + event.data.getRequestUrl())
console.log('getRequestMethod:' + event.data.getRequestMethod())
console.log('header:' + event.data.getRequestHeader())
console.log('url:' + event.data.getRequestUrl())
console.log('isMainFrame:' + event.data.isMainFrame())
console.log('isRedirect:' + event.data.isRedirect())
console.log('isRequestGesture:' + event.data.isRequestGesture())
console.log('--------------- onLoadIntercept end ---------------')
}
let url: string = event.data.getRequestUrl();
// 如果是http协议继续加载
if (url.startsWith("http")) {
// 是网页,直接返回false
return true
}
// 比如是Native页面,自己的非网页页面 , native:// 是自己的定义,一般咱们也是通过Bridge去做的
// 比如 native://pages/mine
if (url.indexOf('native://') === 0) {
// 是网页,直接返回false
router.pushUrl({ url: 'pages/mine' });
return true
}
// 其他协议比如 alipay://dl/scan 扫一扫 ,直接打开 支付宝扫一扫,不用加载了 ,直接打开
// 这里是打开逻辑
let context = getContext(this) as common.UIAbilityContext;
// 打开其他应用界面
context.openLink(event.data.getRequestUrl())
// 返回true表示阻止此次加载,否则允许此次加载
return false
})
onOverrideUrlLoading
事件:当URL将要加载到当前Web中时,让宿主应用程序有机会获得控制权,回调函数,一般比如 是http协议就直接false,继续加载,其他协议,比如微信的协议,直接打开微信即可
- 返回true将导致当前Web中止加载URL,而
- 返回false则会导致Web继续照常加载URL。
ts
.onOverrideUrlLoading((webResourceRequest: WebResourceRequest) => {
// 如果是http协议继续加载
if (webResourceRequest && webResourceRequest.getRequestUrl().startsWith("http")) {
// 是网页,直接返回false
return false
}
// 其他协议比如 alipay://dl/scan 扫一扫 ,直接打开 支付宝扫一扫,不用加载了 ,直接打开
// 这里是打开逻辑
let context = getContext(this) as common.UIAbilityContext;
// 打开其他应用界面
context.openLink(webResourceRequest.getRequestUrl())
return false;
})
onInterceptRequest
web 请求资源的时候,比如 url,js ,css,图片等,在这里我们可以构建离线包
,返回自己的资源,比如下面是替换所有的网页图片为自己的,如果返回null,则走web自己的加载逻辑
,可以在header中添加ResponseDataID,加快js 响应
ResponseDataID
为自定义的JavaScript请求响应生成 CodeCache:自定义请求响应的资源类型如果是JavaScript脚本,可以在响应头中添加"ResponseDataID"字段,Web内核读取到该字段后会在为该JS资源生成CodeCache,加速JS执行,并且ResponseData如果有更新时必须更新该字段。不添加"ResponseDataID"字段的情况下默认不生成CodeCache。
ts
.onInterceptRequest((event) => {
if (event) {
// 是图片的正则表达式
const imageRegex = /\.(jpg|jpeg|png|gif|bmp|webp)(?:\?.*)?$/i;
if (imageRegex.test(event.request.getRequestUrl())) {
console.log(`onInterceptRequest=> ${event.request.getRequestUrl()}`)
// 图片,全部替换成本地的一个图片
let responseWeb: WebResourceResponse = new WebResourceResponse();
responseWeb.setResponseHeader(this.heads);
// 1.要设置的资源响应数据。string表示HTML格式的字符串。
// 2. number表示文件句柄, 此句柄由系统的Web组件负责关闭。
// 3. Resource表示应用rawfile目录下文件资源。
// 4. ArrayBuffer表示资源的原始二进制数据。
// ResponseDataID
// 构造响应数据
// 为自定义的JavaScript请求响应生成 CodeCache:自定义请求响应的资源类型如果是JavaScript脚本,
// 可以在响应头中添加"ResponseDataID"字段,Web内核读取到该字段后会在为该JS资源生成CodeCache,
// 加速JS执行,并且ResponseData如果有更新时必须更新该字段。不添加"ResponseDataID"字段的情况下默认不生成CodeCache。
responseWeb.setResponseHeader([
{
// 格式:不超过13位纯数字。js识别码,Js有更新时必须更新该字段
headerKey: "ResponseDataID",
headerValue: "0000000000001"
}]);
responseWeb.setResponseData($rawfile('img1.webp'));
responseWeb.setResponseMimeType('image/webp');
responseWeb.setResponseEncoding('utf-8');
responseWeb.setResponseCode(200);
responseWeb.setReasonMessage('OK');
responseWeb.setResponseIsReady(true)
return responseWeb
}
}
// 返回响应数据则按照响应数据加载,无响应数据则返回null表示按照原来的方式加载
return null;
})
onPageBegin
网页开始加载时触发该回调 ,loading开始
onProgressChange
加载进度变化,100% 有可能走多次
onPageEnd
web 加载完成 loading 消失,推荐在此事件中执行JavaScript脚本比如
javascript
.onPageBegin((event) => {
// h5 开始加载
if (event) {
console.log(`onPageBegin: ${event.url}`);
// 显示loading
this.loadingVisibility = Visibility.Visible
}
})
.onProgressChange((event) => {
// h5 加载进度变化,100% 有可能走多次
if (event) {
console.log('newProgress:' + event.newProgress);
// 显示loading 进度
this.progress = event.newProgress
}
})
.onPageEnd((event) => {
// 推荐在此事件中执行JavaScript脚本
if (event) {
console.log('onPageEnd url:' + event.url);
// 隐藏loading
this.loadingVisibility = Visibility.None
// 执行JavaScript脚本
this.controller.runJavaScript('htmlTestNoParam()')
}
})
其他的一些属性
-
onScroll 网页滚动条滚动位置。
-
onConsole
h5的打印信息
-
onErrorReceive
接收到错误
网页加载遇到错误时触发该回调。出于性能考虑,建议此回调中尽量执行简单逻辑。在无网络的情况下,触发此回调 -
onHttpErrorReceive 网页加载资源遇到的HTTP错误(响应码>=400)时触发该回调 ,比如请求资源502
-
onTitleReceive 接收到h5 title 的,
一般咱们不需要处理
-
domStorageAccess:设置是否开启文档对象模型存储接口(DOM Storage API)权限,默认未开启
-
fileAccess 是否可以读存储的html,api11 默认是true ,api12 默认是false ,$rawfile(filepath/filename)
不受限制,都可以读到
-
imageAccess(true) 是否允许自动加载图片资源 默认允许
-
javaScriptAccess 设置是否允许执行JavaScript脚本,
默认允许执行,一般咱们也是true,防止修改默认方式,直接写true
-
overScrollMode OverScrollMode和父的滑动方式 还有这个属性
nestedScroll
NestedScrollOptions -
mixedMode是否 HTTP 和 HTTPS 混合使用 默认是false
-
zoomAccess,设置是否支持手势进行缩放,默认允许执行缩放 ,
咱们app一般不允许
-
overviewModeAccess 设置是否使用概览模式加载网页,默认使用该方式
-
databaseAccess 设置是否开启数据库存储API权限,默认不开启
-
geolocationAccess 设置是否开启获取地理位置权限,默认开启,
一般这样的需求,咱们就是用桥接
-
mediaPlayGestureAccess 设置有声视频播放是否需要用户手动点击,静音视频播放不受该接口管控,默认需要。
-
multiWindowAccess 设置是否开启多窗口权限,默认不开启。一般也不需要
-
horizontalScrollBarAccess 设置是否显示横向滚动条,包括系统默认滚动条和用户自定义滚动条。默认显示 ,
咱们肯定不希望有
-
verticalScrollBarAccess 默认显示 ,
咱们肯定不希望有
-
cacheMode 要设置的缓存模式。CacheMode.Default ,咱们一般也是CacheMode.Default这种方式,完全按照http协议的来
-
textZoomRatio 设置页面的文本缩放百分比,默认为100%。
如果不设置,web的字体随着手机字体大小变化,固定之后就不会随着系统变化了
-
initialScale 设置整体页面的缩放百分比,默认为100。
-
userAgent设置userAgent 已废弃,使用 controller.setCustomUserAgent -
blockNetwork 设置Web组件是否阻止从网络加载资源。默认是false,一般也是false
-
defaultFixedFontSize 默认是13 设置网页的默认等宽字体大小。
-
defaultFontSize 默认是16,设置网页的默认字体大小。
-
minFontSize 设置网页字体大小最小值
-
minLogicalFontSize 设置网页逻辑字体大小最小值
-
webFixedFont 设置网页的fixed font字体库。webSansSerifFont,webStandardFont,webFantasyFont,webCursiveFont 字体
-
darkMode(mode: WebDarkMode) 设置Web深色模式,默认关闭
-
forceDarkAccess(access: boolean)设置网页是否开启强制深色模式。默认关闭。该属性仅在darkMode开启深色模式时生效。
-
pinchSmooth 设置网页是否开启捏合流畅模式,默认不开启。
-
mediaOptions(options: WebMediaOptions) 设置Web媒体播放的策略,其中包括:Web中的音频在重新获焦后能够自动续播的有效期、应用内多个Web实例的音频是否独占。
-
javaScriptOnDocumentStart,javaScriptOnDocumentEnd 将JavaScript脚本注入到Web组件中,当指定页面或者文档加载完成时,
-
layoutMode(mode: WebLayoutMode) 设置Web布局模式。
-
defaultTextEncodingFormat 默认是utf-8 设置网页的默认字符编码。
-
metaViewport 设置meta标签的viewport属性是否可用。
-
textAutosizing 设置使能文本自动调整大小。
-
enableNativeMediaPlayer 开启应用接管网页媒体播放功能。
-
selectionMenuOptions Web组件自定义菜单扩展项接口,允许用户设置扩展项的文本内容、图标、回调方法。
-
onAlert 网页触发alert()告警弹窗时触发回调。
一般咱们不需要关心
-
onBeforeUnload 刷新或关闭场景下,在即将离开当前页面时触发此回调。刷新或关闭当前页面应先通过点击等方式获取焦点,才会触发此回调。
-
onConfirm 网页调用confirm()告警时触发此回调
-
onPrompt 网页调用prompt()告警时触发此回调。
-
onDownloadStart 通知主应用开始下载一个文件
-
onRefreshAccessedHistory 加载网页页面完成时触发该回调,用于应用更新其访问的历史链接。
-
onRenderProcessNotResponding 网页进程无响应时触发该回调函数。
-
onRenderProcessResponding 网页进程由无响应状态变回正常运行状态时触发该回调函数,该回调表明该网页并非真正卡死。
-
onShowFileSelector 调用此函数以处理具有"文件"输入类型的HTML表单。如果不调用此函数或返回false,Web组件会提供默认的"选择文件"处理界面。如果返回true,
应用可以自定义"选择文件"的响应行为。
比如选择图片 -
onResourceLoad 通知Web组件所加载的资源文件url信息
-
onScaleChange 当前页面显示比例的变化时触发该回调
-
onHttpAuthRequest 通知收到http auth认证请求。
-
onSslErrorEventReceive 通知用户加载资源时发生SSL错误,只支持主资源
-
onSslErrorEvent 通知用户加载资源(主资源+子资源)时发生SSL错误,如果只想处理主资源的SSL错误
-
onPermissionRequest 当网页请求权限的时候,应该是只有摄像头和录音,暂不考虑吧
-
onClientAuthenticationRequest 通知用户收到SSL客户端证书请求事件
-
onContextMenuShow 长按特定元素(例如图片,链接)或鼠标右键,跳出菜单
-
onContextMenuHide 长按特定元素(例如图片,链接)或鼠标右键
-
onFullScreenEnter
通知开发者Web组件进入全屏模式。
-
onFullScreenExit
应该是视频全屏的时候用到的吧
-
onInterceptKeyEvent 设置键盘事件的回调函数
-
onAudioStateChanged 设置网页上的音频播放状态发生改变时的回调函数。
-
onRequestSelected 当Web组件获得焦点时触发该回调
-
onScreenCaptureRequest 通知收到屏幕捕获请求
-
onOverScroll 该接口在网页过度滚动时触发,用于通知网页过度滚动的偏移量
-
onNavigationEntryCommitted 当网页跳转提交时触发该回调。
-
onSafeBrowsingCheckResult 收到网站安全风险检查结果时触发的回调
-
onNativeEmbedLifecycleChange 当Embed标签生命周期变化时触发该回调。
-
onNativeEmbedGestureEvent 当手指触摸到同层渲染标签时触发该回调。
-
onIntelligentTrackingPreventionResult 智能防跟踪功能使能时,当追踪者cookie被拦截时触发该回调。
-
onViewportFitChanged 网页meta中viewport-fit配置项更改时触发该回调,应用可在此回调中自适应布局视口
-
onInterceptKeyboardAttach 网页中可编辑元素(如input标签)拉起软键盘之前会回调该接口,应用可以使用该接口拦截系统软键盘的弹出,配置应用定制的软键盘(应用根据该接口可以决定使用系统默认软键盘/定制enter键的系统软键盘/全部由应用自定义的软键盘
-
onPageVisible 事件:当HTTP响应的主体开始加载,新页面即将可见时触发该回调,且只在主frame触发。此回调在文档加载的早期触发,因此链接的资源比如在线CSS、在线图片等可能尚不可用。
-
onRenderExited事件: 应用渲染进程异常退出时触发该回调, 可以在此回调中进行系统资源的释放、数据的保存等操作。如果应用希望异常恢复,需要调用loadUrl接口重新加载页面。
-
onDisAppear事件: 组件卸载消失时触发此回调。该事件为通用事件,指组件从组件树上卸载时触发的事件。
-
onFirstContentfulPaint事件: 网页首次内容绘制的回调函数。首次绘制文本、图像、非空白Canvva或者SVG的时间点。
-
onFirstMeaningfulPaint事件: 网页首次有效绘制的回调函数。首次绘制页面主要内容的时间点。
-
onLargestContentfulPaint事件: 网页绘制页面最大内容的回调函数。可视区域内容最大的可见元素开始出现在页面上的时间点。
二 jsbridge
Native调用js
官网有个坑,js调用的不能是方法重载
ts
// 调用
this.controller.runJavaScript('htmlTestHasParam(1)')
this.controller.runJavaScript('htmlTestNoParam()')
下面是h5
js
// 调用有参函数时实现。
function htmlTestHasParam(param) {
document.getElementById('text').style.color = 'green';
}
// 调用无参函数时实现。
function htmlTestNoParam() {
document.getElementById('text2').style.color = 'red';
}
js调用Native
有两种方法,
第一是 在onControllerAttached中调用controller.registerJavaScriptProxy,之后必须调用controller.refresh
ts
.onControllerAttached(() => {
// // 注册 jsbridge,类,h5中的名字,注册的方法
this.controller.registerJavaScriptProxy(this.webTestNew, "objTestNameNew", ["callNativeNew"]);
// 这种注册必须调用refresh
this.controller.refresh()
})
第二是.javaScriptProxy()
methodList 同步方法 ,asyncMethodList 异步方法
ts
.javaScriptProxy({
object: this.webTestObj,
name: "objTestName",
methodList: ["callNative"],
controller: this.controller
asyncMethodList:['asyncMethodList']
})
三 另一种jsbridge - WebMessagePort 只是通信,拿不到返回值
在Web的onPageEnd中创建WebMessagePort
ts
initPorts() {
try {
// 1、创建两个消息端口。
this.ports = this.controller.createWebMessagePorts();
// 2、在应用侧的消息端口(如端口1)上注册回调事件。
this.ports[1].onMessageEvent((result: webview.WebMessage) => {
let msg = 'Got msg from HTML:';
if (typeof (result) === 'string') {
console.info(`received string message from html5, string is: ${result}`);
msg = msg + result;
} else if (typeof (result) === 'object') {
if (result instanceof ArrayBuffer) {
console.info(`received arraybuffer from html5, length is: ${result.byteLength}`);
msg = msg + 'lenght is ' + result.byteLength;
} else {
console.info('not support');
}
} else {
console.info('not support');
}
this.receivedFromHtml = msg;
})
// 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。
this.controller.postMessage('__init_port__', [this.ports[0]], '*');
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
}
提前创建webview
支持命令式创建Web组件,这种方式创建的组件不会立即挂载到组件树,即不会对用户呈现(组件状态为Hidden和InActive),开发者可以在后续使用中按需动态挂载。后台启动的Web实例不建议超过200个。
EntryAbility中
javascript
import { createNWeb } from '../component/common';
createNWeb("https://www.example.com", windowStage.getMainWindowSync().getUIContext());