Harmonyos之加载本地web页面

本地文件存放位置

resources资源文件下的rawfile目录

第一种是放在src\main\resources\rawfile文件夹下,在ets文件中通过$rawfile('文件名')访问
在这里插入图片描述

Web({ src: $rawfile('test.html'), controller: this.controller})

resources资源文件下的自定义目录

我们也可以把h5文件访问到src\main\resources\目录下的自定目录

在这里插入图片描述
加载方式:

// 获取本地h5的资源路径,可以凭借h5链接需要的参数
  @State url: string = "file://" + getContext().resourceDir + "/uatfile/index.html#/"+"?accessToken="+this.acct+"&userName="+this.user_name

Web({ src: '', controller: this.controller })
        .onlineImageAccess(true)
        .imageAccess(true)
        .darkMode(this.mode)
        .domStorageAccess(true)//开启文档对象模型存储接口
        .javaScriptAccess(true)//允许执行JavaScript脚本
        .javaScriptProxy({
          object: new HippiusBridge(this.controller),
          name: "xxxx",
          methodList: ["postMessage"],
          controller: this.controller
        })
        .fileAccess(true)//开启应用中文件系统的访问
        .mixedMode(MixedMode.All)//允许加载超文本传输协议(HTTP)和超文本传输安全协议(HTTPS)混合内容
        .focusOnTouch(false)
        .metaViewport(true)//设置meta标签的viewport属性是否可用
        .onControllerAttached(() => {
          //当Controller成功绑定到Web组件时触发该回调
          // 推荐在此loadUrl、设置自定义用户代理、注入JS对象等
          if (this.url) {
            console.info('[ ~~ mwebview onControllerAttached~~  ]  : ' +this.url.toString());
            this.controller.setPathAllowingUniversalAccess([
              getContext().resourceDir,
              getContext().resourceDir+"/uatfile"
            ])

            try {
              let userAgent = this.controller.getUserAgent() + this.customUserAgent;
              this.controller.setCustomUserAgent(userAgent)
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }

            this.controller.loadUrl(this.url)

          }
          this.initBridge()

        })
        .onOverrideUrlLoading((webResourceRequest: WebResourceRequest) => {
          //当空白页则拦截 加载自定义空白页面
          if (webResourceRequest && webResourceRequest.getRequestUrl() == "about:blank") {
            return true;
          }
          return false;
        })
        .onPageBegin((event) => {
          if (event) {
            console.log('onPageBegin url:' + event.url);
          }
        })
        .onLoadIntercept((event) => {
          // 通过url检测是否点击打电话
          if (event.data.getRequestUrl().startsWith('tel')) {
            this.pushTelPage(event.data.getRequestUrl())
          }
          return false
        })
        .onProgressChange((event) => {
          if (event) {
            console.log('newProgress:' + event.newProgress);
          }
        })
        .onPageEnd((event) => {
          // 推荐在此事件中执行JavaScript脚本
          if (event) {
            console.log('onPageEnd url:' + event.url);
          }
        })
        .geolocationAccess(true)

Native和H5的交互

通过端口通信技术

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

Native代码

创建通道:

ports: webview.WebMessagePort[] = [];
// 1、创建两个消息端口。
            this.ports = this.controller.createWebMessagePorts();

在Native侧消息端口(如端口1)注册 回调事件:

// 2、在应用侧的消息端口(如端口1)上注册回调事件。
            this.ports[1].onMessageEvent((result: webview.WebMessage) => {
 // 注册回调事件, 监听H5发送过来的消息
 // type WebMessage = ArrayBuffer | string;
 // result代表h5传递过来的结果,支持上述类型的数据
 })

将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。

// 创建web控制器方法
controller: webview.WebviewController = new webview.WebviewController();

 this.controller.postMessage('__init_port__', [this.ports[0]], '*');

使用Native的端口给传递给h5的端口发送消息:

// 发送消息给H5
this.ports[1].postMessageEvent(this.sendFromEts);

H5代码

监听window上的message方法,接受Native传递过来的端口:

var h5Port;
window.addEventListener('message', function (event) {
// 接收端
        if (event.data === '__init_port__') {
            if (event.ports[0] !== null) {
                h5Port = event.ports[0]; // 1. 保存从应用侧发送过来的端口。
                h5Port.onmessage = function (event) {
                 //  onmessage 方法是监听Native端发过来的消息
                }
            }
        }
    })

h5段通过端口给Native发送消息:

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

h5调用Native方法(对象注册)

javaScriptProxy(Native注册对象)

在Web组件初始化的时候调用javaScriptProxy()方法,给h5注册对象

注入JavaScript对象到window对象中,并在window对象中调用该对象的方法所有参数不支持更新。注册对象时,同步与异步方法列表请至少选择一项不为空,可同时注册两类方法。同一方法在同步与异步列表中重复注册,将默认异步调用

创建一个注册的类

class testClass {
  constructor() {
  }

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

注册对象:

class testClass {
  constructor() {
  }

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

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



// 将对象注入到web端
        .javaScriptProxy({
          object: this.testObj, // 需要注册的对象
          name: "testObjName",// windows对象上的对象
          methodList: ["test"],// 注册对象中的方法列表
          controller: this.webviewController,
          // 可选参数
          asyncMethodList: [],
          permission: ''
        })

registerJavaScriptProxy(Native注册对象)

在Web组件初始化完成后调用registerJavaScriptProxy()方法来注册

// 这个是在组件加载完成后, 你可以在生命周期方法中
this.webviewController.registerJavaScriptProxy(this.testObj, "testObjName", ["test", "toString"],
                    // 可选参数, asyncMethodList
                    [],
                    // 可选参数, permission
                    '')


使用registerJavaScriptProxy()接口注册方法时,注册后需调用refresh()接口生效。

deleteJavaScriptRegister(Native删除注册对象)

上述两种方式都需要和deleteJavaScriptRegister方法来配合使用, 防止内存泄漏。

try {
            this.webviewController.deleteJavaScriptRegister("testObjName");
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }

h5端调用注册对象的方法

// 直接获取Native注册到windows的对象testObjName, 然后调用其方法
let str = testObjName.test();

Native调用H5的方法

H5侧代码

// 调用有参函数时实现。
function htmlTest(param) {
     // 有参数数实现方法
}
// 调用无参函数时实现。
function htmlTest() {
	// 无参函数实现方法     
}
//上述方法前面实际省略了windwos. , 这个两个方法中实际上住注册在window对象中的。

Native侧

// 前端页面函数无参时,将param删除。
this.webviewController.runJavaScript('htmlTest(param)');

在实际开发过程中我们其实可以灵活实现, 我们在H5可把回调方法传递给Native侧, 然后Native侧得到结果之后再调用回调方法。

// 获取app版本信息
      window.getAppInfoSuccess = this.getOhosAppVersion.bind(this);
      const dict = {
        'className': 'AppVersionBridgePlugin',
        'function': 'getVersionNumber',
        'successCallBack': 'getAppInfoSuccess',
        'failureCallBack': '',
      };
      
// Native侧注册一个公共对象HandBridge, 然后该对象中有一个公共方法,postMessage, 前端统一调用该对象的这个方法, Native收到这个对象在去分发到每个具体的功能实现类中
HandBridge.postMessage(JSON.stringify(dict))

HandBridge方法实现:

 postMessage(data: string) {
    if (data) {
      let obj = JSON.parse(data) as object //获取js传递过来的数据
      if (obj) {
        let className = obj["className"] as string
        let functionName = obj["function"] as string
        let params = obj["params"] as object
        let successCallBack = obj["successCallBack"] as string
        let failCallBack = obj["failureCallBack"] as string
        let callbackContext =
          new CallbackContext(successCallBack, failCallBack, this.controller)
        if (this.plugins.get(className)) {
          //调用原生方法
          this.exec(this.plugins.get(className), functionName, params, callbackContext)
          return
        }
        import(`../plugin/${className}`).then((ns: ESObject) => {
          let classObj: ESObject = new ns[className](); // 实例化
          if (classObj instanceof HippiusPlugin) {
            this.plugins.set(className, classObj)
            this.exec(classObj, functionName, params, callbackContext)
          }
        })
      }
    }
  }

  private exec(plugin: HippiusPlugin, action: string, params: ESObject, callback: CallbackContext) {
    if (plugin) {
      plugin.execute(action, params, callback)
    }
  }

CallbackContext类实现:

export class CallbackContext {
  static readonly TAG = 'CallbackContext'
  mSuccess: string
  mError: string
  controller: webview.WebviewController

  constructor(mSuccess: string, mError: string, controller: webview.WebviewController) {
    this.mSuccess = mSuccess
    this.mError = mError
    this.controller = controller
  }

  public onSuccess(args: string) {
    this.toJS(this.mSuccess, args)
  }

  public onError(args: string) {
    this.toJS(this.mError, args)
  }

  private toJS(fun: string, args: string) {
    if (args) {
      args = args.replace("'", "\\'")
    }
    let js = `${fun}('${args}')`
    if (this.controller) {
      this.controller.runJavaScript(js)
    }
  }
}

参考链接

更多Native和H5交互资料参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-use-frontend-page-js

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值