c
import webView from '@ohos.web.webview';
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';
@Component
export struct WebViewComponent {
webviewController: webView.WebviewController = new webView.WebviewController();
// 页面 loading
isLoading: boolean = true
// 链接
@Prop @Require url: string = 'https://blog.csdn.net/survivorsfyh'
// 声明注册JS侧调用鸿蒙侧交互对象
private webCallApp: WebCallApp = new WebCallApp(this.webviewController)
// 与JS端约定的交互协议名Key
private proxyName:string = 'Harmony'
onBackPress(): boolean | void { // Web 组件左滑手势返回处理
if (this.webviewController.accessStep(-1)) {
// 返回上一层级
this.webviewController.backward()
// 执行自定义逻辑
return true
} else { // 执行系统默认返回逻辑
return false
}
}
webDebugMethod(): void {
try {
// 启用网页调试功能
webView.WebviewController.setWebDebuggingAccess(true);
} catch (error) {
let e: BusinessError = error as BusinessError;
console.log(`[Web] ****** Error Code: ${e.code}, Message: ${e.message}`);
this.webviewController.refresh(); // 页面异常,刷新
}
}
aboutToDisappear(): void {
// javaScriptProxy接口需要和deleteJavaScriptRegister接口配合使用,防止内存泄漏。
this.webviewController.deleteJavaScriptRegister(this.proxyName)
}
build() {
if (this.url) {
Column(){
Button('runJavaScript方法调用js方法')
.onClick(() => {
if (this.webviewController) {
/**
* 1.注意:传参时要注意一个问题,就是这里的调用这个方法,是直接写字符串去调用.
* 但是如果要在调用方法里边传参,且正好是个字符串,就需要区分双引号和单引号,
* 保证对runJavaScript穿的方法收尾对应的是一组符号,而方法内部传参对应的是一组符号,
* 示范如下:
* 2."changeMessage"是一个定义在JS端,参数入参为一个字符串的函数方法.
* */
this.webviewController.runJavaScript('changeMessage("调用h5方法成功")')
}
})
Button('鸿蒙调用js,传递js代码块,修改颜色字体')
.onClick(() => {
// 传递runJavaScript侧代码方法,也可以像这样直接将整个JS方法体传递过去以达到我们修改颜色的目的.
this.webviewController.runJavaScript(`function changeColor(){document.getElementById('text').style.color = 'red'}`);
})
/// 白屏情况可能是权限导致,把权限全部开启,例如本地存储或者 http & https
Web({ src: this.url, controller: this.webviewController })
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.multiWindowAccess(true)
.javaScriptAccess(true)// 访问本地资源文件
.imageAccess(true)// 权限状态开启
.onlineImageAccess(true)// 权限状态开启
.fileAccess(true)// 权限状态开启
.domStorageAccess(true)// 数据存储权限
.mediaPlayGestureAccess(true)// 媒体权限
.mixedMode(MixedMode.All)// https 加载
.layoutMode(WebLayoutMode.FIT_CONTENT)// 自适应布局
.verticalScrollBarAccess(true)// 滚动条
.horizontalScrollBarAccess(false)// 滚动条
.cacheMode(CacheMode.Default)// 缓存
.zoomAccess(false)// 禁止手势缩放
.geolocationAccess(true)// 定位权限
.onConsole((event) => {
console.log('[交互] - onConsole')
console.info(event?.message.getMessage())
return false
})
.onPageBegin(() => { // 页面加载中
console.log('[Web] - 页面加载中:', this.url)
})
.onPageEnd(() => { // 页面加载完成
console.log('[Web] - 页面加载完成:', this.url)
this.isLoading = false
})
.onErrorReceive((event) => { // 异常: 无网络,页面加载错误时
if (event) {
console.info('getErrorInfo:' + event.error.getErrorInfo());
console.info('getErrorCode:' + event.error.getErrorCode());
console.info('url:' + event.request.getRequestUrl());
console.info('isMainFrame:' + event.request.isMainFrame());
console.info('isRedirect:' + event.request.isRedirect());
console.info('isRequestGesture:' + event.request.isRequestGesture());
console.info('getRequestHeader_headerKey:' + event.request.getRequestHeader().toString());
let result = event.request.getRequestHeader();
console.info('The request header result size is ' + result.length);
for (let i of result) {
console.info('The request header key is : ' + i.headerKey + ', value is : ' + i.headerValue);
}
}
})
.onHttpErrorReceive((event) => { // 异常: 网页加载资源 Http code >= 400 时
if (event) {
console.info('url:' + event.request.getRequestUrl());
console.info('isMainFrame:' + event.request.isMainFrame());
console.info('isRedirect:' + event.request.isRedirect());
console.info('isRequestGesture:' + event.request.isRequestGesture());
console.info('getResponseData:' + event.response.getResponseData());
console.info('getResponseEncoding:' + event.response.getResponseEncoding());
console.info('getResponseMimeType:' + event.response.getResponseMimeType());
console.info('getResponseCode:' + event.response.getResponseCode());
console.info('getReasonMessage:' + event.response.getReasonMessage());
let result = event.request.getRequestHeader();
console.info('The request header result size is ' + result.length);
for (let i of result) {
console.info('The request header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);
}
let resph = event.response.getResponseHeader();
console.info('The response header result size is ' + resph.length);
for (let i of resph) {
console.info('The response header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);
}
}
})
.onAlert((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true;
})
.onConfirm((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true
})
.onShowFileSelector((event) => { // 文件选择处理
console.log('MyFileUploader onShowFileSelector invoked');
const documentSelectOptions = new picker.PhotoSelectOptions();
let uri: string | null = null;
const documentViewPicker = new picker.PhotoViewPicker();
documentViewPicker.select(documentSelectOptions).then((documentSelectResult) => {
uri = documentSelectResult[0];
console.info('documentViewPicker.select to file succeed and uri is:' + uri);
if (event) {
event.result.handleFileList([uri]);
}
}).catch((err: BusinessError) => {
console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
return true
})
.onLoadIntercept((event) => {
if (event.data.isRedirect()) {
console.log('[重定向]');
}
return false
})
/// JS调用ArkTS,web组件初始化调用
/*
* 将javaScriptProxy中的ArkTS对象注册到Web组件中,该对象将使用JavaScriptProxy中指定的名称注册到网页的所有框架中
* 这使得JavaScript可以调用javaScriptProxy中ArkTS对象的方法。
* */
.javaScriptProxy({
//将交互对象注入web
object: this.webCallApp,
//与JS端的交互协议Key
name: this.proxyName,
// 基于 object 的 WebCallApp 中交互具体实现的若干函数方法
// 交互对象中所涵盖的方法,支持多个.JS调用鸿蒙App端的方法,最终方法会在交互对象定义的方法中触发
methodList: WebCallApp.methodList,
// 参与注册的应用侧JavaScript对象的异步方法。但是异步方法无法获取返回值。
asyncMethodList:WebCallApp.asyncMethodList,
controller: this.webviewController
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Start)
} else {
// 加载异常,请重试
}
}
}
/**
* javaScriptProxy和registerJavaScriptProxy异同
*
* 相同点:二者都可以注入JavaScript对象到window对象中,并在window对象中调用该对象的方法.
*
* 不同点:
* 1.从注册对象的角度来看,前者仅支持注册一个对象,而后者支持注册多个对象。
* 2.从生命周期上讲,javaScriptProxy在Web组件初始化调用,registerJavaScriptProxy在Web组件初始化完成后调用。
* 3.从接口角度来看,javaScriptProxy是Web组件的方法,而registerJavaScriptProxy是WebviewController的方法。
* */
class WebCallApp {
private controller: webView.WebviewController;
constructor(controller: WebviewController) {
this.controller = controller
}
/// JS调用ArkTS 同步方法数组,包含同步方法的方法名.
static methodList:string[] = [
'WebCallApp',
]
static asyncMethodList:string[] = [
'WebTestAsync',
'WebTest',
]
WebCallApp(value: string) {
}
async WebTestAsync(value: string):Promise<string>{
return '测试 - 异步'
}
WebTest(value: string): Promise<string> { // 测试 - promise
return new Promise((resolve, reject) => {
try {
resolve('[Callback]:你好')
} catch (e) {
reject('[Callback]:异常')
}
})
}
}
修改问题:避免web不适配,需要做下面修改
