【鸿蒙开发】第十五章 H5与端侧交互、Cookies以及Web调试

目录

[1. H5与端侧交互](#1. H5与端侧交互)

[1.1 应用侧调用前端页面函数](#1.1 应用侧调用前端页面函数)

[1.2 前端页面调用应用侧函数](#1.2 前端页面调用应用侧函数)

[1.2.1 复杂类型使用方法](#1.2.1 复杂类型使用方法)

[1.3 建立应用侧与前端页面数据通道](#1.3 建立应用侧与前端页面数据通道)

[2 管理页面跳转及浏览记录导航](#2 管理页面跳转及浏览记录导航)

[2.1 历史记录导航](#2.1 历史记录导航)

[2.2 页面跳转](#2.2 页面跳转)

[2.3 跨应用跳转](#2.3 跨应用跳转)

[3 管理Cookie及数据存储](#3 管理Cookie及数据存储)

[3.1 Cookie管理](#3.1 Cookie管理)

[3.2 缓存与存储管理](#3.2 缓存与存储管理)

[3.2.1 Cache](#3.2.1 Cache)

[3.2.2 Dom Storage](#3.2.2 Dom Storage)

[4 自定义页面请求响应](#4 自定义页面请求响应)

[5 使用Devtools工具调试前端页面](#5 使用Devtools工具调试前端页面)


1. H5与端侧交互

1.1 应用侧调用前端页面函数

应用侧可以通过runJavaScript()方法调用前端页面的JavaScript相关函数。

在下面的示例中,点击应用侧的"runJavaScript"按钮时,来触发前端页面的htmlTest()方法。

  1. 前端页面代码。

    <!DOCTYPE html> <html> <body> <script> function htmlTest() { console.info('JavaScript Hello World! '); } </script> </body> </html>
  2. 应用侧代码。

    // xxx.ets
    import web_webview from '@ohos.web.webview';

    @Entry
    @Component
    struct WebComponent {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();

    build() {
    Column() {
    Web({ src: $rawfile('index.html'), controller: this.webviewController})
    Button('runJavaScript')
    .onClick(() => {
    this.webviewController.runJavaScript('htmlTest()');
    })
    Web({ src: $rawfile('index.html'), controller: this.webviewController})
    }
    }
    }

1.2 前端页面调用应用侧函数

开发者使用Web组件将应用侧代码注册到前端页面中,注册完成之后,前端页面中使用注册的对象名称就可以调用应用侧的函数,实现在前端页面中调用应用侧方法。

注册应用侧代码有两种方式,一种在Web组件初始化调用,使用javaScriptProxy()接口。另外一种在Web组件初始化完成后调用,使用registerJavaScriptProxy()接口。

在下面的示例中,将test()方法注册在前端页面中, 该函数可以在前端页面触发运行。

  1. javaScriptProxy()接口使用示例如下。

    // xxx.ets
    import web_webview from '@ohos.web.webview';

    class testClass {
    constructor() {
    }

    test(): string {
    return 'ArkTS Hello World!';
    }
    }

    @Entry
    @Component
    struct WebComponent {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    // 声明需要注册的对象
    @State testObj: testClass = new testClass();

    build() {
    Column() {
    // web组件加载本地index.html页面
    Web({ src: $rawfile('index.html'), controller: this.webviewController})
    // 将对象注入到web端
    .javaScriptProxy({
    object: this.testObj,
    name: "testObjName",
    methodList: ["test"],
    controller: this.webviewController
    })
    }
    }
    }

  2. 应用侧使用registerJavaScriptProxy()接口注册。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class testClass {
    constructor() {
    }

    test(): string {
    return "ArkUI Web Component";
    }

    toString(): void {
    console.log('Web Component toString');
    }
    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
    Column() {
    Button('refresh')
    .onClick(() => {
    try {
    this.webviewController.refresh();
    } catch (error) {
    let e: business_error.BusinessError = error as business_error.BusinessError;
    console.error(ErrorCode: ${e.code}, Message: ${e.message});
    }
    })
    Button('Register JavaScript To Window')
    .onClick(() => {
    try {
    this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
    } catch (error) {
    let e: business_error.BusinessError = error as business_error.BusinessError;
    console.error(ErrorCode: ${e.code}, Message: ${e.message});
    }
    })
    Web({ src: $rawfile('index.html'), controller: this.webviewController })
    }
    }
    }

  • 说明:
    使用registerJavaScriptProxy()接口注册方法时,注册后需调用refresh()接口生效。
  1. index.html前端页面触发应用侧代码。

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { let str = testObjName.test(); document.getElementById("demo").innerHTML = str; console.info('ArkTS Hello World! :' + str); } </script> </body> </html>

1.2.1 复杂类型使用方法

  • 应用侧和前端页面之间传递Array。

    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class testClass {
    constructor() {
    }

    test(): Array<Number>{
      return [1, 2, 3, 4]
    }
    
    toString(param:String): void {
      console.log('Web Component toString' + param);
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { testObjName.test().then((param)=>{testObjName.toString(param)}).catch((param)=>{testObjName.toString(param)}) } </script> </body> </html>
  • 应用侧和前端页面之间传递不带Function的Dictionary。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class student {
    name: string = ''
    age: string = ''
    }

    class testClass {
    constructor() {
    }

    test(): student {
      let st: student = {name:"jeck", age:"12"}
      return st
    }
    
    toString(param: ESObject): void {
      console.log('Web Component toString' + param["name"]);
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { testObjName.toString(testObjName.test()); } </script> </body> </html>
  • 应用侧调用前端页面的Callback。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class testClass {
    constructor() {
    }

    test(param: Function): void {
      param("call callback");
    }
    
    toString(param:String): void {
      console.log('Web Component toString' + param);
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { testObjName.test(function(param){testObjName.toString(param)}); } </script> </body> </html>
  • 应用侧调用前端页面Object里的Function。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class testClass {
    constructor() {
    }

    test(param: ESObject): void {
      param.hello("call obj func");
    }
    
    toString(param:String): void {
      console.log('Web Component toString' + param);
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> // 写法1 class Student { constructor(nameList) { this.methodNameListForJsProxy = nameList; }
          hello(param) {
              testObjName.toString(param)
          }
      }
      var st = new Student(["hello"])
    
      // 写法2
      //创建一个构造器,构造函数首字母大写
      function Obj1(){
          this.methodNameListForJsProxy=["hello"];
          this.hello=function(param){
              testObjName.toString(param)
          };
      }
      //利用构造器,通过new关键字生成对象
      var st1 = new Obj1();
    
      function callArkTS() {
          testObjName.test(st);
          testObjName.test(st1);
      }
    
    </script> </body> </html>
  • 前端页面调用应用侧Object里的Function。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class ObjOther {
    methodNameListForJsProxy: string[]

      constructor(list: string[]) {
          this.methodNameListForJsProxy = list
      }
    
      testOther(json:string): void {
          console.info(json)
      }
    

    }

    class testClass {
    ObjReturn:ObjOther
    constructor() {
    this.ObjReturn = new ObjOther(["testOther"]);
    }

    test(): ESObject {
      return this.ObjReturn
    }
    
    toString(param: string): void {
      console.log('Web Component toString' + param);
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { testObjName.test().testOther("call other object func"); } </script> </body> </html>
  • Promise场景。
    第一种使用方法,在应用侧new Promise。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    class testClass {
    constructor() {
    }

    test(): Promise<string> {
        let p: Promise<string> = new Promise((resolve, reject) => {  setTimeout(() => {console.log('执行完成'); reject('fail');}, 10000);});
        return p;
    }
    
    toString(param:String): void {
        console.log(" " + param)
    }
    

    }

    @Entry
    @Component
    struct Index {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();
    @State testObj: testClass = new testClass();

    build() {
      Column() {
        Button('refresh')
          .onClick(() => {
            try {
              this.webviewController.refresh();
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Button('Register JavaScript To Window')
          .onClick(() => {
            try {
              this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
            } catch (error) {
              let e: business_error.BusinessError = error as business_error.BusinessError;
              console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
            }
          })
        Web({ src: $rawfile('index.html'), controller: this.webviewController })
      }
    }
    

    }

    <!DOCTYPE html> <html> <body> <button type="button" onclick="callArkTS()">Click Me!</button>

    <script> function callArkTS() { testObjName.test().then((param)=>{testObjName.toString(param)}).catch((param)=>{testObjName.toString(param)}) } </script> </body> </html>

第二种使用方法,在前端页面new Promise。

// xxx.ets
import web_webview from '@ohos.web.webview';
import business_error from '@ohos.base';

class testClass {
  constructor() {
  }

  test(param:Function): void {
      setTimeout( () => { param("suc") }, 10000)
  }

  toString(param:String): void {
      console.log(" " + param)
  }
}

@Entry
@Component
struct Index {
  webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  @State testObj: testClass = new testClass();

  build() {
    Column() {
      Button('refresh')
        .onClick(() => {
          try {
            this.webviewController.refresh();
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Button('Register JavaScript To Window')
        .onClick(() => {
          try {
            this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Web({ src: $rawfile('index.html'), controller: this.webviewController })
    }
  }
}

<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<button type="button" onclick="callArkTS()">Click Me!</button>
<p id="demo"></p>
<script>
    function callArkTS() {
      let funpromise
      var p = new Promise(function(resolve, reject){funpromise=(param)=>{resolve(param)}})
      testObjName.test(funpromise)
      p.then((param)=>{testObjName.toString(param)})
    }
</script>
</body>
</html>

1.3 建立应用侧与前端页面数据通道

前端页面和应用侧之间可以用createWebMessagePorts()接口创建消息端口来实现两端的通信。

在下面的示例中,应用侧页面中通过createWebMessagePorts方法创建消息端口,再把其中一个端口通过postMessage()接口发送到前端页面,便可以在前端页面和应用侧之间互相发送消息。

  1. 应用侧代码。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import business_error from '@ohos.base';

    @Entry
    @Component
    struct WebComponent {
    controller: web_webview.WebviewController = new web_webview.WebviewController();
    ports: web_webview.WebMessagePort[] = [];
    @State sendFromEts: string = 'Send this message from ets to HTML';
    @State receivedFromHtml: string = 'Display received message send from HTML';

    build() {
    Column() {
    // 展示接收到的来自HTML的内容
    Text(this.receivedFromHtml)
    // 输入框的内容发送到HTML
    TextInput({placeholder: 'Send this message from ets to HTML'})
    .onChange((value: string) => {
    this.sendFromEts = value;
    })

       Button('postMessage')
         .onClick(() => {
           try {
             // 1、创建两个消息端口。
             this.ports = this.controller.createWebMessagePorts();
             // 2、在应用侧的消息端口(如端口1)上注册回调事件。
             this.ports[1].onMessageEvent((result: web_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) {
             let e: business_error.BusinessError = error as business_error.BusinessError;
             console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
           }
         })
    
       // 4、使用应用侧的端口给另一个已经发送到html的端口发送消息。
       Button('SendDataToHTML')
         .onClick(() => {
           try {
             if (this.ports && this.ports[1]) {
               this.ports[1].postMessageEvent(this.sendFromEts);
             } else {
               console.error(`ports is null, Please initialize first`);
             }
           } catch (error) {
             let e: business_error.BusinessError = error as business_error.BusinessError;
             console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
           }
         })
       Web({ src: $rawfile('xxx.html'), controller: this.controller })
     }
    

    }
    }

  2. 前端页面代码。

    <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WebView Message Port Demo</title> </head> <body>

    WebView Message Port Demo



    display received message send from ets

    </body> <script> var h5Port; var output = document.querySelector('.output'); window.addEventListener('message', function (event) { if (event.data === '__init_port__') { if (event.ports[0] !== null) { h5Port = event.ports[0]; // 1. 保存从应用侧发送过来的端口。 h5Port.onmessage = function (event) { // 2. 接收ets侧发送过来的消息。 var msg = 'Got message from ets:'; var result = event.data; 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'); } output.innerHTML = msg; } } } })

    // 3. 使用h5Port向应用侧发送消息。
    function PostMsgToEts(data) {
    if (h5Port) {
    h5Port.postMessage(data);
    } else {
    console.error('h5Port is null, Please initialize first');
    }
    }
    </script>

    </html>

2 管理页面跳转及浏览记录导航

2.1 历史记录导航

在前端页面点击网页中的链接时,Web组件默认会自动打开并加载目标网址。当前端页面替换为新的加载链接时,会自动记录已经访问的网页地址。可以通过forward()和backward()接口向前/向后浏览上一个/下一个历史记录。

在下面的示例中,点击应用的按钮来触发前端页面的后退操作。

// xxx.ets
import web_webview from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  webviewController: web_webview.WebviewController = new web_webview.WebviewController();
  build() {
    Column() {
      Button('loadData')
        .onClick(() => {
          if (this.webviewController.accessBackward()) {
            this.webviewController.backward();
          }
        })
      Web({ src: 'https://www.example.com/cn/', controller: this.webviewController})
    }
  }
}

如果存在历史记录,accessBackward()接口会返回true。同样,您可以使用accessForward()接口检查是否存在前进的历史记录。如果您不执行检查,那么当用户浏览到历史记录的末尾时,调用forward()和backward()接口时将不执行任何操作。

2.2 页面跳转

当点击网页中的链接需要跳转到应用内其他页面时,可以通过使用Web组件的onUrlLoadIntercept()接口来实现。

在下面的示例中,应用首页Index.ets加载前端页面route.html,在前端route.html页面点击超链接,可跳转到应用的ProfilePage.ets页面。

  1. 应用首页Index.ets页面代码。

    // index.ets
    import web_webview from '@ohos.web.webview';
    import router from '@ohos.router';
    @Entry
    @Component
    struct WebComponent {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();

    build() {
    Column() {
    Web({ src: $rawfile('route.html'), controller: this.webviewController })
    .onUrlLoadIntercept((event) => {
    if (event) {
    let url: string = event.data.getRequestUrl();
    if (url.indexOf('native://') === 0) {
    // 跳转其他界面
    router.pushUrl({ url:url.substring(9) })
    return true;
    }
    }
    return false;
    })
    }
    }
    }

  2. route.html前端页面代码。

    <!DOCTYPE html> <html> <body> </body> </html>
  3. 跳转页面ProfilePage.ets代码。

    @Entry
    @Component
    struct ProfilePage {
    @State message: string = 'Hello World';

    build() {
    Column() {
    Text(this.message)
    .fontSize(20)
    }
    }
    }

2.3 跨应用跳转

Web组件可以实现点击前端页面超链接跳转到其他应用

在下面的示例中,点击call.html前端页面中的超链接,跳转到电话应用的拨号界面。

  1. 应用侧代码。

    // xxx.ets
    import web_webview from '@ohos.web.webview';
    import call from '@ohos.telephony.call';

    @Entry
    @Component
    struct WebComponent {
    webviewController: web_webview.WebviewController = new web_webview.WebviewController();

    build() {
    Column() {
    Web({ src: $rawfile('call.html'), controller: this.webviewController})
    .onUrlLoadIntercept((event) => {
    if (event) {
    let url: string = event.data as string;
    // 判断链接是否为拨号链接
    if (url.indexOf('tel://') === 0) {
    // 跳转拨号界面
    call.makeCall(url.substring(6), (err) => {
    if (!err) {
    console.info('make call succeeded.');
    } else {
    console.info('make call fail, err is:' + JSON.stringify(err));
    }
    });
    return true;
    }
    }
    return false;
    })
    }
    }
    }

  2. 前端页面call.html代码。

    <!DOCTYPE html> <html> <body> </body> </html>

3 管理Cookie及数据存储

3.1 Cookie管理

Cookie是网络访问过程中,由服务端发送给客户端的一小段数据。客户端可持有该数据,并在后续访问该服务端时,方便服务端快速对客户端身份、状态等进行识别。

Web组件提供了WebCookieManager类,用于管理Web组件的Cookie信息。Cookie信息保存在应用沙箱路径下/proc/{pid}/root/data/storage/el2/base/cache/web/Cookiesd的文件中。

下面以setCookie()接口举例,为"www.example.com"设置单个Cookie的值"value=test"。其他Cookie的相关功能及使用

// xxx.ets
import web_webview from '@ohos.web.webview';
import business_error from '@ohos.base';

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

  build() {
    Column() {
      Button('setCookie')
        .onClick(() => {
          try {
            web_webview.WebCookieManager.setCookie('https://www.example.com', 'value=test');
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}

3.2 缓存与存储管理

在访问网站时,网络资源请求是相对比较耗时的。开发者可以通过Cache、Dom Storage等手段将资源保存到本地,以提升访问同一网站的速度。

3.2.1 Cache

使用cacheMode()配置页面资源的缓存模式,Web组件为开发者提供四种缓存模式,分别为:

  • Default : 优先使用未过期的缓存,如果缓存不存在,则从网络获取。
  • None : 加载资源使用cache,如果cache中无该资源则从网络中获取。
  • Online : 加载资源不使用cache,全部从网络中获取。
  • Only :只从cache中加载资源。

在下面的示例中,选用缓存设置为None模式。

// xxx.ets
import web_webview from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  @State mode: CacheMode = CacheMode.None;
  controller: web_webview.WebviewController = new web_webview.WebviewController();
  build() {
    Column() {
      Web({ src: 'www.example.com', controller: this.controller })
        .cacheMode(this.mode)
    }
  }
}

同时,为了获取最新资源,开发者可以通过removeCache()接口清除已经缓存的资源,示例代码如下:

// xxx.ets
import web_webview from '@ohos.web.webview';
import business_error from '@ohos.base';

@Entry
@Component
struct WebComponent {
  @State mode: CacheMode = CacheMode.None;
  controller: web_webview.WebviewController = new web_webview.WebviewController();
  build() {
    Column() {
      Button('removeCache')
        .onClick(() => {
          try {
            // 设置为true时同时清除rom和ram中的缓存,设置为false时只清除ram中的缓存
            this.controller.removeCache(true);
          } catch (error) {
            let e: business_error.BusinessError = error as business_error.BusinessError;
            console.error(`ErrorCode: ${e.code},  Message: ${e.message}`);
          }
        })
      Web({ src: 'www.example.com', controller: this.controller })
        .cacheMode(this.mode)
    }
  }
}

3.2.2 Dom Storage

Dom Storage包含了Session Storage和Local Storage两类。前者为临时数据,其存储与释放跟随会话生命周期;后者为可持久化数据,落盘在应用目录下。两者的数据均通过Key-Value的形式存储,通常在访问需要客户端存储的页面时使用。开发者可以通过Web组件的属性接口domStorageAccess()进行使能配置,示例如下:

// xxx.ets
import web_webview from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  controller: web_webview.WebviewController = new web_webview.WebviewController();
  build() {
    Column() {
      Web({ src: 'www.example.com', controller: this.controller })
        .domStorageAccess(true)
    }
  }
}

4 自定义页面请求响应

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

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

在下面的示例中,Web组件通过拦截页面请求"https://www.example.com/test.html", 在应用侧代码构建响应资源,实现自定义页面响应场景。

  1. 前端页面index.html代码。

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> intercept test! </body> </html>
  2. 应用侧代码。

    // xxx.ets
    import web_webview from '@ohos.web.webview';

    @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 test</title>\n'+
    '</head>\n'+
    '<body>\n'+
    '

    intercept ok

    \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') {
    return null;
    }
    }
    // 构造响应数据
    this.responseResource.setResponseData(this.webData);
    this.responseResource.setResponseEncoding('utf-8');
    this.responseResource.setResponseMimeType('text/html');
    this.responseResource.setResponseCode(200);
    this.responseResource.setReasonMessage('OK');
    return this.responseResource;
    })
    }
    }
    }

5 使用Devtools工具调试前端页面

Web组件支持使用DevTools工具调试前端页面。DevTools是一个 Web前端开发调试工具,提供了电脑上调试移动设备前端页面的能力。开发者通过setWebDebuggingAccess()接口开启Web组件前端页面调试能力,利用DevTools工具可以在电脑上调试移动设备上的前端网页,设备需为4.1.0及以上版本。

使用DevTools工具,可以执行以下步骤:

  1. 在应用代码中开启Web调试开关,具体如下:

    // xxx.ets
    import web_webview from '@ohos.web.webview';

    @Entry
    @Component
    struct WebComponent {
    controller: web_webview.WebviewController = new web_webview.WebviewController();
    aboutToAppear() {
    // 配置Web开启调试模式
    web_webview.WebviewController.setWebDebuggingAccess(true);
    }
    build() {
    Column() {
    Web({ src: 'www.example.com', controller: this.controller })
    }
    }
    }

  2. 开启调试功能需要在DevEco Studio应用工程的module.json5文件中增加权限, 具体如下:

    "requestPermissions":[
    {
    "name" : "ohos.permission.INTERNET"
    }
    ]
    "requestPermissions":[
    {
    "name" : "ohos.permission.INTERNET"
    }
    ]

  3. 将设备连接上电脑,在电脑端配置端口映射,配置方法如下:

    //查找 devtools 远程调试所需的 domain socket 名称,该名称与进程号有关,重启调试应用后,需要重复此步骤,以完成端口转发
    cat /proc/net/unix | grep devtools
    // 添加映射 [pid] 替换成实际的进程id
    hdc fport tcp:9222 localabstract:webview_devtools_remote_[pid]
    // 查看映射
    hdc fport ls
    示例:
    hdc shell
    cat /proc/net/unix | grep devtools
    //显示 webview_devtools_remote_3458
    exit
    hdc fport tcp:9222 localabstract:webview_devtools_remote_3458
    hdc fport ls

在电脑端Chrome浏览器地址栏中输入chrome://inspect/#devices,页面识别到设备后,就可以开始页面调试。调试效果如下:

参考文献:

[1]OpenHarmoney应用开发文档

相关推荐
程序猿会指北1 小时前
纯血鸿蒙APP实战开发——应用新功能引导实现案例
移动开发·harmonyos·arkts·openharmony·arkui·组件化·鸿蒙开发
BruceGerGer1 小时前
harmonyOS组件拥有的状态汇总
华为·harmonyos
二流小码农2 小时前
鸿蒙元服务项目实战:终结篇之备忘录搜索功能实现
android·ios·harmonyos
枫叶丹43 小时前
【HarmonyOS之旅】HarmonyOS开发基础知识(二)
华为od·华为·华为云·harmonyos
Cocos 引擎4 小时前
鸿蒙NEXT游戏|Cocos参展2024华为开发者年度盛典
游戏·华为·harmonyos
凯子坚持 c5 小时前
鸿蒙心路旅程:HarmonyOS NEXT 心路旅程:技术、成长与未来
华为·harmonyos
play_big_knife14 小时前
鸿蒙项目云捐助第十六讲云捐助使用云数据库实现登录注册
数据库·华为云·harmonyos·鸿蒙·云开发·云数据库·鸿蒙开发
学海无涯乐作舟14 小时前
鸿蒙高级特性 - 动态UI加载
ui·华为·harmonyos
葡萄城技术团队14 小时前
共创共建!葡萄城 SpreadJS 完成 HarmonyOS NEXT 操作系统兼容认证
华为·harmonyos
海绵宝宝_18 小时前
【HarmonyOS NEXT】ArkTs数据类型解析与使用
android·前端·华为·harmonyos·鸿蒙