【每日学点HarmonyOS Next知识】Web跨域资源、Web长按菜单、Web拦截请求、禁止录屏、Base64图片宽高

1、HarmonyOS Web组件本地资源跨域问题?

关于资源跨域问题的解决,可以参考以下官网文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-cross-origin-V5

方法一

为了使Web组件能够成功访问跨域资源,开发者应采用http或https等协议,替代原先使用的file或resource协议进行加载。其中,替代的url域名为自定义构造的仅供个人或者组织使用的域名,以避免与互联网上实际存在的域名产生冲突。同时,开发者需利用Web组件的onInterceptRequest方法,对本地资源进行拦截和相应的替换。

以下结合示例说明如何解决本地资源跨域访问失败的问题。其中,index.html和js/script.js置于工程中的rawfile目录下。如果使用resource协议访问index.html,js/script.js将因跨域而被拦截,无法加载。在示例中,使用https://www.example.com/域名替换了原本的resource协议,同时利用onInterceptRequest接口替换资源,使得js/script.js可以成功加载,从而解决了跨域拦截的问题。

// main/ets/pages/Index.ets
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  webviewController: webview.WebviewController = new webview.WebviewController();
  // 构造域名和本地文件的映射表
  schemeMap = new Map([
    ["https://www.example.com/index.html", "index.html"],
    ["https://www.example.com/js/script.js", "js/script.js"],
  ])
  // 构造本地文件和构造返回的格式mimeType
  mimeTypeMap = new Map([
    ["index.html", 'text/html'],
    ["js/script.js", "text/javascript"]
  ])

  build() {
    Row() {
      Column() {
        // 针对本地index.html,使用http或者https协议代替file协议或者resource协议,并且构造一个属于自己的域名。
        // 本例中构造www.example.com为例。
        Web({ src: "https://www.example.com/index.html", controller: this.webviewController })
          .javaScriptAccess(true)
          .fileAccess(true)
          .domStorageAccess(true)
          .geolocationAccess(true)
          .width("100%")
          .height("100%")
          .onInterceptRequest((event) => {
            if (!event) {
              return;
            }
            // 此处匹配自己想要加载的本地离线资源,进行资源拦截替换,绕过跨域
            if (this.schemeMap.has(event.request.getRequestUrl())) {
              let rawfileName: string = this.schemeMap.get(event.request.getRequestUrl())!;
              let mimeType = this.mimeTypeMap.get(rawfileName);
              if (typeof mimeType === 'string') {
                let response = new WebResourceResponse();
                // 构造响应数据,如果本地文件在rawfile下,可以通过如下方式设置
                response.setResponseData($rawfile(rawfileName));
                response.setResponseEncoding('utf-8');
                response.setResponseMimeType(mimeType);
                response.setResponseCode(200);
                response.setReasonMessage('OK');
                response.setResponseIsReady(true);
                return response;
              }
            }
            return null;
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

<!-- main/resources/rawfile/index.html -->
<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<script crossorigin src="./js/script.js"></script>
</body>
</html>

// main/resources/rawfile/js/script.js
const body = document.body;
const element = document.createElement('div');
element.textContent = 'success';
body.appendChild(element);

方法二

通过setPathAllowingUniversalAccess设置一个路径列表。当使用file协议访问该列表中的资源时,允许进行跨域访问本地文件。此外,一旦设置了路径列表,file协议将仅限于访问列表内的资源(此时,fileAccess的行为将会被此接口行为覆盖)。路径列表中的路径必须符合以下任一路径格式:

  1. 应用文件目录通过Context.filesDir获取,其子目录示例如下:

    • /data/storage/el2/base/files/example
    • /data/storage/el2/base/haps/entry/files/example
  2. 应用资源目录通过Context.resourceDir获取,其子目录示例如下:

    • /data/storage/el1/bundle/entry/resource/resfile
    • /data/storage/el1/bundle/entry/resource/resfile/example
      当路径列表中的任一路径不满足上述条件时,系统将抛出异常码401,并判定路径列表设置失败。若设置的路径列表为空,file协议的可访问范围将遵循fileAccess的规则,具体示例如下。

    // main/ets/pages/Index.ets
    import { webview } from '@kit.ArkWeb';
    import { BusinessError } from '@kit.BasicServicesKit';

    @Entry
    @Component
    struct WebComponent {
    controller: WebviewController = new webview.WebviewController();

    build() {
    Row() {
    Web({ src: "", controller: this.controller })
    .onControllerAttached(() => {
    try {
    // 设置允许可以跨域访问的路径列表
    this.controller.setPathAllowingUniversalAccess([
    getContext().resourceDir,
    getContext().filesDir + "/example"
    ])
    this.controller.loadUrl("file://" + getContext().resourceDir + "/index.html")
    } catch (error) {
    console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message});
    }
    })
    .javaScriptAccess(true)
    .fileAccess(true)
    .domStorageAccess(true)
    }
    }
    }

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Demo</title> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, viewport-fit=cover"> <script> function getFile() { var file = "file:///data/storage/el1/bundle/entry/resources/resfile/js/script.js"; // 使用file协议通过XMLHttpRequest跨域访问本地js文件。 var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.onreadystatechange = function(){ console.log("readyState:" + xmlHttpReq.readyState); console.log("status:" + xmlHttpReq.status); if(xmlHttpReq.readyState == 4){ if (xmlHttpReq.status == 200) { // 如果ets侧正确设置路径列表,则此处能正常获取资源 const element = document.getElementById('text'); element.textContent = "load " + file + " success"; } else { // 如果ets侧不设置路径列表,则此处会触发CORS跨域检查错误 const element = document.getElementById('text'); element.textContent = "load " + file + " failed"; } } } xmlHttpReq.open("GET", file); xmlHttpReq.send(null); } </script> </head> <body>
    <button id="example" onclick="getFile()">stealFile</button>
    </body> </html>

    // main/resources/rawfile/js/script.js
    const body = document.body;
    const element = document.createElement('div');
    element.textContent = 'success';
    body.appendChild(element);

2、HarmonyOS web里需要实现长按弹出菜单保存图片,有类似getHitTestResult的方法吗?

可以参考下web组件中的onContextMenuShow事件,长按特定元素(例如图片,链接)或鼠标右键,跳出菜单。具体参考下面文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5#oncontextmenushow9

暂时无法控制长按弹框的条件,可以尝试下从h5侧通过控制事件和CSS方式控制选择框

3、HarmonyOS web拦截应用跳转和自定义请求响应对应demo?

web拦截和自定义请求响应,可以参考官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-resource-interception-request-mgmt-V5

Web组件支持在应用拦截到页面请求后自定义响应请求能力。开发者通过onInterceptRequest()接口来实现自定义资源请求响应 。自定义请求能力可以用于开发者自定义Web页面响应、自定义文件资源响应等场景。

Web网页上发起资源加载请求,应用层收到资源请求消息。应用层构造本地资源响应消息发送给Web内核。Web内核解析应用层响应信息,根据此响应信息进行页面资源加载。

4、HarmonyOS 如何禁止单个page页面录屏截屏 ;禁止某个dialog 录屏截屏 如dialog 安全密码键盘?

现在需要在某些page 页面、dialog,不让录屏和截屏

可以通过setWindowPrivacyMode设置窗口为隐私模式后,截屏录屏或分享屏幕,屏幕会显示灰色蒙层(隐私窗口不允许这些操作)

可参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-window-V5#setwindowprivacymode9

setWindowPrivacyMode

setWindowPrivacyMode(isPrivacyMode: boolean, callback: AsyncCallback): void

设置窗口是否为隐私模式,使用callback异步回调。设置为隐私模式的窗口,窗口内容将无法被截屏或录屏。此接口可用于禁止截屏/录屏的场景。

5、HarmonyOS 如何获取 base64图片的图片原始宽高? 图片验证码场景,服务端返回两张base64 格式图片 背景图与验证图,需要根据背景图、原图大小计算缩放系数,从而计算验证图的大小与定位信息

使用Image Kit的能力,参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-image-V5#imageinfo

demo:

import util from '@ohos.util';
import { image } from '@kit.ImageKit';
@Entry
@Component
struct Index {
  @State message: string = 'getImage';
  @StorageLink('test') test: object = new Object;
  @State imageBase64: string =
    'iVBORw0KGgoAAAANSUhEUgAAADwAAAAUCAYAAADRA14pAAABN0lEQVR42mP4P8IAAy0Mjf6xAYxHnIcHo6cZaOlZYj38VbESjIech5E9SayHYZ5FxnT1cL7uFwxMbt4lxtPYPElLjzNg8ywhMWp6GOZBeiVzDA/jinFySmZSkzUpHn5oLosXk+1hYj2NXliRUnjh8hy5MYzP0wzEeIzUvEyNGCY3WZMUw5Qm61EPjzQPkwIGjYfp4VlsnianIULIs3gbHvT2LLZWFzVLZ7xNS3p7lBqAGM+CPZy6o+w/DGfvrv5ffagTjtuOT/4/8cxcOF50Zc3/5dc3wvHeh0fh+PDjk/8vv74Bx/c+PPz/8utrOP7559fg8LD/uqT/A4GpHdB7Q/XBmFBAMyBLPv70DCWWTjw7h2L42pvbUCxGdlTPqRkoji7Y24DiqdCN6f8HKnCRMcNA5bmBCmgACwohlRAJ3H4AAAAASUVORK5CYII='
  @State pixelMap: image.PixelMap | undefined = undefined;
  build() {
    Column() {
      Text(this.message)
        .id('HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .onClick(async () => {
          let helper = new util.Base64Helper();
          let buffer: ArrayBuffer = helper.decodeSync(this.imageBase64, util.Type.MIME).buffer as ArrayBuffer;
          let imageSource = image.createImageSource(buffer);
          let opts: image.DecodingOptions = { editable: true };
          this.pixelMap = await imageSource.createPixelMap(opts);
          this.pixelMap.getImageInfo().then((imageInfo : image.ImageInfo) => {
            if (imageInfo == undefined) {
              console.error(`Failed to obtain the image pixel map information.`);
            }
            let wit = imageInfo.size.width;
            let hig = imageInfo.size.height;
            console.log(`Succeeded in obtaining the image pixel map information., ${JSON.stringify(wit)}, ${JSON.stringify(hig)}`);
          })
        })
    }
    .height('100%')
    .width('100%')
  }
}
相关推荐
轻口味1 小时前
【每日学点HarmonyOS Next知识】获取资源问题、软键盘弹起、swiper更新、C给图片设置位图、读取本地Json
c语言·json·harmonyos·harmonyosnext
林钟雪3 小时前
HarmonyNext 实战:基于 ArkTS 的高级跨设备数据同步方案
harmonyos
陈无左耳、5 小时前
HarmonyOS学习第18天:多媒体功能全解析
学习·华为·harmonyos
IT乐手5 小时前
2.6、媒体查询(mediaquery)
harmonyos
麦田里的守望者江5 小时前
Kotlin/Native 给鸿蒙使用(二)
kotlin·harmonyos
IT乐手5 小时前
2.5、栅格布局(GridRow/GridCol)
harmonyos
小时代的大玩家6 小时前
鸿蒙系统下使用AVPlay播放视频,封装播放器
harmonyos
Harmony培训部小助手6 小时前
HarmonyOS NEXT Grid 组件性能优化指南
性能优化·harmonyos
Harmony培训部小助手6 小时前
HarmonyOS NEXT 瀑布流性能优化指南
性能优化·harmonyos
kangyouwei6 小时前
鸿蒙开发:16-软键盘弹起顶起页面问题
前端·harmonyos