# 开发web-view组件

web-view用于在元服务中嵌入网页内容，它作为一个容器，能够将网页内容直接集成到元服务的界面中，使得用户可以在不离开元服务的情况下浏览网页，为用户提供无缝的浏览体验。

## 开发准备

1. 开始开发前，请确保已完成[业务域名配置](https://developer.huawei.com/consumer/cn/doc/atomic-guides/agc-help-harmonyos-business-domain)。

2. 需要获取安装JS SDK，具体方法请参照[JS SDK](#js-sdk)。

3. 对应接口能力可参考[web-view](https://developer.huawei.com/consumer/cn/doc/atomic-ascf/components-web-view)。

## JS SDK

**获取安装**

可以通过NPM方式，将JS SDK集成到工程。

**安装方法**

在目标路径下打开cmd命令窗口，并执行以下npm命令，获得对应的js文件。

```bash
npm install @atomicservice/ascf-web-sdk
```

**使用方法**

**ES6**

```js
import has from '@atomicservice/ascf-web-sdk';

has.ascfweb.getEnv((res) => {
  console.info('getEnv success', res);
});
```

**umd**

```html
<script src="../dist/ascf-web-sdk.umd.js"></script>
<script>
  has.ascfweb.getEnv((res) => {
    console.info('getEnv success', res);
  });
</script>
```

在命令行中看到打印成功的结果，则说明已成功安装sdk，可以开发使用web-view组件。
> 说明
>
> 复制npm安装包里面的ascf-web-sdk.umd.js文件，放到项目的静态资源目录后，需要将上述示例中script的src引用的目录改为对应的路径。

**UserAgent**

使用web-view访问服务器，会在系统的UserAgent追加ASCF/Appid，用于判断是否运行在元服务ASCF框架。

**示例：**

* UserAgent格式：

  ****** ASCF/1234567890123456

  ******表示原始UserAgent内容。
* 判断是否在ASCF中打开：

  ```js
  const isAscfWebview = window.navigator.userAgent.includes('ASCF'); // true
  ```

  当isAscfWebview为true时，H5页面就已经在ASCF中成功打开了。

## ASCF元服务与web-view内嵌H5相互通信

**双向通信说明：**

* web-view内嵌H5页面通过[has.ascfweb.postMessage](https://developer.huawei.com/consumer/cn/doc/atomic-ascf/components-web-view#hasascfwebpostmessage)接口向元服务发送消息，元服务侧通过bindmessage属性绑定事件接收消息。

* 元服务通过[WebViewContext.postMessage](https://developer.huawei.com/consumer/cn/doc/atomic-ascf/apis-web-view-context#webviewcontextpostmessage)接口向web-view内嵌H5页面发消息，H5页面通过[has.ascfweb.onMessage](https://developer.huawei.com/consumer/cn/doc/atomic-ascf/components-web-view#hasascfwebonmessage)接口接收消息。

**示例：**

* 场景一：H5页面给元服务发消息

  1. 在H5页面调用JS SDK接口。

     服务端H5页面集成完JS SDK后，可以直接调用has.ascfweb.postMessage接口。

     发送实时消息需要给options属性添加{ mode: 'realtime' }配置。

     index.html：

     ```html
     <!DOCTYPE html>
     <html lang="zh-CN">

     <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>PostMessage H5</title>
       <script src="ascf-web-sdk.umd.js"></script>
     </head>

     <body>
     <h1>H5 - has.ascfweb.postMessage</h1>
     <button type="button" class="button" onclick="postMessage1();">H5 发字符串消息给元服务</button>
     <button type="button" class="button" onclick="postMessage2();">H5 发对象类型消息给元服务</button>
     </body>
     <script type="text/javascript">
       // 发送string类型消息
       function postMessage1() {
         has.ascfweb.postMessage({
           data: 'H5 string to Js',
           options: { mode: 'realtime' },
           success: () => {
             console.info('postMessage success');
           },
           fail: (err) => {
             console.error('postMessage fail:', err.message);
           },
           complete: (res) => {
             console.info('postMessage complete:', res);
           }
         });
       }

       // 发送对象类型消息
       function postMessage2() {
         has.ascfweb.postMessage({
           data: { name: 'H5 object to Js' },
           options: { mode: 'realtime' },
           success: () => {
             console.info('postMessage success');
           },
           fail: (err) => {
             console.error('postMessage fail:', err.message);
           },
           complete: (res) => {
             console.info('postMessage complete:', res);
           }
         });
       }
     </script>
     </html>
     ```

  2. 在hxml文件中，加载H5页面。

     通过web-view组件指定对应url加载服务端的H5页面，给bindmessage属性绑定接收消息的回调函数。

     xxx.hxml：

     ```html
     <web-view src="{{ url }}" bindmessage="onWebviewMessage"></web-view>
     ```

  3. 在js文件中，处理H5发过来的消息。

     xxx.js：

     ```js
     Page({
       data: {
         url: 'http://www.example.com/example.html' // 此处仅为样例，请开发者更换为可用网络地址
       },

       onWebviewMessage(e) {
         // 接收H5页面发过来的消息
         console.info('onWebviewMessage:', e.detail);
       }
     });
     ```

* 场景二：元服务给H5页面发消息

  1. 在H5页面调用JS SDK接口。

     服务端H5页面集成完JS SDK后，可以直接调用has.ascfweb.onMessage接口。通过onMessage来接收消息。

     index.html：

     ```html
     <!DOCTYPE html>
     <html lang="zh-CN">

     <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>PostMessage H5</title>
       <script src="ascf-web-sdk.umd.js"></script>
     </head>

     <body>
     <h1>H5 - has.ascfweb.onMessage</h1>
     </body>
     <script type="text/javascript">
       // 监听JS发过来的消息
       has.ascfweb.onMessage((data) => {
         console.info('onMessage H5收到来自元服务的消息:', data);
       });
     </script>
     </html>
     ```

  2. 在hxml文件中，加载H5页面。

     通过web-view组件指定对应url加载服务端的H5页面。

     xxx.hxml：

     ```html
     <view class="menu-list">
       <view class="web-view-class">
         <web-view src="{{ url }}" bindmessage="onWebviewMessage" class="web-view-class"></web-view>
       </view>
       <button bindtap="sendString" type="primary">发送字符串</button>
       <button bindtap="sendSimpleObject" type="primary">发送简单对象消息</button>
     </view>
     ```

     xxx.css：

     ```css
     .web-view-class {
       height: 400px;
     }

     .menu-list {
       display: flex;
       flex-direction: column;
       align-items: flex-start;
       gap: 12px;
       padding: 16px;
     }
     ```

  3. 在js文件中，发送消息给H5页面。

     使用has.createWebViewContext()方法获取web-view组件控制实例，通过实例的postMessage方法发送消息。

     xxx.js：

     ```js
     Page({
       data: {
         url: 'http://www.example.com/example.html' // 此处仅为样例，请开发者更换为可用网络地址
       },

       sendString() {
         // 发字符串消息给H5页面
         const ctx = has.createWebViewContext();
         ctx.postMessage({
           data: 'Js string message to H5',
           success: () => {
             console.info('postMessage success');
           },
           fail: (err) => {
             console.error('postMessage fail:', err);
           },
           complete: (res) => {
             console.info('postMessage complete:', res);
           }
         });
       },

       sendSimpleObject() {
         // 发对象消息给H5页面
         const ctx = has.createWebViewContext();
         ctx.postMessage({
           data: {
             msg: 'JS object message to H5',
             version: '1.0'
           },
           success: () => {
            console.info('postMessage success');
           },
           fail: (err) => {
             console.error('postMessage fail:', err);
           },
           complete: (res) => {
             console.info('postMessage complete:', res);
           }
         });
       }
     });
     ```

