HarmonyOS 鸿蒙Next:如何实现在web的onInterceptRequest回调方法里拦截h5页面的html,js,css和png等资源请求,然后从本地磁盘找到对应文件后转成WebResourceResponse对象后返回给Web,从而实现离线加载页面的功能

发布于 1周前 作者 zlyuanteng 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:如何实现在web的onInterceptRequest回调方法里拦截h5页面的html,js,css和png等资源请求,然后从本地磁盘找到对应文件后转成WebResourceResponse对象后返回给Web,从而实现离线加载页面的功能 我想在Web的onInterceptRequest回调方法里拦截h5页面的html,js,css和png等资源请求,然后从本地磁盘找到对应文件后转成WebResourceResponse对象后返回给Web,从而实现离线加载页面的功能。现在通过在线地址找手机本地磁盘离线资源的方法是Promise异步返回的,怎么做可以实现同步返回

2 回复

可以先设置setResponseIsReadyfalse,那么内核此时不会去读取response的内容。当获取到fd后再将其改为true,此时内核才会去读去响应数据。参考demo:

build() {
  Column() {
    Web({ src: $rawfile('catch.html'), controller: this.webviewController })
      .onInterceptRequest((event) => {
        if (event) {
          console.log('url123456:' + event.request.getRequestUrl())
        }
        const url = event!.request.getRequestUrl();
        if (!url.endsWith(".jpg")) {
          return null;
        }
        try {
          let url2 = 'https://img.tukuppt.com/photo-big/17/12/16/57/94/171216579483.jpg';
          this.xxxx(url2).then(fd => {
            this.responseweb.setResponseData(fd);
            this.responseweb.setResponseCode(200);
            this.responseweb.setReasonMessage('OK');
            this.responseweb.setResponseIsReady(true);
            console.log(fd + " 1234567")
          });
          this.responseweb.setResponseMimeType('image/*');
          this.responseweb.setResponseIsReady(false);
          console.log(this.responseweb.getResponseData().toString + "123456")
          return this.responseweb;
        } catch (error) {
          console.error(`[Demo]Code: ${error.code},Message: ${error.message} `);
          return null
        }
      })
  }
}

参考文档如下: https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs-V5/faqs-arkweb-82-V5

setResponseIsReady属性说明: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-web-V5#setresponseisready9

您可以看看该示例是否满足您的需求:

onInterceptRequest接口,当Web组件加载url之前触发。返回值WebResourceResponse。返回响应数据则按照响应数据加载,无响应数据则返回null表示按照原来的方式加载。

// xxx.ets
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  responseWeb: WebResourceResponse = new WebResourceResponse();
  heads: Header[] = new Array();
  @State webData: string = "<!DOCTYPE html>\n<html>\n<head>\n<title>intercept test</title>\n</head>\n<body>\n<h1>intercept test</h1>\n</body>\n</html>";

  build() {
    Column() {
      Web({ src: 'www.example.com', controller: this.controller })
        .onInterceptRequest((event) => {
          if (event) {
            console.log('url:' + event.request.getRequestUrl());
          }
          let head1: Header = {
            headerKey: "Connection",
            headerValue: "keep-alive"
          }
          let head2: Header = {
            headerKey: "Cache-Control",
            headerValue: "no-cache"
          }
          let length = this.heads.push(head1);
          length = this.heads.push(head2);
          const promise: Promise<String> = new Promise((resolve: Function, reject: Function) => {
            this.responseWeb.setResponseHeader(this.heads);
            this.responseWeb.setResponseData(this.webData);
            this.responseWeb.setResponseEncoding('utf-8');
            this.responseWeb.setResponseMimeType('text/html');
            this.responseWeb.setResponseCode(200);
            this.responseWeb.setReasonMessage('OK');
            resolve("success");
          })
          promise.then(() => {
            console.log("prepare response ready");
            this.responseWeb.setResponseIsReady(true);
          })
          this.responseWeb.setResponseIsReady(false);
          return this.responseWeb;
        })
    }
  }
}

请参考以下demo,在返回null时,则添加如下代码this.responseResource.setResponseIsReady(false);达到以下效果:返回响应数据则按照响应数据加载,无响应数据则返回null表示按照原来的方式加载。

//rawfile/index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<script src=""></script>
<body>
<!-- 页面资源请求 -->
<a href="https://www.example.com/test.html">intercept test111111!</a>
</body>
</html>

// xxx.ets
import web_webview from '@ohos.web.webview';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct WebComponent {
  controller: web_webview.WebviewController = new web_webview.WebviewController()
  responseResource: WebResourceResponse = new WebResourceResponse()
  // 自定义响应数据
  @State webData: string = '<!DOCTYPE html>\n<html>\n<head>\n<title>intercept test22222</title>\n</head>\n<body>\n<h1>intercept ok</h1>\n</body>\n</html>'
  build() {
    Column() {
      Web({ src: $rawfile('index.html'), controller: this.controller })
        .onInterceptRequest((event) => {
          if (event) {
            console.info('url:' + event.request.getRequestUrl());
            // 拦截页面请求
            if (event.request.getRequestUrl() !== 'https://www.example.com/test.html') {
              console.log('拦截了')
              return null;
            }
          }
          try {
            const promise: Promise<string> = new Promise((resolve: Function, reject: Function) => {
              setTimeout(() => {
                console.info('responseweb->setTimeout after wait');
                // resolve('OK')
                resolve(null)
              }, 3000);
            })
            promise.then((result) => {
              if(result==='OK'){
                this.responseResource.setResponseData(this.webData);
                this.responseResource.setResponseCode(200);
                this.responseResource.setReasonMessage('OK');
                this.responseResource.setResponseIsReady(true);
                console.info('responseweb->set true');
              }else{
                this.responseResource.setResponseIsReady(false);//添加该逻辑
                console.info('responseweb为null->set false');
              }
            }).catch((error: BusinessError) => {
              console.error(error.message);
            });
            console.info('responseweb-> start setTimeout');
            this.responseResource.setResponseMimeType('text/html');
            this.responseResource.setResponseIsReady(false);
            console.info('responseweb->set false');
            return  this.responseResource;
          } catch (error) {
            console.error('errorresponseweb->' + `${error.message}`);
            return new WebResourceResponse();
          }
        })
    }
  }
}

更多关于HarmonyOS 鸿蒙Next:如何实现在web的onInterceptRequest回调方法里拦截h5页面的html,js,css和png等资源请求,然后从本地磁盘找到对应文件后转成WebResourceResponse对象后返回给Web,从而实现离线加载页面的功能的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙系统中,若想在onInterceptRequest回调方法里拦截H5页面的HTML、JS、CSS和PNG等资源请求,并从本地磁盘找到对应文件后转成WebResourceResponse对象返回给Web,可以按照以下步骤实现:

  1. 重写shouldInterceptRequest方法:在WebViewClient的子类中重写此方法,用于拦截资源请求。

  2. 读取本地文件:根据请求的URL路径,从本地磁盘读取对应的HTML、JS、CSS或PNG文件。

  3. 构建WebResourceResponse:根据读取的文件内容及其MIME类型,构建WebResourceResponse对象。

  4. 返回WebResourceResponse:将构建的WebResourceResponse对象返回,以便WebView加载本地资源。

示例代码如下:

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
    String url = request.getUrl().toString();
    // 解析URL,获取资源路径
    String filePath = getPathFromUrl(url);
    if (filePath != null) {
        try {
            File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            String mimeType = getMimeType(filePath);
            return new WebResourceResponse(mimeType, "UTF-8", fis);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return super.shouldInterceptRequest(view, request);
}

// 根据文件扩展名获取MIME类型的方法需自行实现
private String getMimeType(String filePath) {
    // 实现代码略
}

注意:上述代码示例中的getPathFromUrlgetMimeType方法需根据实际需求实现。

如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部