上篇回顾:ArkTS开发系列之事件(2.8.2手势事件)
本篇内容: ArkTS开发系列之Web组件的学习(2.9)
一、知识储备
Web组件就是用来展示网页的一个组件。具有页面加载、页面交互以及页面调试功能
1. 加载网络页面
Web({ src: this.indexUrl, controller: this.webViewController })
2. 加载本地页面
Web({ src: $rawfile('local.html'), controller: this.webViewController })
3. 加载html格式的文本数据
- 该示例中,是点击button后开始加载html格式的文本数据
Button('加载html文本内容')
.onClick(event => {
this.webViewController.loadData(
"<html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>",
"text/html",
"UTF-8"
);
})
Web({ src: this.indexUrl, controller: this.webViewController })
4.深色模式设置
Web({ src: this.indexUrl, controller: this.webViewController })
.darkMode(WebDarkMode.On) //设置深色模式
.forceDarkAccess(true)//强制生效
5. 文件上传
Web({ src: $rawfile('local.html'), controller: this.webViewController })
.onShowFileSelector(event=>{
//设置要上传的文件路径
let fileList: Array<string> =[
]
if (event) {
event.result.handleFileList(fileList)
}
return true;
})
6. 在新容器中打开页面
- 通过multiWindowAccess()来设置是否允许网页在新窗口中打开。有新窗口打开时,应用侧会在onWindowNew()接口中收到新窗口事件,需要我们在此接口中处理web组件的窗口请求
.onWindowNew(event=>{
}
- 如果开发者在onWindowNew()接口通知中不需要打开新窗口,需要将ControllerHandler.setWebController()接口返回值设置成null。
7. 管理位置权限
.geolocationAccess(true)
8. 应用调用html的js函数
Web({ src: $rawfile('local.html'), controller: this.webViewController })
.javaScriptAccess(true)
this.webViewController.runJavaScript('htmlTest()')
9. 前端调用应用函数
- 在web组件初始化的时候注入javaScriptProxy()
@State testObj: TestClass = new TestClass(); //注册应用内js调用函数的对象
Web({ src: $rawfile('local.html'), controller: this.webViewController })
.javaScriptProxy({//将对角注入到web端
object: this.testObj,
name: 'testObjName',
methodList: ['test'],
controller: this.webViewController
})
- 在web组件初始化完成后注入registerJavaScriptProxy()
this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"]);
10. 应用与前端页面数据通道
aboutToAppear() {
try {
//1.在这里初始化ports
this.ports = this.webViewController.createWebMessagePorts();
this.ports[1].onMessageEvent((result: webview.WebMessage) => { //2.接收消息,并根据业务处理消息
let msg = '读取网页消息'
if (typeof (result) == 'string') {
msg = msg + result;
} else if (typeof (result) == 'object') {
if (result instanceof ArrayBuffer) {
msg = msg + " result length: " + result.byteLength;
} else {
console.error('msg not support')
}
} else {
console.error('msg not support')
}
this.receiveMsgFromHtml = msg;
// 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。
this.webViewController.postMessage('__init_port__', [this.ports[0]], "*");
})
} catch (err) {
console.error('err: ' + JSON.stringify(err))
}
}
//4.给html发消息
this.ports[1].postMessageEvent(this.sendFromEts)
11. 管理web组件的页面跳转和浏览记录
- 返回上一页
this.controller.backward()
- 进入下一页
this.controller.forward()
- 从web组件跳转到hap应用内的页面
Web({ controller: this.controller, src: $rawfile('route.html') })
.onUrlLoadIntercept(event => {
let url: string = event.data as string;
if (url.indexOf('native://') === 0) {
router.pushUrl({ url: url.substring(9) })
return true;
}
return false;
})
- 跨应用的页面跳转
call.makeCall(url.substring(6), err => {
if (!err) {
console.info('打电话成功')
} else {
console.info('拨号失败' + JSON.stringify(err))
}
})
12. 管理Cookie及数据存储
Cookie信息保存在应用沙箱路径下/proc/{pid}/root/data/storage/el2/base/cache/web/Cookiesd的文件中。
由WebCookieManager管理cookie
webview.WebCookieManager.setCookie('https://www.baidu.com','val=yes') //存储cookie
- 四种缓存策略(Cache)
Default : 优先使用未过期的缓存,如果缓存不存在,则从网络获取。
None : 加载资源使用cache,如果cache中无该资源则从网络中获取。
Online : 加载资源不使用cache,全部从网络中获取。
Only :只从cache中加载资源。 - 清除缓存
this.controller.removeCache(true);
- 是否持久化缓存domStorageAccess
domStorageAccess(true) ///true是Local Storage持久化存储;false是Session Storage,会随会话生命周期释放
13. 自定义页面请求响应
通过对onIntercerptRequest接口来实现自定义
.onInterceptRequest((event?: Record<string, WebResourceRequest>): WebResourceResponse => {
if (!event) {
return new WebResourceResponse();
}
let mRequest: WebResourceRequest = event.request as WebResourceRequest;
console.info('url: ' + mRequest.getRequestUrl())
if (mRequest.getRequestUrl().indexOf('https://www.baidu.com') === 0) {
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;
}
return;
})
14.
- 第一步
aboutToAppear() {
// 配置web开启调试模式
web_webview.WebviewController.setWebDebuggingAccess(true);
}
- 第二步
// 添加映射
hdc fport tcp:9222 tcp:9222
// 查看映射
hdc fport ls
- 第三步
在电脑端chrome浏览器地址栏中输入chrome://inspect/#devices,页面识别到设备后,就可以开始页面调试。
二、 效果一览
三、 源码大杂烩
import webview from '@ohos.web.webview'
import router from '@ohos.router';
import call from '@ohos.telephony.call';
@Entry
@Component
struct Index {
controller: webview.WebviewController = new webview.WebviewController();
responseResource: WebResourceResponse = new WebResourceResponse();
@State webdata: string = "<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
"<title>将www.baidu.com改成我</title>\n" +
"</head>\n" +
"<body>\n" +
"<h1>将www.baidu.com改成我</h1>\n" +
"</body>\n" +
"</html>"
build() {
Column() {
Button('上一页')
.onClick(() => {
this.controller.backward()
})
Button('下一页')
.onClick(() => {
this.controller.forward()
})
Web({ controller: this.controller, src: 'www.baidu.com' })
// Web({ controller: this.controller, src: $rawfile('route.html') })
.onUrlLoadIntercept(event => {
let url: string = event.data as string;
if (url.indexOf('native://') === 0) {
router.pushUrl({ url: url.substring(9) })
return true;
} else if (url.indexOf('tel://') === 0) {
call.makeCall(url.substring(6), err => {
if (!err) {
console.info('打电话成功')
} else {
console.info('拨号失败' + JSON.stringify(err))
}
})
return true;
}
return false;
})
.onInterceptRequest((event?: Record<string, WebResourceRequest>): WebResourceResponse => {
if (!event) {
return new WebResourceResponse();
}
let mRequest: WebResourceRequest = event.request as WebResourceRequest;
console.info('url: ' + mRequest.getRequestUrl())
if (mRequest.getRequestUrl().indexOf('https://www.baidu.com') === 0) {
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;
}
return;
})
// webview.WebCookieManager.setCookie('https://www.baidu.com','val=yes')
}
.width('100%')
.height('100%')
}
}
import webview from '@ohos.web.webview';
import common from '@ohos.app.ability.common';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import geoLocationManager from '@ohos.geoLocationManager';
let context = getContext(this) as common.UIAbilityContext;
let atManager = abilityAccessCtrl.createAtManager();
try {
atManager.requestPermissionsFromUser(context, ["ohos.permission.LOCATION", "ohos.permission.APPROXIMATELY_LOCATION"], (err, data) => {
// let requestInfo: geoLocationManager.LocationRequest = {
// 'priority': 0x203,
// 'scenario': 0x300,
// 'maxAccuracy': 0
// };
//
// let locationChange = (location: geoLocationManager.Location): void => {
// if (location) {
// console.error('location = ' + JSON.stringify(location))
// }
// };
//
// try {
// geoLocationManager.on('locationChange', requestInfo, locationChange);
// geoLocationManager.off('locationChange', locationChange);
// } catch (err) {
// console.error('err : ' + JSON.stringify(err))
// }
console.info('data: ' + JSON.stringify(data))
console.info("data permissions: " + JSON.stringify(data.permissions))
console.info("data authResults: " + JSON.stringify(data.authResults))
}
)
} catch (err) {
console.error('err : ', err)
}
class TestClass {
constructor() {
}
test() {
return '我是应用内函数';
}
}
@Entry
@Component
struct Index {
@State indexUrl: string = 'www.baidu.com';
webViewController: webview.WebviewController = new webview.WebviewController();
dialog: CustomDialogController | null = null
@State testObj: TestClass = new TestClass(); //注册应用内js调用函数的对象
ports: webview.WebMessagePort[]; //消息端口
@State sendFromEts: string = '这消息将被发送到html'
@State receiveMsgFromHtml: string = '这将展示接收到html发来的消息'
aboutToAppear() {
try {
//1.在这里初始化ports
this.ports = this.webViewController.createWebMessagePorts();
this.ports[1].onMessageEvent((result: webview.WebMessage) => { //2.接收消息,并根据业务处理消息
let msg = '读取网页消息'
if (typeof (result) == 'string') {
msg = msg + result;
} else if (typeof (result) == 'object') {
if (result instanceof ArrayBuffer) {
msg = msg + " result length: " + result.byteLength;
} else {
console.error('msg not support')
}
} else {
console.error('msg not support')
}
this.receiveMsgFromHtml = msg;
// 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。
this.webViewController.postMessage('__init_port__', [this.ports[0]], "*");
})
} catch (err) {
console.error('err: ' + JSON.stringify(err))
}
}
build() {
Column() {
Button('加载html文本内容')
.onClick(event => {
this.webViewController.loadData(
"<html><body bgcolor=\"white\">Source:<pre>source</pre></body></html>",
"text/html",
"UTF-8"
);
})
Button('调用html的js函数')
.onClick(event => {
this.webViewController.runJavaScript('htmlTest()')
})
Button('web组件初始化完成后注入')
.onClick(event => {
this.webViewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test"]);
})
Text(this.receiveMsgFromHtml).fontSize(33)
Button('给html端发消息')
.onClick(() => {
try {
if (this.ports && this.ports[1]) {
//4.给html发消息
this.ports[1].postMessageEvent(this.sendFromEts)
} else {
console.error('ports init fail')
}
} catch (err) {
console.error('ports init fail ' + JSON.stringify(err))
}
})
// Web({ src: this.indexUrl, controller: this.webViewController })
// .darkMode(WebDarkMode.On) //设置深色模式
// .forceDarkAccess(true) //强制生效
// Web({ src: $rawfile('window.html'), controller: this.webViewController })
// .javaScriptAccess(true)
// .multiWindowAccess(true)
// .onWindowNew(event=>{
// if (this.dialog) {
// this.dialog.close()
// }
//
// let popController: webview.WebviewController = new webview.WebviewController();
//
// this.dialog = new CustomDialogController({
// builder: NewWebViewComp({webviewController1: popController})
// })
// this.dialog.open()
// //将新窗口对应WebviewController返回给Web内核。
// //如果不需要打开新窗口请调用event.handler.setWebController接口设置成null。
// //若不调用event.handler.setWebController接口,会造成render进程阻塞。
// event.handler.setWebController(popController)
// })
Web({ src: $rawfile('postMsg.html'), controller: this.webViewController })
// Web({ src: $rawfile('local.html'), controller: this.webViewController })
// .onShowFileSelector(event => {
// //设置要上传的文件路径
// let fileList: Array<string> = []
// if (event) {
// event.result.handleFileList(fileList)
// }
// return true;
// })
// .geolocationAccess(true)
// .javaScriptAccess(true)
// .javaScriptProxy({//将对角注入到web端
// object: this.testObj,
// name: 'testObjName',
// methodList: ['test'],
// controller: this.webViewController
// })
// .onGeolocationShow(event => {
// AlertDialog.show({
// title: '位置权限请求',
// message: '是否允许获取位置信息',
// primaryButton: {
// value: '同意',
// action: () => {
// event.geolocation.invoke(event.origin, true, false);
// }
// },
// secondaryButton: {
// value: '取消',
// action: () => {
// if (event) {
// event.geolocation.invoke(event.origin, false, false)
// }
// }
// },
// cancel: () => {
// if (event) {
// event.geolocation.invoke(event.origin, false, false)
// }
// }
//
// })
// })
}
.width('100%')
.height('100%')
}
}