【鸿蒙实战开发】—— 管理Web组件

[复制链接]
发表于 2025-12-23 00:28:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

📚往期笔录记载✏️:

✏️ 鸿蒙(HarmonyOS)北向开发知识点记载~
✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
✏️ 鸿蒙应用开发与鸿蒙体系开发哪个更有远景?
✏️ 嵌入式开发适不得当做鸿蒙南向开发?看完这篇你就相识了~
✏️ 对于大前端开发来说,转鸿蒙开发毕竟是福照旧祸?
✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✏️ 记载一场鸿蒙开发岗位口试履历~
✏️ 连续更新中……

办理Web组件当地资源跨域标题

拦截当地资源跨域

为了进步安全性,ArkWeb内核不允许file协议大概resource协议访问URL上下文中来自跨域的哀求。因此,在使用Web组件加载当地离线资源的时间,Web组件会拦截file协媾和resource协议的跨域访问。当Web组件无法访问当地跨域资源时,开发者可以在devtools控制台中看到类似以下报错信息:
  1. Access to script at 'xxx' from origin 'xxx' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, arkweb, data, chrome-extension, chrome, https, chrome-untrusted.
复制代码
当地资源跨域标题办理方法

如果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可以乐成加载,办理了跨域拦截的标题。
  1. // main/ets/pages/index.ets
  2. import { webview } from '@kit.ArkWeb';
  3. @Entry
  4. @Component
  5. struct Index {
  6.   @State message: string = 'Hello World';
  7.   webviewController: webview.WebviewController = new webview.WebviewController();
  8.   // 构造域名和本地文件的映射表
  9.   schemeMap = new Map([
  10.     ["https://www.example.com/index.html", "index.html"],
  11.     ["https://www.example.com/js/script.js", "js/script.js"],
  12.   ])
  13.   // 构造本地文件和构造返回的格式mimeType
  14.   mimeTypeMap = new Map([
  15.     ["index.html", 'text/html'],
  16.     ["js/script.js", "text/javascript"]
  17.   ])
  18.   build() {
  19.     Row() {
  20.       Column() {
  21.         // 针对本地index.html,使用http或者https协议代替file协议或者resource协议,并且构造一个属于自己的域名。
  22.         // 本例中构造www.example.com为例。
  23.         Web({ src: "https://www.example.com/index.html", controller: this.webviewController })
  24.           .javaScriptAccess(true)
  25.           .fileAccess(true)
  26.           .domStorageAccess(true)
  27.           .geolocationAccess(true)
  28.           .width("100%")
  29.           .height("100%")
  30.           .onInterceptRequest((event) => {
  31.             if (!event) {
  32.               return;
  33.             }
  34.             // 此处匹配自己想要加载的本地离线资源,进行资源拦截替换,绕过跨域
  35.             if (this.schemeMap.has(event.request.getRequestUrl())) {
  36.               let rawfileName: string = this.schemeMap.get(event.request.getRequestUrl())!;
  37.               let mimeType = this.mimeTypeMap.get(rawfileName);
  38.               if (typeof mimeType === 'string') {
  39.                 let response = new WebResourceResponse();
  40.                 // 构造响应数据,如果本地文件在rawfile下,可以通过如下方式设置
  41.                 response.setResponseData($rawfile(rawfileName));
  42.                 response.setResponseEncoding('utf-8');
  43.                 response.setResponseMimeType(mimeType);
  44.                 response.setResponseCode(200);
  45.                 response.setReasonMessage('OK');
  46.                 response.setResponseIsReady(true);
  47.                 return response;
  48.               }
  49.             }
  50.             return null;
  51.           })
  52.       }
  53.       .width('100%')
  54.     }
  55.     .height('100%')
  56.   }
  57. }
复制代码

  1. <!-- main/resources/rawfile/index.html -->
  2. <html>
  3. <head>
  4.     <meta name="viewport" content="width=device-width,initial-scale=1">
  5. </head>
  6. <body>
  7. <script crossorigin src="./js/script.js"></script>
  8. </body>
  9. </html>
复制代码

  1. // main/resources/rawfile/js/script.js
  2. const body = document.body;
  3. const element = document.createElement('div');
  4. element.textContent = 'success';
  5. body.appendChild(element);
复制代码
使用智能防跟踪功能

Web组件支持智能防跟踪功能,即跟踪型网站作为三方插入别的网页时,其发送的网络哀求克制携带cookie。


  • 通过调用 enableIntelligentTrackingPrevention 接口使能大概关闭相应Web组件的智能防跟踪功能,默认情况下该功能未启用。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       Button('enableIntelligentTrackingPrevention')
  11.         .onClick(() => {
  12.           try {
  13.             this.controller.enableIntelligentTrackingPrevention(true);
  14.             console.log("enableIntelligentTrackingPrevention: true");
  15.           } catch (error) {
  16.             console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
  17.           }
  18.         })
  19.       Web({ src: 'www.example.com', controller: this.controller })
  20.     }
  21.   }
  22. }
复制代码


  • 通过调用 isIntelligentTrackingPreventionEnabled 接口判断当前Web组件是否开启了智能防跟踪功能。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       Button('isIntelligentTrackingPreventionEnabled')
  11.         .onClick(() => {
  12.           try {
  13.             let result = this.controller.isIntelligentTrackingPreventionEnabled();
  14.             console.log("result: " + result);
  15.           } catch (error) {
  16.             console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
  17.           }
  18.         })
  19.       Web({ src: 'www.example.com', controller: this.controller })
  20.     }
  21.   }
  22. }
复制代码


  • 通过调用 onIntelligentTrackingPreventionResult 接口,以回调的方式异步获取拦截的跟踪型网站的域名和访问的网站域名信息。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       // 需要打开智能防跟踪功能,才会触发onIntelligentTrackingPreventionResult回调
  11.       Button('enableIntelligentTrackingPrevention')
  12.         .onClick(() => {
  13.           try {
  14.             this.controller.enableIntelligentTrackingPrevention(true);
  15.           } catch (error) {
  16.             console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
  17.           }
  18.         })
  19.       Web({ src: 'www.example.com', controller: this.controller })
  20.         .onIntelligentTrackingPreventionResult((details) => {
  21.           console.log("onIntelligentTrackingPreventionResult: [websiteHost]= " + details.host +
  22.             ", [trackerHost]=" + details.trackerHost);
  23.         })
  24.     }
  25.   }
  26. }
复制代码
同时,智能防跟踪功能提供了一组接口,用于设置须要绕过智能防跟踪功能的域名列表。这些接口设置的域名列表是整个应用见效,而非某个Web组件。


  • 通过调用 addIntelligentTrackingPreventionBypassingList 接口设置须要绕过智能防跟踪功能的域名列表。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       Button('removeIntelligentTrackingPreventionBypassingList')
  11.         .onClick(() => {
  12.           try {
  13.             let hostList = [ "www.test1.com", "www.test2.com" ];
  14.             webview.WebviewController.removeIntelligentTrackingPreventionBypassingList(hostList);
  15.           } catch (error) {
  16.             console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
  17.           }
  18.         })
  19.       Web({ src: 'www.example.com', controller: this.controller })
  20.     }
  21.   }
  22. }
复制代码


  • 通过调用 removeIntelligentTrackingPreventionBypassingList 接口移除通过 addIntelligentTrackingPreventionBypassingList 接口设置的部分域名列表。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       Button('removeIntelligentTrackingPreventionBypassingList')
  11.         .onClick(() => {
  12.           try {
  13.             let hostList = [ "www.test1.com", "www.test2.com" ];
  14.             webview.WebviewController.removeIntelligentTrackingPreventionBypassingList(hostList);
  15.           } catch (error) {
  16.             console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
  17.           }
  18.         })
  19.       Web({ src: 'www.example.com', controller: this.controller })
  20.     }
  21.   }
  22. }
复制代码


  • 通过调用 clearIntelligentTrackingPreventionBypassingList 接口扫除通过 addIntelligentTrackingPreventionBypassingList 接口设置的全部域名。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. @Entry
  4. @Component
  5. struct WebComponent {
  6.   controller: webview.WebviewController = new webview.WebviewController();
  7.   build() {
  8.     Column() {
  9.       Button('clearIntelligentTrackingPreventionBypassingList')
  10.         .onClick(() => {
  11.           webview.WebviewController.clearIntelligentTrackingPreventionBypassingList();
  12.         })
  13.       Web({ src: 'www.example.com', controller: this.controller })
  14.     }
  15.   }
  16. }
复制代码
使用Web组件的广告过滤功能

Web组件提供了网页广告过滤特性,包罗最常见的url拦截与元素隐蔽本领。应用可以通过AdsBlockManager提供的 setAdsBlockRules() 接口设置自界说的easylist过滤规则,并通过Web组件的 enableAdsBlock() 接口使能广告过滤特性。
开启广告过滤

在下面的示例中,演示了一个应用通过文件选择器选择easylist规则文件,并开启广告过滤功能。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. import { picker, fileUri } from '@kit.CoreFileKit';
  4. // 演示点击按钮,通过filepicker打开一个easylist规则文件并设置到Web组件中
  5. @Entry
  6. @Component
  7. struct WebComponent {
  8.   main_url: string = 'https://www.example.com';
  9.   controller: webview.WebviewController = new webview.WebviewController();
  10.   @State input_text: string = 'https://www.example.com';
  11.   build() {
  12.     Column() {
  13.       Row() {
  14.         Flex() {
  15.           Button({type: ButtonType.Capsule}) {
  16.             Text("setAdsBlockRules")
  17.           }
  18.           .onClick(() => {
  19.             try {
  20.               let documentSelectionOptions: ESObject = new picker.DocumentSelectOptions();
  21.               let documentPicker: ESObject = new picker.DocumentViewPicker();
  22.               documentPicker.select(documentSelectionOptions).then((documentSelectResult: ESObject) => {
  23.                 if (documentSelectResult && documentSelectResult.length > 0) {
  24.                   let fileRealPath = new fileUri.FileUri(documentSelectResult[0]);
  25.                   console.info('DocumentViewPicker.select successfully, uri: ' + fileRealPath);
  26.                   webview.AdsBlockManager.setAdsBlockRules(fileRealPath.path, true);
  27.                 }
  28.               })
  29.             } catch (err) {
  30.               console.error('DocumentViewPicker.select failed with err:' + err);
  31.             }
  32.           })
  33.         }
  34.       }
  35.       Web({ src: this.main_url, controller: this.controller })
  36.         .onControllerAttached(()=>{
  37.           this.controller.enableAdsBlock(true);
  38.         })
  39.     }
  40.   }
  41. }
复制代码
如果存在内置的easylist规则文件, setAdsBlockRules() 接口的replace参数可用于设置规则文件的使用战略,replace为true表现倒霉用内置的easylist规则文件,replace为false表现自界说规则和内置的规则将会同时工作,如果发现内置规则与自界说规则辩说,可使用replace=true禁用内置规则结果。
设置的自界说规则文件将在应用历程内对全部的Web组件见效,是一个应用级全局设置文件,并将长期化,应用重启后可继续工作。
关闭特定域名页面的广告过滤

在Web组件的广告过滤开关开启后,应用偶然间会盼望关闭一些特定页面的广告过滤功能,除了可以使用自界说的easylist规则,AdsBlockManager还提供了 addAdsBlockDisallowedList() 接口完成此功能。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. // 演示通过一个按钮的点击向Web组件设置广告过滤的域名策略
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   main_url: string = 'https://www.example.com';
  8.   text_input_controller: TextInputController = new TextInputController();
  9.   controller: webview.WebviewController = new webview.WebviewController();
  10.   @State input_text: string = 'https://www.example.com';
  11.   build() {
  12.     Column() {
  13.       Row() {
  14.         Flex() {
  15.           TextInput({ text: this.input_text, placeholder: this.main_url, controller: this.text_input_controller})
  16.             .id("input_url")
  17.             .height(40)
  18.             .margin(5)
  19.             .borderColor(Color.Blue)
  20.             .onChange((value: string) => {
  21.               this.input_text = value;
  22.             })
  23.           Button({type: ButtonType.Capsule}) { Text("Go") }
  24.           .onClick(() => {
  25.             this.controller.loadUrl(this.input_text);
  26.           })
  27.           Button({type: ButtonType.Capsule}) { Text("addAdsBlockDisallowedList") }
  28.           .onClick(() => {
  29.             let arrDomainSuffixes = new Array<string>();
  30.             arrDomainSuffixes.push('example.com');
  31.             arrDomainSuffixes.push('abcdefg.cn');
  32.             webview.AdsBlockManager.addAdsBlockDisallowedList(arrDomainSuffixes);
  33.           })
  34.         }
  35.       }
  36.       Web({ src: this.main_url, controller: this.controller })
  37.         .onControllerAttached(()=>{
  38.           this.controller.enableAdsBlock(true);
  39.         })
  40.     }
  41.   }
  42. }
复制代码
addAdsBlockDisallowedList接口将域名设置到AdsBlockManager的DisallowedList中,下次页面加载时会使用网页url和DisallowedList中的域名举行后缀匹配,匹配乐成则不会对此页面举行广告过滤。别的,还提供了 addAdsBlockAllowedList() 接口共同DisallowedList举行域名设置,控制是否开启广告过滤。
AdsBlockManager中缓存有2组域名列表,分别为DisallowedList和AllowList,此中DisallowedList用于禁用网页的广告过滤,而AllowList用于重新开启被DisallowedList关闭的广告过滤开关,此中AllowList优先级更高。页面加载时会先使用网页url和AllowList举行匹配,匹配乐成的网页广告过滤将保持开启,否则将会继续使用DisallowedList举行匹配,匹配乐成将关闭网页的广告过滤。如果访问的网页不在AllowList和DisallowedList中,那么默认网页的广告过滤会保持开启状态。
比方,应用想要开启域名为’news.example.com’和’sport.example.com’的广告过滤,但须要关闭’example.com’的其他域名下网页的广告过滤,就可以先使用addAdsBlockDisallowedList()接口添加’example.com’域名到DisallowedList,再使用addAdsBlockAllowedList()接口添加’news.example.com’和’sport.example.com’域名。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. // 演示addAdsBlockAllowedList和addAdsBlockAllowedList配套使用,设置网页级的广告过滤开关。
  4. @Entry
  5. @Component
  6. struct WebComponent {
  7.   main_url: string = 'https://www.example.com';
  8.   text_input_controller: TextInputController = new TextInputController();
  9.   controller: webview.WebviewController = new webview.WebviewController();
  10.   @State input_text: string = 'https://www.example.com';
  11.   build() {
  12.     Column() {
  13.       Row() {
  14.         Flex() {
  15.           TextInput({ text: this.input_text, placeholder: this.main_url, controller: this.text_input_controller})
  16.             .id("input_url")
  17.             .height(40)
  18.             .margin(5)
  19.             .borderColor(Color.Blue)
  20.             .onChange((value: string) => {
  21.               this.input_text = value;
  22.             })
  23.           Button({type: ButtonType.Capsule}) { Text("Go") }
  24.           .onClick(() => {
  25.             this.controller.loadUrl(this.input_text);
  26.           })
  27.           Button({type: ButtonType.Capsule}) { Text("addAdsBlockAllowedList") }
  28.           .onClick(() => {
  29.             let arrDisallowDomainSuffixes = new Array<string>();
  30.             arrDisallowDomainSuffixes.push('example.com');
  31.             webview.AdsBlockManager.addAdsBlockDisallowedList(arrDisallowDomainSuffixes);
  32.             let arrAllowedDomainSuffixes = new Array<string>();
  33.             arrAllowedDomainSuffixes.push('news.example.com');
  34.             arrAllowedDomainSuffixes.push('sport.example.com');
  35.             webview.AdsBlockManager.addAdsBlockAllowedList(arrAllowedDomainSuffixes);
  36.           })
  37.         }
  38.       }
  39.       Web({ src: this.main_url, controller: this.controller })
  40.         .onControllerAttached(()=>{
  41.           this.controller.enableAdsBlock(true);
  42.         })
  43.     }
  44.   }
  45. }
复制代码
须要留意的是,AdsBlockManager的DisallowedList和AllowedList列表不会长期化,因此重启应用后会重置为空。
如果Web组件未通过enableAdsBlock()接口开启广告过滤功能,上述接口设置在此Web组件中将不起作用。
网络广告过滤的信息

在Web组件的广告过滤开关开启后,访问的网页如果发生了广告过滤,会通过Web组件的 onAdsBlocked() 回调接口关照到应用,应用可根据须要举行过滤信息的网络和统计。
  1. // xxx.ets
  2. import { webview } from '@kit.ArkWeb';
  3. @Entry
  4. @Component
  5. struct WebComponent {
  6.   @State totalAdsBlockCounts: number = 0;
  7.   controller: webview.WebviewController = new webview.WebviewController();
  8.   build() {
  9.     Column() {
  10.       Web({ src: 'https://www.example.com', controller: this.controller })
  11.         .onAdsBlocked((details: AdsBlockedDetails) => {
  12.           if (details) {
  13.             console.log(' Blocked ' + details.adsBlocked.length + ' in ' + details.url);
  14.             let adList: Array<string> = Array.from(new Set(details.adsBlocked));
  15.             this.totalAdsBlockCounts += adList.length;
  16.             console.log('Total blocked counts :' + this.totalAdsBlockCounts);
  17.           }
  18.         })
  19.     }
  20.   }
  21. }
复制代码
由于页面大概随时发生变革并不停产生网络哀求,为了淘汰关照频次、低沉对页面加载过程的影响,仅在页面加载完成时举行初次关照,以后发生的过滤将隔断1秒钟上报,无广告过滤则无关照。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表