鸿蒙-Web

类似于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,可以在回调中使用loadUrlgetWebId等操作网页不相关的接口。但因该回调调用时网页还未加载,因此无法在回调中使用有关操作网页的接口,例如zoomInzoomOut等。

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());

加速Web页面的访问

相关推荐
码爸18 分钟前
flink doris批量sink
java·前端·flink
深情废杨杨20 分钟前
前端vue-父传子
前端·javascript·vue.js
J不A秃V头A1 小时前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂2 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客2 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹3 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码3 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!4 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr4 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林4 小时前
npm发布插件超级简单版
前端·npm·node.js