未验证 提交 78582225 编写于 作者: O openharmony_ci 提交者: Gitee

!17054 精品文档-媒体+文件修改+Web

Merge pull request !17054 from zengyawen/OpenHarmony-3.2-Release
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
- 应用程序包结构 - 应用程序包结构
- [Stage模型应用程序包结构](quick-start/application-package-structure-stage.md) - [Stage模型应用程序包结构](quick-start/application-package-structure-stage.md)
- [FA模型应用程序包结构](quick-start/application-package-structure-fa.md) - [FA模型应用程序包结构](quick-start/application-package-structure-fa.md)
- [HAR包结构](quick-start/har-package.md)
- 应用程序包多HAP机制 - 应用程序包多HAP机制
- [多HAP机制设计目标](quick-start/multi-hap-objective.md) - [多HAP机制设计目标](quick-start/multi-hap-objective.md)
- [多HAP构建视图](quick-start/multi-hap-build-view.md) - [多HAP构建视图](quick-start/multi-hap-build-view.md)
...@@ -25,6 +24,12 @@ ...@@ -25,6 +24,12 @@
- [多HAP使用规则](quick-start/multi-hap-rules.md) - [多HAP使用规则](quick-start/multi-hap-rules.md)
- [多HAP运行机制及数据通信方式](quick-start/multi-hap-principles.md) - [多HAP运行机制及数据通信方式](quick-start/multi-hap-principles.md)
- [应用程序包安装和卸载流程](quick-start/application-package-install-uninstall.md) - [应用程序包安装和卸载流程](quick-start/application-package-install-uninstall.md)
- 共享包
- [共享包概述](quick-start/shared-guide.md)
- [HAR](quick-start/har-package.md)
- HSP
- [应用内HSP开发指导](quick-start/in-app-hsp.md)
- [应用间HSP开发指导(仅对系统应用开放)](quick-start/cross-app-hsp.md)
- 应用配置文件(Stage模型) - 应用配置文件(Stage模型)
- [应用配置文件概述(Stage模型)](quick-start/application-configuration-file-overview-stage.md) - [应用配置文件概述(Stage模型)](quick-start/application-configuration-file-overview-stage.md)
- [app.json5配置文件](quick-start/app-configuration-file.md) - [app.json5配置文件](quick-start/app-configuration-file.md)
...@@ -49,6 +54,7 @@ ...@@ -49,6 +54,7 @@
- 开发 - 开发
- [应用模型](application-models/Readme-CN.md) - [应用模型](application-models/Readme-CN.md)
- [UI开发](ui/Readme-CN.md) - [UI开发](ui/Readme-CN.md)
- [Web](web/Readme-CN.md)
- [通知](notification/Readme-CN.md) - [通知](notification/Readme-CN.md)
- [窗口管理](windowmanager/Readme-CN.md) - [窗口管理](windowmanager/Readme-CN.md)
- [WebGL](webgl/Readme-CN.md) - [WebGL](webgl/Readme-CN.md)
...@@ -71,7 +77,7 @@ ...@@ -71,7 +77,7 @@
- [DevEco Studio(OpenHarmony)使用指南](quick-start/deveco-studio-user-guide-for-openharmony.md) - [DevEco Studio(OpenHarmony)使用指南](quick-start/deveco-studio-user-guide-for-openharmony.md)
- [调试工具](tools/Readme-CN.md) - [调试工具](tools/Readme-CN.md)
- 示例教程 - 示例教程
- [示例代码](https://gitee.com/openharmony/applications_app_samples/blob/monthly_20221018/README_zh.md) - [示例代码](https://gitee.com/openharmony/applications_app_samples/blob/OpenHarmony-3.2-Release/README_zh.md)
- [Codelabs](https://gitee.com/openharmony/codelabs/blob/master/README.md) - [Codelabs](https://gitee.com/openharmony/codelabs/blob/master/README.md)
- API参考 - API参考
- [系统能力SystemCapability使用指南](reference/syscap.md) - [系统能力SystemCapability使用指南](reference/syscap.md)
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
所有应用都应该在这两个框架的基础之上进行功能的开发。 所有应用都应该在这两个框架的基础之上进行功能的开发。
在此基础上,还提供了如下功能的开发指导: 在此基础上,还提供了如下功能的开发指导:
- [Web](web/web-component-overview.md)
- [通知](notification/Readme-CN.md) - [通知](notification/Readme-CN.md)
- [窗口管理](windowmanager/Readme-CN.md) - [窗口管理](windowmanager/Readme-CN.md)
- [WebGL](webgl/Readme-CN.md) - [WebGL](webgl/Readme-CN.md)
...@@ -50,7 +52,7 @@ DevEco Studio工具是OpenHarmony应用开发的推荐IDE工具。 ...@@ -50,7 +52,7 @@ DevEco Studio工具是OpenHarmony应用开发的推荐IDE工具。
### 示例教程 ### 示例教程
我们提供了[Sample工程](https://gitee.com/openharmony/applications_app_samples/blob/monthly_20221018/README_zh.md)[Codelab](https://gitee.com/openharmony/codelabs/blob/master/README.md)这两种形式的示例教程,为开发者提供更丰富的开发参考,辅助开发者理解功能逻辑,提升开发效率。 我们提供了[Sample工程](https://gitee.com/openharmony/applications_app_samples/blob/OpenHarmony-3.2-Release/README_zh.md)[Codelab](https://gitee.com/openharmony/codelabs/blob/master/README.md)这两种形式的示例教程,为开发者提供更丰富的开发参考,辅助开发者理解功能逻辑,提升开发效率。
### API参考 ### API参考
...@@ -62,14 +64,12 @@ API参考提供了OpenHarmony全量组件和接口的参考文档,可以帮助 ...@@ -62,14 +64,12 @@ API参考提供了OpenHarmony全量组件和接口的参考文档,可以帮助
- [组件参考(基于JS扩展的类Web开发范式)](reference/arkui-js/Readme-CN.md) - [组件参考(基于JS扩展的类Web开发范式)](reference/arkui-js/Readme-CN.md)
- [JS服务卡片UI组件参考](reference/js-service-widget-ui/Readme-CN.md) - [JS服务卡片UI组件参考](reference/js-service-widget-ui/Readme-CN.md)
- 接口参考 - 接口参考
- [JS及TS API参考](reference/apis/Readme-CN.md) - [JS及TS API参考](reference/apis/Readme-CN.md)
- Native API - Native API
- [Native API参考](reference/native-apis/Readme-CN.md) - [Native API参考](reference/native-apis/Readme-CN.md)
- [标准库](reference/native-lib/third_party_libc/musl.md) - [标准库](reference/native-lib/third_party_libc/musl.md)
- [Node_API](reference/native-lib/third_party_napi/napi.md) - [Node_API](reference/native-lib/third_party_napi/napi.md)
### Readme ### Readme
如果需要了解各子系统的原理和基本信息,可以参考“[docs/zh-cn/readme](../readme)”目录中各子系统readme的介绍。 如果需要了解各子系统的原理和基本信息,可以参考“[docs/zh-cn/readme](../readme)”目录中各子系统readme的介绍。
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
所有应用都应该在这两个框架的基础之上进行功能的开发。 所有应用都应该在这两个框架的基础之上进行功能的开发。
在此基础上,还提供了如下功能的开发指导: 在此基础上,还提供了如下功能的开发指导:
- [Web](web/web-component-overview.md)
- [通知](notification/notification-overview.md) - [通知](notification/notification-overview.md)
- [窗口管理](windowmanager/window-overview.md) - [窗口管理](windowmanager/window-overview.md)
- [WebGL](webgl/webgl-overview.md) - [WebGL](webgl/webgl-overview.md)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
## 接口说明 ## 接口说明
API的详细介绍请参见[ohos.file.statvfs](../reference/apis/js-apis-file-statvfs.md)[ohos.file.storageStatistics](../reference/apis/js-apis-storage-statistics.md) API的详细介绍请参见[ohos.file.statvfs](../reference/apis/js-apis-file-statvfs.md)[ohos.file.storageStatistics](../reference/apis/js-apis-file-storage-statistics.md)
**表1** 文件系统空间和应用空间统计 **表1** 文件系统空间和应用空间统计
......
# 跨设备文件访问 # 跨设备文件访问
分布式文件系统为应用提供了跨设备文件访问的能力,开发者在多个设备安装同一应用时,通过[基础文件接口](app-file-access-mgmt.md),可跨设备读写其他设备该应用分布式文件路径(/data/storage/el2/distributedfiles/)下的文件。例如:多设备数据流转的场景,设备组网互联之后,设备A上的应用可访问设备B同应用分布式路径下的文件,当期望应用文件被其他设备访问时,只需将文件移动到分布式文件路径即可。 分布式文件系统为应用提供了跨设备文件访问的能力,开发者在多个设备安装同一应用时,通过[基础文件接口](app-file-access.md),可跨设备读写其他设备该应用分布式文件路径(/data/storage/el2/distributedfiles/)下的文件。例如:多设备数据流转的场景,设备组网互联之后,设备A上的应用可访问设备B同应用分布式路径下的文件,当期望应用文件被其他设备访问时,只需将文件移动到分布式文件路径即可。
## 开发步骤 ## 开发步骤
......
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
3. 创建音频选择器实例。调用[select()](../reference/apis/js-apis-file-picker.md#select-6)接口拉起FilePicker界面进行文件选择。 3. 创建音频选择器实例。调用[select()](../reference/apis/js-apis-file-picker.md#select-6)接口拉起FilePicker界面进行文件选择。
文件选择成功后,返回被选中音频的URI结果集。开发者可以根据结果集中URI做进一步的处理。 文件选择成功后,返回被选中音频的URI结果集。开发者可以根据结果集中URI做进一步的处理。
例如通过[文件管理接口](../reference/apis/js-apis-file-fs.md#ohosfilefs-%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86)根据URI拿到音频资源的文件句柄(FD),再配合媒体服务实现音频播放的开发,具体请参考[音频播放开发指导](../media/audio-playback-overview.md)。 例如通过[文件管理接口](../reference/apis/js-apis-file-fs.md)根据URI拿到音频资源的文件句柄(FD),再配合媒体服务实现音频播放的开发,具体请参考[音频播放开发指导](../media/audio-playback-overview.md)。
> **说明:** > **说明:**
> >
> 目前AudioSelectOptions不支持参数配置,默认可以选择所有类型的用户文件。 > 目前AudioSelectOptions不支持参数配置,默认可以选择所有类型的用户文件。
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
## 读取或监听应用内音频流状态变化 ## 读取或监听应用内音频流状态变化
参考[使用AudioCapturer开发音频录制功能](using-audiocapturer-for-recording.md)[audio.createAudioCapturer](../apis/js-apis-audio.md#audiocreateaudiocapturer8),完成AudioRenderer的创建,然后可以通过以下两种方式查看音频流状态的变化: 参考[使用AudioCapturer开发音频录制功能](using-audiocapturer-for-recording.md)[audio.createAudioCapturer](../reference/apis/js-apis-audio.md#audiocreateaudiocapturer8),完成AudioRenderer的创建,然后可以通过以下两种方式查看音频流状态的变化:
- 方法1:直接查看AudioCapturer的[state](../apis/js-apis-audio.md#属性) - 方法1:直接查看AudioCapturer的[state](../reference/apis/js-apis-audio.md#属性)
```ts ```ts
let audioCapturerState = audioCapturer.state; let audioCapturerState = audioCapturer.state;
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
}); });
``` ```
获取state后可对照[AudioState](../apis/js-apis-audio.md#audiostate8)来进行相应的操作,比如显示录制结束的提示等。 获取state后可对照[AudioState](../reference/apis/js-apis-audio.md#audiostate8)来进行相应的操作,比如显示录制结束的提示等。
## 读取或监听所有录制流的变化 ## 读取或监听所有录制流的变化
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
在进行应用开发的过程中,开发者需要使用getStreamManager()创建一个AudioStreamManager实例,进而通过该实例管理音频流。开发者可通过调用on('audioCapturerChange')监听音频流的变化,在音频流状态变化、设备变化时获得通知,同时可通过off('audioCapturerChange')取消相关事件的监听。另外,开发者可以通过主动调用getCurrentAudioCapturerInfoArray()查询录制流的唯一ID、录制流客户端的UID、以及流状态等信息。 在进行应用开发的过程中,开发者需要使用getStreamManager()创建一个AudioStreamManager实例,进而通过该实例管理音频流。开发者可通过调用on('audioCapturerChange')监听音频流的变化,在音频流状态变化、设备变化时获得通知,同时可通过off('audioCapturerChange')取消相关事件的监听。另外,开发者可以通过主动调用getCurrentAudioCapturerInfoArray()查询录制流的唯一ID、录制流客户端的UID、以及流状态等信息。
详细API含义可参考[音频管理API文档AudioStreamManager](../apis/js-apis-audio.md#audiostreammanager9) 详细API含义可参考[音频管理API文档AudioStreamManager](../reference/apis/js-apis-audio.md#audiostreammanager9)
## 开发步骤及注意事项 ## 开发步骤及注意事项
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
以上权限的授权方式均为user_grant(用户授权),即开发者在module.json5文件中配置对应的权限后,需要使用接口[abilityAccessCtrl.requestPermissionsFromUser](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)去校验当前用户是否已授权。如果是,应用可以直接访问/操作目标对象;否则需要弹框向用户申请授权。 以上权限的授权方式均为user_grant(用户授权),即开发者在module.json5文件中配置对应的权限后,需要使用接口[abilityAccessCtrl.requestPermissionsFromUser](../reference/apis/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)去校验当前用户是否已授权。如果是,应用可以直接访问/操作目标对象;否则需要弹框向用户申请授权。
具体申请方式及校验方式,请参考[访问控制授权申请指导](../security/accesstoken-guidelines.md/) 具体申请方式及校验方式,请参考[访问控制授权申请指导](../security/accesstoken-guidelines.md)
> **说明:** > **说明:**
......
# 图片解码 # 图片解码
图片解码指将所支持格式的存档图片解码成统一的[PixelMap](image-overview.md),以便在应用或系统中进行图片显示或[图片处理](image-overview.md)。当前支持的存档图片格式包括JPEG、PNG、GIF、RAW、WebP、BMP、SVG。 图片解码指将所支持格式的存档图片解码成统一的[PixelMap](image-overview.md),以便在应用或系统中进行图片显示或[图片处理](image-transformation.md)。当前支持的存档图片格式包括JPEG、PNG、GIF、RAW、WebP、BMP、SVG。
## 开发步骤 ## 开发步骤
...@@ -108,7 +108,7 @@ ...@@ -108,7 +108,7 @@
const pixelMap = await imageSource.createPixelMap(decodingOptions); const pixelMap = await imageSource.createPixelMap(decodingOptions);
``` ```
解码完成,获取到PixelMap对象后,可以进行后续[图片处理](image-processing.md) 解码完成,获取到PixelMap对象后,可以进行后续[图片处理](image-transformation.md)
## 开发示例-对资源文件中的图片进行解码 ## 开发示例-对资源文件中的图片进行解码
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
> **说明:** > **说明:**
> >
> AVRecorder只负责视频数据的处理,需要与视频数据采集模块配合才能完成视频录制。视频数据采集模块需要通过Surface将视频数据传递给AVRecorder进行数据处理。当前常用的数据采集模块为相机模块,相机模块目前仅对系统应用开放,具体请参考[相机模块](camera.md) > AVRecorder只负责视频数据的处理,需要与视频数据采集模块配合才能完成视频录制。视频数据采集模块需要通过Surface将视频数据传递给AVRecorder进行数据处理。当前常用的数据采集模块为相机模块,相机模块目前仅对系统应用开放,具体请参考[相机模块](../reference/apis/js-apis-camera.md)。
AVRecorder详细的API说明请参考[AVRecorder API参考](../reference/apis/js-apis-media.md#avrecorder9) AVRecorder详细的API说明请参考[AVRecorder API参考](../reference/apis/js-apis-media.md#avrecorder9)
......
# Web
- [Web组件概述](web-component-overview.md)
- [使用Web组件加载页面](web-page-loading-with-web-components.md)
- 设置基本属性和事件
- [设置深色模式](web-set-dark-mode.md)
- [上传文件](web-file-upload.md)
- [在新窗口中打开页面](web-open-in-new-window.md)
- [管理位置权限](web-geolocation-permission.md)
- 在应用中使用前端页面JavaScript
- [应用侧调用前端页面函数](web-in-app-frontend-page-function-invoking.md)
- [前端页面调用应用侧函数](web-in-page-app-function-invoking.md)
- [建立应用侧与前端页面数据通道](web-app-page-data-channel.md)
- [管理页面跳转及浏览记录导航](web-redirection-and-browsing-history-mgmt.md)
- [管理Cookie及数据存储](web-cookie-and-data-storage-mgmt.md)
- [自定义页面请求响应](web-resource-interception-request-mgmt.md)
- [使用Devtools工具调试前端页面](web-debugging-with-devtools.md)
\ No newline at end of file
# 建立应用侧与前端页面数据通道
前端页面和应用侧之间可以用[createWebMessagePorts()](../reference/apis/js-apis-webview.md#createwebmessageports)接口创建消息端口来实现两端的通信。
在下面的示例中,用侧页面中通过createWebMessagePorts方法创建消息端口,再把其中一个端口通过[postMessage()](../reference/apis/js-apis-webview.md#postmessage)接口发送到前端页面,便可以在前端页面和应用侧之间互相发送消息。
- 应用侧代码。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@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) {
console.error(`ErrorCode: ${error.code}, Message: ${error.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) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
Web({ src: $rawfile('xxx.html'), controller: this.controller })
}
}
}
```
- 前端页面代码。
```html
<!--xxx.html-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView Message Port Demo</title>
</head>
<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. 保存从ets侧发送过来的端口
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往ets侧发送消息.
function PostMsgToEts(data) {
if (h5Port) {
h5Port.postMessage(data);
} else {
console.error('h5Port is null, Please initialize first');
}
}
</script>
<body>
<h1>WebView Message Port Demo</h1>
<div>
<input type="button" value="SendToEts" onclick="PostMsgToEts(msgFromJS.value);"/><br/>
<input id="msgFromJS" type="text" value="send this message from HTML to ets"/><br/>
</div>
<p class="output">display received message send from ets</p>
</body>
</html>
```
# Web组件概述
Web组件用于在应用程序中显示Web页面内容,为开发者提供页面加载、页面交互、页面调试等能力。
- 页面加载:Web组件提供基础的前端页面加载的能力,包括加载网络页面、本地页面、Html格式文本数据。
- 页面交互:Web组件提供丰富的页面交互的方式,包括:设置前端页面深色模式,新窗口中加载页面,位置权限管理,Cookie管理,应用侧使用前端页面JavaScript等能力。
- 页面调试:Web组件支持使用Devtools工具调试前端页面。
下面通过常见使用场景举例,来具体介绍Web组件功能特性。
# 管理Cookie及数据存储
## Cookie管理
Cookie是网络访问过程中,由服务端发送给客户端的一小段数据。客户端可持有该数据,并在后续访问该服务端时,方便服务端快速对客户端身份、状态等进行识别。
Web组件提供了WebCookieManager类,用于管理Web组件的Cookie信息。Cookie信息保存在应用沙箱路径下/proc/{pid}/root/data/storage/el2/base/cache/web/Cookiesd的文件中。
下面以[setCookie()](../reference/apis/js-apis-webview.md#setcookie)接口举例,为“www.example.com”设置单个Cookie的值“value=test”。其他Cookie的相关功能及使用,请参考[WebCookieManager()](../reference/apis/js-apis-webview.md#webcookiemanager)接口文档。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@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) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
Web({ src: 'www.example.com', controller: this.controller })
}
}
}
```
## 缓存与存储管理
在访问网站时,网络资源请求是相对比较耗时的。开发者可以通过Cache、Dom Storage等手段将资源保持至本地,以提升访问同一网站的速度。
### Cache
使用[cacheMode()](../reference/arkui-ts/ts-basic-components-web.md#cachemode%E6%9E%9A%E4%B8%BE%E8%AF%B4%E6%98%8E)配置页面资源的缓存模式,Web组件为开发者提供四种缓存模式,分别为:
- Default : 优先使用未过期的缓存,如果缓存不存在,则从网络获取。
- None : 加载资源使用cache,如果cache中无该资源则从网络中获取。
- Online : 加载资源不使用cache,全部从网络中获取。
- Only :只从cache中加载资源。
在下面的示例中,选用缓存设置为None模式。
```ts
// 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()](../reference/apis/js-apis-webview.md#removecache)接口清除已经缓存的资源,示例代码如下:
```ts
// 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() {
Button('removeCache')
.onClick(() => {
try {
// 设置为true时同时清除rom和ram中的缓存,设置为false时只清除ram中的缓存
this.controller.removeCache(true);
} catch (error) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
Web({ src: 'www.example.com', controller: this.controller })
.cacheMode(this.mode)
}
}
}
```
### Dom Storage
Dom Storage包含了Session Storage和Local Storage两类。前者为临时数据,其存储与释放跟随会话生命周期;后者为可持久化数据,落盘在应用目录下。两者的数据均通过Key-Value的形式存储,通常在访问需要客户端存储的页面时使用。开发者可以通过Web组件的属性接口[domStorageAccess()](../reference/arkui-ts/ts-basic-components-web.md#domstorageaccess)进行使能配置,示例如下:
```ts
// 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)
}
}
}
```
# 使用Devtools工具调试前端页面
Web组件支持使用DevTools工具调试前端页面。DevTools是一个 Web前端开发调试工具,提供了电脑上调试移动设备前端页面的能力。开发者通过[setWebDebuggingAccess()](../reference/apis/js-apis-webview.md#setwebdebuggingaccess)接口开启Web组件前端页面调试能力,利用DevTools工具可以在电脑上调试移动设备上的前端网页。
使用DevTools工具,可以执行以下步骤:
1. 在应用代码中开启Web调试开关,具体如下:
```ts
// 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. 将设备连接上电脑,在电脑端配置端口映射,配置方法如下:
```
// 添加映射
hdc fport tcp:9222 tcp:9222
// 查看映射
hdc fport ls
```
3. 在电脑端chrome浏览器地址栏中输入chrome://inspect/\#devices,页面识别到设备后,就可以开始页面调试。调试效果如下:
**图1** 页面调试效果图
![debug-effect](figures/debug-effect.png)
# 上传文件
Web组件支持前端页面选择文件上传功能,应用开发者可以使用[onShowFileSelector()](../reference/arkui-ts/ts-basic-components-web.md#onshowfileselector9)接口来处理前端页面文件上传的请求。
下面的示例中,当用户在前端页面点击文件上传按钮,应用侧在[onShowFileSelector()](../reference/arkui-ts/ts-basic-components-web.md#onshowfileselector9)接口中收到文件上传请求,在此接口中开发者将上传的本地文件路径设置给前端页面。
- 应用侧代码。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
controller: WebController = new WebController()
build() {
Column() {
// 加载本地local.html页面
Web({ src: $rawfile('local.html'), controller: this.controller })
.onShowFileSelector((event) => {
// 开发者设置要上传的文件路径
let fileList: Array<string> = [
'xxx/test.png',
]
event.result.handleFileList(fileList)
return true;
})
}
}
}
```
- local.html页面代码。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Document</title>
</head>
<body>
<!-- 点击上传文件按钮 -->
<input type="file" value="file"></br>
</body>
</html>
```
# 管理位置权限
Web组件提供位置权限管理能力。开发者可以通过[onGeolocationShow()](../reference/arkui-ts/ts-basic-components-web.md#ongeolocationshow)接口对某个网站进行位置权限管理。Web组件根据接口响应结果,决定是否赋予前端页面权限。获取设备位置,需要开发者配置[ohos.permission.LOCATION](../security/accesstoken-guidelines.md)权限。
在下面的示例中,用户点击前端页面"获取位置"按钮,Web组件通过弹窗的形式通知应用侧位置权限请求消息。
- 前端页面代码。
```html
<!DOCTYPE html>
<html>
<body>
<p id="locationInfo">位置信息</p>
<button onclick="getLocation()">获取位置</button>
<script>
var locationInfo=document.getElementById("locationInfo");
function getLocation(){
if (navigator.geolocation) {
<!-- 前端页面访问设备地理位置 -->
navigator.geolocation.getCurrentPosition(showPosition);
}
}
function showPosition(position){
locationInfo.innerHTML="Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude;
}
</script>
</body>
</html>
```
- 应用代码。
```ts
// 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:$rawfile('getLocation.html'), controller:this.controller })
.geolocationAccess(true)
.onGeolocationShow((event) => { // 地理位置权限申请通知
AlertDialog.show({
title: '位置权限请求',
message: '是否允许获取位置信息',
primaryButton: {
value: 'cancel',
action: () => {
event.geolocation.invoke(event.origin, false, false); // 不允许此站点地理位置权限请求
}
},
secondaryButton: {
value: 'ok',
action: () => {
event.geolocation.invoke(event.origin, true, false); // 允许此站点地理位置权限请求
}
},
cancel: () => {
event.geolocation.invoke(event.origin, false, false); // 不允许此站点地理位置权限请求
}
})
})
}
}
}
```
# 应用侧调用前端页面函数
应用侧可以通过[runJavaScript()](../reference/apis/js-apis-webview.md#runjavascript)方法调用前端页面的JavaScript相关函数。
在下面的示例中,点击应用侧的“runJavaScript”按钮时,来触发前端页面的htmlTest()方法。
- 前端页面代码。
```html
<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<script>
function htmlTest() {
console.info('JavaScript Hello World! ');
}
</script>
</body>
</html>
```
- 应用侧代码。
```ts
// 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组件将应用侧代码注册到前端页面中,注册完成之后,前端页面中使用注册的对象名称就可以调用应用侧的函数,实现在前端页面中调用应用侧方法。
注册应用侧代码有两种方式,一种在Web组件初始化使用调用,使用[javaScriptProxy()](../reference/arkui-ts/ts-basic-components-web.md#javascriptproxy)接口。另外一种在Web组件初始化完成后调用,使用[registerJavaScriptProxy()](../reference/apis/js-apis-webview.md#registerjavascriptproxy)接口。
在下面的示例中,将test()方法注册在前端页面中, 该函数可以在前端页面触发运行。
- [javaScriptProxy()](../reference/arkui-ts/ts-basic-components-web.md#javascriptproxy)接口使用示例如下。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
// 声明需要注册的对象
testObj = {
test: () => {
return 'ArkTS Hello World!';
}
}
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
})
}
}
}
```
- 应用侧使用registerJavaScriptProxy()接口注册。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct Index {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
testObj = {
test: (data) => {
return "ArkUI Web Component";
},
toString: () => {
console.info('Web Component toString');
}
}
build() {
Column() {
Button('refresh')
.onClick(() => {
try {
this.webviewController.refresh();
} catch (error) {
console.error(`Errorcode: ${error.code}, Message: ${error.message}`);
}
})
Button('Register JavaScript To Window')
.onClick(() => {
try {
this.webviewController.registerJavaScriptProxy(this.testObj, "objName", ["test", "toString"]);
} catch (error) {
console.error(`Errorcode: ${error.code}, Message: ${error.message}`);
}
})
Web({ src: $rawfile('index.html'), controller: this.webviewController })
}
}
}
```
> **说明:**
>
> 使用[registerJavaScriptProxy()](../reference/apis/js-apis-webview.md#registerjavascriptproxy)接口注册方法时,注册后需调用[refresh()](../reference/apis/js-apis-webview.md#refresh)接口生效。
- index.htm前端页面触发应用侧代码。
```html
<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<button type="button" onclick="callArkTS()">Click Me!</button>
<p id="demo"></p>
<script>
function callArkTS() {
let str = testObjName.test();
document.getElementById("demo").innerHTML = str;
console.info('ArkTS Hello World! :' + str);
}
</script>
</body>
</html>
```
# 在新窗口中打开页面
Web组件提供了在新窗口打开页面的能力,开发者可以通过[multiWindowAccess()](../reference/arkui-ts/ts-basic-components-web.md#multiwindowaccess9)接口来设置是否允许网页在新窗口打开。当有新窗口打开时,应用侧会在[onWindowNew()](../reference/arkui-ts/ts-basic-components-web.md#onwindownew9)接口中收到Web组件新窗口事件,开发者需要在此接口事件中,新建窗口来处理Web组件窗口请求。
> **说明:**
>
> - [allowWindowOpenMethod()](../reference/arkui-ts/ts-basic-components-web.md#allowwindowopenmethod9)接口设置为true时,前端页面通过JavaScript函数调用的方式打开新窗口。
>
> - 如果开发者在[onWindowNew()](../reference/arkui-ts/ts-basic-components-web.md#onwindownew9)接口通知中不需要打开新窗口,需要将[ControllerHandler.setWebController()](../reference/arkui-ts/ts-basic-components-web.md#onwindownew9)接口返回值设置成null。
如下面的本地示例,当用户点击“新窗口中打开网页”按钮时,应用侧会在[onWindowNew()](../reference/arkui-ts/ts-basic-components-web.md#onwindownew9)接口中收到Web组件新窗口事件。
- 应用侧代码。
创建新窗口的方法可参考[Web开发相关例子](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Web/Browser)
```ts
// 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:$rawfile("window.html"), controller: this.controller })
.multiWindowAccess(true)
.onWindowNew((event) => {
console.info("onWindowNew...");
var popController: web_webview.WebviewController = new web_webview.WebviewController();
// 开发者需要在此处新建窗口,跟popController关联,并且将popController返回给Web组件。如果不需要打开新窗口请将返回值设置为event.handler.setWebController(null);
event.handler.setWebController(popController);
})
}
}
}
```
- window.html页面代码。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WindowEvent</title>
</head>
<body>
<input type="button" value="新窗口中打开网页" onclick="OpenNewWindow()">
<script type="text/javascript">
function OpenNewWindow()
{
let openedWindow = window.open("about:blank", "", "location=no,status=no,scrollvars=no");
if (openedWindow) {
openedWindow.document.body.write("<p>这是我的窗口</p>");
} else {
log.innerHTML = "window.open failed";
}
}
</script>
</body>
</html>
```
# 使用Web组件加载页面
页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景,包括加载网络页面、加载本地页面、加载HTML格式的富文本数据。
页面加载过程中,若涉及网络资源获取,需要配置[ohos.permission.INTERNET](../security/accesstoken-guidelines.md)网络访问权限。
## 加载网络页面
开发者可以在Web组件创建的时候指定默认加载的网络页面 。在默认页面加载完成后,如果开发者需要变更此Web组件显示的网络页面,可以通过调用[loadUrl()](../reference/apis/js-apis-webview.md#loadurl)接口加载指定网络网页。
在下面的示例中,在Web组件加载完“www.example.com”页面后,开发者可通过loadUrl接口将此Web组件显示页面变更为“www.example1.com”。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Button('loadUrl')
.onClick(() => {
try {
// 点击按钮时,通过loadUrl,跳转到www.example1.com
this.webviewController.loadUrl('www.example1.com');
} catch (error) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
// 组件创建时,加载www.example.com
Web({ src: 'www.example.com', controller: this.webviewController})
}
}
}
```
## 加载本地页面
将本地页面文件放在应用的rawfile目录下,开发者可以在Web组件创建的时候指定默认加载的本地页面 ,并且加载完成后可通过调用[loadUrl()](../reference/apis/js-apis-webview.md#loadurl)接口变更当前Web组件的页面。
在下面的示例中展示加载本地页面文件的方法:
- 将资源文件放置在应用的resources/rawfile目录下。
**图1** 资源文件路径  
![resource-path](figures/resource-path.png)
- 应用侧代码。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
webviewController: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Button('loadUrl')
.onClick(() => {
try {
// 点击按钮时,通过loadUrl,跳转到local1.html
this.webviewController.loadUrl($rawfile("local1.html"));
} catch (error) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
// 组件创建时,通过$rawfile加载本地文件local.html
Web({ src: $rawfile("local.html"), controller: this.webviewController })
}
}
}
```
- local.html页面代码。
```html
<!-- local.html -->
<!DOCTYPE html>
<html>
<body>
<p>Hello World</p>
</body>
</html>
```
## 加载HTML格式的文本数据
Web组件可以通过[loadData()](../reference/apis/js-apis-webview.md#loaddata)接口实现加载HTML格式的文本数据。当开发者不需要加载整个页面,只需要显示一些页面片段时,可通过此功能来快速加载页面。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Button('loadData')
.onClick(() => {
try {
// 点击按钮时,通过loadData,加载HTML格式的文本数据
this.controller.loadData(
'<html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>',
'text/html',
'UTF-8'
);
} catch (error) {
console.error(`ErrorCode: ${error.code}, Message: ${error.message}`);
}
})
// 组件创建时,加载www.example.com
Web({ src: 'www.example.com', controller: this.controller })
}
}
}
```
# 管理页面跳转及浏览记录导航
## 历史记录导航
使用者在前端页面点击网页中的链接时,Web组件默认会自动打开并加载目标网址。当前端页面替换为新的加载链接时,会自动记录已经访问的网页地址。可以通过[forward()](../reference/apis/js-apis-webview.md#forward)[backward()](../reference/apis/js-apis-webview.md#backward)接口向前/向后浏览上一个/下一个历史记录。
在下面的示例中,点击应用的按钮来触发前端页面的后退操作。
```ts
// 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();
return true;
}
})
Web({ src: 'https://www.example.com/cn/', controller: this.webviewController})
}
}
}
```
如果存在历史记录,[accessBackward()](../reference/apis/js-apis-webview.md#accessbackward)接口会返回true。同样,您可以使用[accessForward()](../reference/apis/js-apis-webview.md#accessforward)接口检查是否存在前进的历史记录。如果您不执行检查,那么当用户浏览到历史记录的末尾时,调用[forward()](../reference/apis/js-apis-webview.md#forward)[backward()](../reference/apis/js-apis-webview.md#backward)接口时将不执行任何操作。
## 页面跳转
当点击网页中的链接需要跳转到应用内其他页面时,可以通过使用Web组件的[onUrlLoadIntercept()](../reference/arkui-ts/ts-basic-components-web.md#onurlloadintercept)接口来实现。
在下面的示例中,应用首页Index.ets加载前端页面route.html,在前端route.html页面点击超链接,可跳转到应用的ProfilePage.ets页面。
- 应用首页index.ets页面代码。
```ts
// 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) => {
let url: string = event.data as string;
if (url.indexOf('native://') === 0) {
// 跳转其他界面
router.pushUrl({ url:url.substring(9) })
return true;
}
return false;
})
}
}
}
```
- route.html前端页面代码。
```html
<!-- route.html -->
<!DOCTYPE html>
<html>
<body>
<div>
<a href="native://pages/ProfilePage">个人中心</a>
</div>
</body>
</html>
```
- 跳转页面ProfilePage.ets代码。
```ts
@Entry
@Component
struct ProfilePage {
@State message: string = 'Hello World';
build() {
Column() {
Text(this.message)
.fontSize(20)
}
}
}
```
## 跨应用跳转
Web组件可以实现点击前端页面超链接跳转到其他应用。
在下面的示例中,点击call.html前端页面中的超连接,跳转到电话应用的拨号界面。
- 应用侧代码。
```ts
// 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('xxx.html'), controller: this.webviewController})
.onUrlLoadIntercept((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;
})
}
}
}
```
- 前端页面call.html代码。
```html
<!-- call.html -->
<!DOCTYPE html>
<html>
<body>
<div>
<a href="tel://xxx xxxx xxx">拨打电话</a>
</div>
</body>
</html>
```
# 自定义页面请求响应
Web组件支持在应用拦截到页面请求后自定义响应请求能力。开发者通过[onInterceptRequest()](../reference/arkui-ts/ts-basic-components-web.md#oninterceptrequest9)接口来实现自定义资源请求响应 。自定义请求能力可以用于开发者自定义Web页面响应、自定义文件资源响应等场景。
Web网页上发起资源加载请求,应用层收到资源请求消息。应用层构造本地资源响应消息发送给Web内核。Web内核解析应用层响应信息,根据此响应信息进行页面资源加载。
在下面的示例中,Web组件通过拦截页面请求“https://www.intercept.com/test.html”, 在应用侧代码构建响应资源,实现自定义页面响应场景。
- 前端页面example.html代码。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example</title>
</head>
<body>
<!-- 页面资源请求 -->
<a href="https://www.intercept.com/test.html">intercept test!</a>
</body>
</html>
```
- 应用侧代码。
```ts
// 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'+
'<h1>intercept ok</h1>\n'+
'</body>\n'+
'</html>'
build() {
Column() {
Web({ src: $rawfile('example.html'), controller: this.controller })
.onInterceptRequest((event) => {
console.info('url:' + event.request.getRequestUrl());
// 拦截页面请求
if (event.request.getRequestUrl() !== 'https://www.intercept.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;
})
}
}
}
```
# 设置深色模式
Web组件支持对前端页面进行深色模式配置。
- 通过[darkMode()](../reference/arkui-ts/ts-basic-components-web.md#darkmode9)接口可以配置不同的深色模式,[WebDarkMode.Off](../reference/arkui-ts/ts-basic-components-web.md#webdarkmode9%E6%9E%9A%E4%B8%BE%E8%AF%B4%E6%98%8E)模式表示关闭深色模式。[WebDarkMode.On](../reference/arkui-ts/ts-basic-components-web.md#webdarkmode9%E6%9E%9A%E4%B8%BE%E8%AF%B4%E6%98%8E)表示开启深色模式,并且深色模式跟随前端页面。[WebDarkMode.Auto](../reference/arkui-ts/ts-basic-components-web.md#webdarkmode9%E6%9E%9A%E4%B8%BE%E8%AF%B4%E6%98%8E)表示开启深色模式,并且深色模式跟随系统。
在下面的示例中, 通过[darkMode()](../reference/arkui-ts/ts-basic-components-web.md#darkmode9)接口将页面深色模式配置为跟随系统。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
@State mode: WebDarkMode = WebDarkMode.Auto;
build() {
Column() {
Web({ src: 'www.example.com', controller: this.controller })
.darkMode(this.mode)
}
}
}
```
- 通过[forceDarkAccess()](../reference/arkui-ts/ts-basic-components-web.md#forcedarkaccess9)接口可将前端页面强制配置深色模式,且深色模式不跟随前端页面和系统。配置该模式时候,需要将深色模式配置成WebDarkMode.On。
在下面的示例中, 通过[forceDarkAccess()](../reference/arkui-ts/ts-basic-components-web.md#forcedarkaccess9)接口将页面强制配置为深色模式。
```ts
// xxx.ets
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebComponent {
controller: web_webview.WebviewController = new web_webview.WebviewController();
@State mode: WebDarkMode = WebDarkMode.On;
@State access: boolean = true;
build() {
Column() {
Web({ src: 'www.example.com', controller: this.controller })
.darkMode(this.mode)
.forceDarkAccess(this.access)
}
}
}
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册