【每日学点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%')
  }
}
相关推荐
小小小小小星2 小时前
鸿蒙开发之ArkUI框架进阶:从声明式范式到跨端实战
harmonyos·arkui
鸿蒙小灰2 小时前
鸿蒙开发对象字面量类型标注的问题
harmonyos
鸿蒙先行者3 小时前
鸿蒙Next不再兼容安卓APK,开发者该如何应对?
harmonyos
YF云飞5 小时前
.NET 在鸿蒙系统(HarmonyOS Next)上的适配探索与实践
华为·.net·harmonyos
Quarkn9 小时前
鸿蒙原生应用ArkUI之自定义List下拉刷新动效
list·harmonyos·arkts·鸿蒙·arkui
AlbertZein10 小时前
HarmonyOS5 凭什么学鸿蒙 —— Context详解
harmonyos
whysqwhw18 小时前
鸿蒙音频播放方式总结
harmonyos
whysqwhw18 小时前
鸿蒙音频录制方式总结
harmonyos
zhanshuo20 小时前
HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新
harmonyos
zhanshuo20 小时前
鸿蒙任务调度机制深度解析:优先级、时间片、多核与分布式的流畅秘密
harmonyos