[文章]使用WebView组件实现应用与Web页面间的通信

阅读量 0
0
0
1. 介绍
开发者如果需要在自己的应用中嵌入Web页面,可以通过WebView组件进行开发。WebView组件派生于通用组件Component,可以像通用组件一样使用。
本教程以应用嵌入WebView组件为例,从WebView组件构建、Web页面加载、应用与WebView中Web页面间的交互三个方面出发,让您快速了解WebView组件的基本能力及使用方法。
WebView组件能力的详细介绍可以参考开发指南WebView。

说明
  • 请使用真机或模拟器运行查看WebView效果,预览器不支持WebView显示。
  • 只有预置WebView能力的真机设备才支持WebView功能。具体请以实际设备支持情况为准。智能穿戴设备不支持WebView。

2. 搭建HarmonyOS环境 我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
  • 安装DevEco Studio,详情请参考下载和安装软件。
  • 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
    • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
    • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
  • 开发者可以参考以下链接,完成设备调试的相关配置:
    • 使用真机进行调试
    • 使用模拟器进行调试

3. 增加一个WebView组件

步骤 1 - 在"resources/base/layout/ability_main.xml"文件中创建WebView,示例代码如下:
  1. ohos:id="$+id:webview"
  2. ohos:height="match_parent"
  3. ohos:width="match_parent">
复制代码
步骤 2 - 在"slice/MainAbilitySlice.java"文件中通过如下方式获取WebView对象,示例代码如下:
  1. WebView webview = (WebView) findComponentById(ResourceTable.Id_webview);
复制代码
—- 结束

4. 通过WebView加载Web页面 WebView加载页面分为加载Web页面和加载本地Web页面两种情况,接下来我们将分别进行介绍。
  • WebView加载网络Web页面
    在entry/src/main/config.json中申请网络权限ohos.permission.INTERNET,示例代码如下:
    1. module": {
    2. ......
    3. "reqPermissions": [
    4. {
    5. "name": "ohos.permission.INTERNET"
    6. }
    7. ]
    8. }
    复制代码
    在"slice/MainAbilitySlice.java"文件中通过webview.load(String url)方法访问具体的Web页面,通过WebConfig类对WebView组件的行为进行配置,示例代码如下:
    1. WebConfig webConfig = webview.getWebConfig();
    2. // WebView加载URL,其中urlTextField为输入URL的TextField组件
    3. webview.load(urlTextField.getText());
    复制代码
    在Web页面进行链接跳转时,WebView默认会打开目标网址,通过WebAgent对象可以定制该行为,示例代码如下
    1. webview.setWebAgent(new WebAgent() {
    2. [url=home.php?mod=space&uid=2735960]@Override[/url]
    3. public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
    4. if (request == null || request.getRequestUrl() == null) {
    5. LogUtil.info(TAG,"WebAgent isNeedLoadUrl:request is null.");
    6. return false;
    7. }
    8. String url = request.getRequestUrl().toString();
    9. if (url.startsWith("http:") || url.startsWith("https:")) {
    10. webView.load(url);
    11. return false;
    12. } else {
    13. return super.isNeedLoadUrl(webView, request);
    14. }
    15. }
    16. });
    复制代码
    除此之外,WebAgent对象还提供了相关的回调函数以观测页面状态的变更,如onLoadingPage、onPageLoaded、onError等方法。WebView提供Navigator类进行历史记录的浏览和处理,通过getNavigator()方法获取该类的对象,使用canGoBack()或canGoForward()方法检查是否可以向后或向前浏览,使用goBack()或goForward()方法向后或向前浏览,示例代码如下:
    1. Navigator navigator = webView.getNavigator();
    2. if (navigator.canGoBack()) {
    3. navigator.goBack();
    4. }
    5. if (navigator.canGoForward()) {
    6. navigator.goForward();
    7. }
    复制代码

WebView加载本地Web页面
将本地的HTML文件放在"resources/rawfile/"目录下,在本教程中命名为test.html。在HarmonyOS系统中,WebView要访问本地Web文件,需要通过DataAbility的方式进行访问,DataAbility的具体使用方法可以参考开发DataAbility。
在"entry/src/main/config.json"中完成DataAbility的声明,示例代码如下:
  1. module": {
  2. ......
  3. "abilities": [
  4. {
  5. "name": "com.huawei.codelab.DataAbility",
  6. "type": "data",
  7. "uri": "dataability://com.huawei.codelab.DataAbility"
  8. }
  9. ]
  10. }
复制代码
另外需要实现一个DataAbility,通过实现openRawFile(Uri uri, String mode)方法,完成WebView对本地Web页面的访问,示例代码如下:
  1. public class DataAbility extends Ability {
  2. ...
  3. @Override
  4. public RawFileDescriptor openRawFile(Uri uri, String mode) throws FileNotFoundException {
  5. if (uri == null) {;
  6. return super.openRawFile(uri, mode);
  7. }
  8. String path = uri.getEncodedPath();
  9. int splitIndex = path.indexOf('/', 1);
  10. String providerName = Uri.decode(path.substring(1, splitIndex));
  11. String rawFilePath = Uri.decode(path.substring(splitIndex + 1));
  12. RawFileDescriptor rawFileDescriptor = null;
  13. try {
  14. rawFileDescriptor = getResourceManager().getRawFileEntry(rawFilePath).openRawFileDescriptor();
  15. } catch (IOException e) {
  16. // 异常处理
  17. }
  18. return rawFileDescriptor;
  19. }
  20. }
复制代码
在"slice/MainAbilitySlice.java"中声明需要访问的文件路径,通过webview.load(String url)方法加载本地Web页面,可以通过WebConfig类的对象对WebView访问DataAbility的能力进行配置,示例代码如下:
  1. private static final String URL_LOCAL = "dataability://com.huawei.codelab.DataAbility/resources/rawfile/test.html";
  2. // 配置是否支持访问DataAbility资源,默认为true
  3. webConfig.setDataAbilityPermit(true);
  4. webview.load(URL_LOCAL);
复制代码
5. 实现应用与WebView中的Web页面间的通信 本教程以本地Web页面"resources/rawfile/test.html"为例介绍如何实现应用与WebView中的Web页面间交互。
首先需要对WebConfig进行配置,使能WebView与Web页面JavaScript交互的能力,示例代码如下:
  1. // 配置是否支持JavaScript,默认值为false
  2. webConfig.setJavaScriptPermit(true);
复制代码
  • 应用调用Web页面
    在"resources/rawfile/test.html"中编写callJS方法,待应用调用,示例代码如下:
    复制代码
    在"slice/MainAbilitySlice.java"中实现应用对JavaScript的调用,示例代码如下:

    1. webview.executeJs("javascript:callJS('这是来自JavaSlice的消息')", msg -> {
    2. // 在这里处理Js的方法的返回值
    3. });
    复制代码
    我们可以通过setBrowserAgent方法设置自定义BrowserAgent对象,以观测JavaScript事件及通知等,通过复写onJsMessageShow方法来接管Web页面弹出Alert对话框的事件,示例代码如下:
    1. webview.setBrowserAgent(new BrowserAgent(this) {
    2. @Override
    3. public boolean onJsMessageShow(WebView webView, String url, String message, boolean isAlert, JsMessageResult result) {
    4. LogUtil.info(TAG,"BrowserAgent onJsMessageShow : " + message);
    5. if (isAlert) {
    6. // 将Web页面的alert对话框改为ToastDialog方式提示
    7. new ToastDialog(getApplicationContext()).setText(message).setAlignment(LayoutAlignment.CENTER).show();
    8. // 对弹框进行确认处理
    9. result.confirm();
    10. return true;
    11. } else {
    12. return super.onJsMessageShow(webView, url, message, isAlert, result);
    13. }
    14. }
    15. });
    复制代码

  • Web页面使用JavaScript调用应用
    在"resources/rawfile/test.html"中编写按钮,当按钮被点击时实现JavaScript对应用的调用,示例代码如下:

    1. ......


    复制代码
    在"slice/MainAbilitySlice.java"中实现应用对JavaScript发起的调用的响应,示例代码如下:
    1. private static final String JS_NAME = "JsCallJava";
    2. webview.addJsCallback(JS_NAME, str -> {
    3. // 处理接收到的JavaScript发送来的消息,本教程通过ToastDialog提示确认收到Web页面发来的消息
    4. new ToastDialog(this).setText(str).setAlignment(LayoutAlignment.CENTER).show();
    5. // 返回给JavaScript
    6. return "Js Call Java Success";
    7. });
    复制代码

6. 恭喜你
通过本教程的学习,你已学会如何使用WebView组件。
7. 完整示例
下面我们通过一个完整的示例来看下WebV iew组件的使用。本示例可以让用户选择加载手动输入的Web URL,也可以加载本地Web页面,并实现了前进、后退及应用与Web页面交互的基本功能,实现效果如下:
5.png

  • 点击"Load URL"按钮会加载上方网址的Web页面,通过"Go Back"和"Go Forward"按钮实现Web页面间的导航。
  • 点击"Load Local HTML"按钮加载本地Web页面,点击"Send Message to Local HTML"或者Web页面中的"调用Java方法"按钮,实现应用与Web页面间的交互。
具体实现代码如下:
  • 布局与样式
    在HUAWEI DevEco Studio中创建一个Phone的Empty Feature Ability(Java)模板工程,然后在生成的布局文件"resources/base/layout/ability_main.xml"中增加如下代码:

    1. xmlns:ohos="http://schemas.huawei.com/res/ohos"
    2. ohos:height="match_parent"
    3. ohos:orientation="vertical"
    4. ohos:width="match_parent">
    5. ohos:id="$+id:textField"
    6. ohos:height="30vp"
    7. ohos:width="match_parent"
    8. ohos:left_margin="5vp"
    9. ohos:right_margin="5vp"
    10. ohos:text_alignment="vertical_center"
    11. ohos:text="https://www.huawei.com/cn/"
    12. ohos:hint="请输入网址"
    13. ohos:basement="#000099"
    14. ohos:text_size="20fp">

    15. ohos:height="510vp"
    16. ohos:width="match_parent"
    17. ohos:top_margin="5vp"
    18. ohos:background_element="$graphic:background_button"
    19. ohos:orientation="horizontal">
    20. ohos:margin="5vp"
    21. ohos:height="500vp"
    22. ohos:id="$+id:webview"
    23. ohos:width="match_parent"/>

    24. ohos:id="$+id:loadUrl"
    25. ohos:height="30vp"
    26. ohos:left_margin="5vp"
    27. ohos:right_margin="5vp"
    28. ohos:top_margin="5vp"
    29. ohos:text="Load URL"
    30. ohos:background_element="$graphic:background_button"
    31. ohos:text_size="20fp"
    32. ohos:width="match_parent">

    33. ohos:height="30vp"
    34. ohos:width="match_parent"
    35. ohos:top_margin="5vp"
    36. ohos:orientation="horizontal">
    37. ohos:id="$+id:goback"
    38. ohos:height="match_parent"
    39. ohos:width="1"
    40. ohos:left_margin="5vp"
    41. ohos:right_margin="5vp"
    42. ohos:weight="1"
    43. ohos:text="Go Back"
    44. ohos:background_element="$graphic:background_button"
    45. ohos:text_size="20fp">

    46. ohos:id="$+id:forward"
    47. ohos:height="match_parent"
    48. ohos:width="1"
    49. ohos:text="GO Forward"
    50. ohos:right_margin="5vp"
    51. ohos:left_margin="5vp"
    52. ohos:weight="1"
    53. ohos:background_element="$graphic:background_button"
    54. ohos:text_size="20fp">


    55. ohos:width="match_parent"
    56. ohos:id="$+id:load_local_url"
    57. ohos:height="30vp"
    58. ohos:text="Load Local HTML"
    59. ohos:left_margin="5vp"
    60. ohos:top_margin="5vp"
    61. ohos:right_margin="5vp"
    62. ohos:background_element="$graphic:background_button"
    63. ohos:text_size="20fp">

    64. ohos:id="$+id:callJS"
    65. ohos:height="30vp"
    66. ohos:width="match_parent"
    67. ohos:left_margin="5vp"
    68. ohos:top_margin="5vp"
    69. ohos:right_margin="5vp"
    70. ohos:text="Send Message to Local HTML"
    71. ohos:background_element="$graphic:background_button"
    72. ohos:text_size="20fp">

    复制代码
    在"resources/base/graphic/"目录下增加background_button.xml文件用来定义背景属性。


    1. ohos:shape="rectangle">
    2. ohos:radius="6vp"/>
    3. ohos:color="#e9e9e9"/>
    复制代码

  • 首页代码
    在"slice/MainAbilitySlice.java"中添加如下代码:
    1. import com.huawei.codelab.ResourceTable;

    2. import ohos.aafwk.ability.AbilitySlice;
    3. import ohos.aafwk.content.Intent;
    4. import ohos.agp.components.Button;
    5. import ohos.agp.components.TextField;
    6. import ohos.agp.components.webengine.BrowserAgent;
    7. import ohos.agp.components.webengine.JsMessageResult;
    8. import ohos.agp.components.webengine.Navigator;
    9. import ohos.agp.components.webengine.ResourceRequest;
    10. import ohos.agp.components.webengine.WebAgent;
    11. import ohos.agp.components.webengine.WebConfig;
    12. import ohos.agp.components.webengine.WebView;
    13. import ohos.agp.utils.LayoutAlignment;
    14. import ohos.agp.window.dialog.ToastDialog;

    15. public class MainAbilitySlice extends AbilitySlice {
    16. private static final String URL_LOCAL = "dataability://com.huawei.codelab.DataAbility/resources/rawfile/test.html";
    17. private static final String JS_NAME = "JsCallJava";
    18. private WebView webview;
    19. private TextField urlTextField;
    20. private Navigator navigator;

    21. @Override
    22. public void onStart(Intent intent) {
    23. super.onStart(intent);
    24. super.setUIContent(ResourceTable.Layout_ability_main);
    25. initView();
    26. }

    27. private void initView() {
    28. webview = (WebView) findComponentById(ResourceTable.Id_webview);
    29. urlTextField = (TextField) findComponentById(ResourceTable.Id_textField);
    30. navigator = webview.getNavigator();
    31. initButton();
    32. configWebView();
    33. }

    34. private void configWebView() {
    35. WebConfig webConfig = webview.getWebConfig();

    36. // 是否支持Javascript,默认值false
    37. webConfig.setJavaScriptPermit(true);
    38. webview.setWebAgent(new WebAgent() {
    39. @Override
    40. public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
    41. if (request == null || request.getRequestUrl() == null) {
    42. return false;
    43. }
    44. String url = request.getRequestUrl().toString();
    45. if (url.startsWith("http:") || url.startsWith("https:")) {
    46. webView.load(url);
    47. return false;
    48. } else {
    49. return super.isNeedLoadUrl(webView, request);
    50. }
    51. }
    52. });

    53. webview.setBrowserAgent(new BrowserAgent(this) {
    54. @Override
    55. public boolean onJsMessageShow(WebView webView, String url, String message, boolean isAlert, JsMessageResult result) {
    56. if (isAlert) {
    57. new ToastDialog(getApplicationContext()).setText(message).setAlignment(LayoutAlignment.CENTER).show();
    58. result.confirm();
    59. return true;
    60. } else {
    61. return super.onJsMessageShow(webView, url, message, isAlert, result);
    62. }
    63. }
    64. });

    65. // 配置JS发来的消息处理
    66. webview.addJsCallback(JS_NAME, str -> {
    67. // 处理接收到的Js发送来的消息
    68. new ToastDialog(this).setText(str).setAlignment(LayoutAlignment.CENTER).show();

    69. // 返回给Js
    70. return "Js Call Java Success";
    71. });
    72. }

    73. private void initButton() {
    74. initLoadUrlButton();
    75. initGoBackButton();
    76. initGoForwardButton();
    77. initLoadLocalUrlButton();
    78. initCallJsButton();
    79. }

    80. private void initCallJsButton() {
    81. Button callJs = (Button) findComponentById(ResourceTable.Id_callJS);
    82. callJs.setClickedListener(component -> {
    83. webview.executeJs("javascript:callJS('这是来自JavaSlice的消息')", msg -> {
    84. // 在这里处理Java调用Js的方法的返回值
    85. });
    86. });
    87. }

    88. private void initLoadLocalUrlButton() {
    89. Button loadLocalUrlButton = (Button) findComponentById(ResourceTable.Id_load_local_url);
    90. loadLocalUrlButton.setClickedListener(component -> {
    91. webview.load(URL_LOCAL);
    92. });
    93. }

    94. private void initLoadUrlButton() {
    95. Button loadUrlButton = (Button) findComponentById(ResourceTable.Id_loadUrl);
    96. loadUrlButton.setClickedListener(component -> {
    97. webview.load(urlTextField.getText());
    98. });
    99. }

    100. private void initGoBackButton() {
    101. Button goBackButton = (Button) findComponentById(ResourceTable.Id_goback);
    102. goBackButton.setClickedListener(component -> {
    103. if (navigator.canGoBack()) {
    104. navigator.goBack();
    105. }
    106. });
    107. }

    108. private void initGoForwardButton() {
    109. Button goForwardButton = (Button) findComponentById(ResourceTable.Id_forward);
    110. goForwardButton.setClickedListener(component -> {
    111. if (navigator.canGoForward()) {
    112. navigator.goForward();
    113. }
    114. });
    115. }

    116. @Override
    117. public void onActive() {
    118. super.onActive();
    119. }

    120. @Override
    121. public void onForeground(Intent intent) {
    122. super.onForeground(intent);
    123. }
    124. }
    复制代码

  • DataAbility实现
    创建一个DataAbility,并添加如下代码:
    1. import java.io.FileNotFoundException;
    2. import java.io.IOException;

    3. import ohos.aafwk.ability.Ability;
    4. import ohos.aafwk.content.Intent;
    5. import ohos.global.resource.RawFileDescriptor;
    6. import ohos.utils.net.Uri;

    7. public class DataAbility extends Ability {

    8. @Override
    9. public void onStart(Intent intent) {
    10. super.onStart(intent);
    11. }

    12. @Override
    13. public RawFileDescriptor openRawFile(Uri uri, String mode) throws FileNotFoundException {
    14. if (uri == null) {
    15. return super.openRawFile(uri, mode);
    16. }
    17. String path = uri.getEncodedPath();
    18. final int splitIndex = path.indexOf('/', 1);
    19. final String providerName = Uri.decode(path.substring(1, splitIndex));
    20. String rawFilePath = Uri.decode(path.substring(splitIndex + 1));
    21. RawFileDescriptor rawFileDescriptor = null;
    22. try {
    23. rawFileDescriptor = getResourceManager().getRawFileEntry(rawFilePath).openRawFileDescriptor();
    24. } catch (IOException e) {
    25. // 处理异常
    26. }
    27. return rawFileDescriptor;
    28. }
    29. }
    复制代码

  • 本地Web页面实现
    在"resources/rawfile/"目录下创建本地Web页面test.html,示例代码如下:



    1. 本地html



    2. 这是一个本地HTML页面








    复制代码

说明
以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友