「这是我参与2022首次更文挑战的第39天,活动详情查看: 2022首次更文挑战

什么是 Webview

其实现在很多应用 App 里都内置了 Web 网页,比如微信、淘宝。在 Android 中就是利用 WebView 这一组件实现。WebView 是一个基于 webkit 引擎、展现 web 页面的控件。

鸿蒙也不例外,也通过 WebView 来提供应用中集成 Web 页面的能力。

  • 显示和渲染 Web 页面
  • 直接使用 HTML文件(网络上或本地 resources 中)作布局
  • 可和 JavaScript 交互调用
  • WebView 支持对网络页面的访问,比如我这里就是读取 HarmonyOS应用开发官网 ,读者当然可以自己想访问哪个网页就访问自己的网页。

    WebView 使用

    如果我们要加载远程网页,就要增加对网络的支持。在 config.json 中写入如下代码:

      "module": {
        "package": "com.yuzhou1su.webviewdemo",
        "name": ".MyApplication",
        "mainAbility": "com.yuzhou1su.webviewdemo.MainAbility",
        "deviceType": [
          "phone", "tv", "tablet"
        "reqPermissions": [
            "name": "ohos.permission.INTERNET"	// 增加网络权限
    

    在 layout 的 ability_main.xml 中创建 WebView

    在"slice/MainAbilitySlice.java"文件中通过 webview.load(String url) 方法访问具体的Web 页面,通过 WebConfig 类对 WebView 组件的行为进行配置,代码如下:

    package com.yuzhou1su.webviewdemo.slice;
    import com.yuzhou1su.webviewdemo.ResourceTable;
    import ohos.aafwk.ability.AbilitySlice;
    import ohos.aafwk.content.Intent;
    import ohos.agp.components.Button;
    import ohos.agp.components.TextField;
    import ohos.agp.components.webengine.BrowserAgent;
    import ohos.agp.components.webengine.JsMessageResult;
    import ohos.agp.components.webengine.ResourceRequest;
    import ohos.agp.components.webengine.WebAgent;
    import ohos.agp.components.webengine.WebConfig;
    import ohos.agp.components.webengine.WebView;
    import ohos.agp.utils.LayoutAlignment;
    import ohos.agp.window.dialog.ToastDialog;
    public class MainAbilitySlice extends AbilitySlice {
        private static final String URL_LOCAL = "dataability://com.yuzhou1su.webviewdemo.DataAbility/resources/rawfile/BingDwenDwen.html";
        private static final String JS_NAME = "JsCallJava";
        private WebView webview;
        private TextField urlTextField;
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            initView();
        private void initView() {
            webview = (WebView) findComponentById(ResourceTable.Id_webview);
            webview.getWebConfig().setDataAbilityPermit(true);  //这个要加上,设置 webview 支持打开本地文件
            urlTextField = (TextField) findComponentById(ResourceTable.Id_textField);
            initButton();
            configWebView();
        private void configWebView() {
            WebConfig webConfig = webview.getWebConfig();
            // 是否支持Javascript,默认值false
            webConfig.setJavaScriptPermit(true);
            webview.setWebAgent(new WebAgent() {
                @Override
                public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
                    if (request == null || request.getRequestUrl() == null) {
                        return false;
                    String url = request.getRequestUrl().toString();
                    if (url.startsWith("http:") || url.startsWith("https:")) {
                        webView.load(url);
                        return false;
                    } else {
                        return super.isNeedLoadUrl(webView, request);
            webview.setBrowserAgent(new BrowserAgent(this) {
                @Override
                public boolean onJsMessageShow(WebView webView, String url, String message, boolean isAlert, JsMessageResult result) {
                    if (isAlert) {
                        new ToastDialog(getApplicationContext()).setText(message).setAlignment(LayoutAlignment.CENTER).show();
                        result.confirm();
                        return true;
                    } else {
                        return super.onJsMessageShow(webView, url, message, isAlert, result);
            // 配置JS发来的消息处理
            webview.addJsCallback(JS_NAME, str -> {
                // 处理接收到的Js发送来的消息
                new ToastDialog(this).setText(str).setAlignment(LayoutAlignment.CENTER).show();
                // 返回给Js
                return "Js Call Java Success";
        private void initButton() {
            initLoadUrlButton();
            initLoadLocalUrlButton();
        private void initLoadLocalUrlButton() {
            Button loadLocalUrlButton = (Button) findComponentById(ResourceTable.Id_load_local_url);
            loadLocalUrlButton.setClickedListener(component -> {
                webview.load(URL_LOCAL);
        private void initLoadUrlButton() {
            Button loadUrlButton = (Button) findComponentById(ResourceTable.Id_loadUrl);
            loadUrlButton.setClickedListener(component -> {
                webview.load(urlTextField.getText());
        @Override
        public void onActive() {
            super.onActive();
        @Override
        public void onForeground(Intent intent) {
            super.onForeground(intent);
    

    background_ability_main.xml 写入如下代码:

    <?xml version="1.0" encoding="UTF-8" ?>
    <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
           ohos:shape="rectangle">
        <solid
            ohos:color="#F8F1EAEA"/>
    </shape>
    

    background_button.xml 写入如下代码:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
           ohos:shape="rectangle">
        <corners
            ohos:radius="20vp"/>
        <solid
            ohos:color="#FF46F5C3"/>
    </shape>
    

    WebView 读取本地页面

    将本地的 HTML 文件放在"resources/rawfile/"目录下,在本教程中命名为 BingDwenDwen.html 。在 HarmonyOS 系统中,WebView 要访问本地 Web 文件,需要通过DataAbility 的方式进行访问,所以此处创建 DataAbility.java 文件,写入如下代码:

    package com.yuzhou1su.webviewdemo;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import ohos.aafwk.ability.Ability;
    import ohos.aafwk.content.Intent;
    import ohos.global.resource.RawFileDescriptor;
    import ohos.utils.net.Uri;
    public class DataAbility extends Ability {
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
        @Override
        public RawFileDescriptor openRawFile(Uri uri, String mode) throws FileNotFoundException {
            if (uri == null) {
                return super.openRawFile(uri, mode);
            String path = uri.getEncodedPath();
            final int splitIndex = path.indexOf('/', 1);
            final String providerName = Uri.decode(path.substring(1, splitIndex));
            String rawFilePath = Uri.decode(path.substring(splitIndex + 1));
            RawFileDescriptor rawFileDescriptor = null;
            try {
                rawFileDescriptor = getResourceManager().getRawFileEntry(rawFilePath).openRawFileDescriptor();
            } catch (IOException e) {
                // 处理异常
            return rawFileDescriptor;
    

    然后在 "entry/src/main/config.json" 中完成 DataAbility 的声明,代码如下:

    "name": "com.yuzhou1su.webviewdemo.DataAbility", "type": "data", "uri": "dataability://com.yuzhou1su.webviewdemo.DataAbility"

    至此,整个 config.json 文件内容如下:

    "app": { "bundleName": "com.yuzhou1su.webviewdemo", "vendor": "yuzhou1su", "version": { "code": 1000000, "name": "1.0.0" "deviceConfig": {}, "module": { "package": "com.yuzhou1su.webviewdemo", "name": ".MyApplication", "mainAbility": "com.yuzhou1su.webviewdemo.MainAbility", "deviceType": [ "phone", "tv", "tablet" "reqPermissions": [ "name": "ohos.permission.INTERNET" "distro": { "deliveryWithInstall": true, "moduleName": "entry", "moduleType": "entry", "installationFree": true "abilities": [ "skills": [ "entities": [ "entity.system.home" "actions": [ "action.system.home" "orientation": "unspecified", "name": "com.yuzhou1su.webviewdemo.MainAbility", "icon": "$media:icon", "description": "$string:mainability_description", "label": "$string:entry_MainAbility", "type": "page", "launchType": "standard" "name": "com.yuzhou1su.webviewdemo.DataAbility", "type": "data", "uri": "dataability://com.yuzhou1su.webviewdemo.DataAbility"

    然后在 "slice/MainAbilitySlice.java" 中声明需要访问的文件路径,通过webview.load(String url) 方法加载本地 Web 页面,可以通过 WebConfig 类的对象对WebView 访问 DataAbility 的能力进行配置,示例代码如下:

    private static final String URL_LOCAL = "dataability://com.yuzhou1su.webviewdemo.DataAbility/resources/rawfile/BingDwenDwen.html";
        private static final String JS_NAME = "JsCallJava";
        private WebView webview;
        private TextField urlTextField;
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            initView();
    

    代码结构如下

    然后运行一个 MataPad Pro,执行我们的代码:

    点击打开在线网页,就能看到鸿蒙开发官网:

    在 App 开发中,内嵌 WebView 始终占有着一席之地。它能以较低的成本实现 Android 、iOS 和 Web 的复用。 -- 美团技术团队

    至此,我们通过 WebView 来访问远程网页和本地 HTML 都成功了,但是这仅仅是很小的一个工作。

    如果大家还想继续研究 WebView,可以自己多多探索,如果大家看完我的文章,有兴趣去做出一个 APP 内置浏览器功能,那我的目的也就达到了。

    希望更多小伙伴加入鸿蒙开发的队伍,下一篇文章,我们再见!

    参考资料: