鴻蒙學習筆記:利用鴻蒙JavaUI 框架的 WebView 加載在線網頁

語言: CN / TW / HK

theme: channing-cyan

「這是我參與2022首次更文挑戰的第39天,活動詳情查看:2022首次更文挑戰

什麼是 Webview

其實現在很多應用 App 裏都內置了 Web 網頁,比如微信、淘寶。在 Android 中就是利用 WebView 這一組件實現。WebView 是一個基於 webkit 引擎、展現 web 頁面的控件。

鴻蒙也不例外,也通過 WebView 來提供應用中集成 Web 頁面的能力。

作用: - 顯示和渲染 Web 頁面 - 直接使用 HTML文件(網絡上或本地 resources 中)作佈局 - 可和 JavaScript 交互調用

WebView 支持對網絡頁面的訪問,比如我這裏就是讀取 HarmonyOS應用開發官網,讀者當然可以自己想訪問哪個網頁就訪問自己的網頁。

WebView 使用

如果我們要加載遠程網頁,就要增加對網絡的支持。在 config.json 中寫入如下代碼:

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 組件的行為進行配置,代碼如下:

```java 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

```

background_button.xml 寫入如下代碼: ```xml

```

WebView 讀取本地頁面

將本地的 HTML 文件放在"resources/rawfile/"目錄下,在本教程中命名為 BingDwenDwen.html 。在 HarmonyOS 系統中,WebView 要訪問本地 Web 文件,需要通過DataAbility 的方式進行訪問,所以此處創建 DataAbility.java 文件,寫入如下代碼: ```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 的聲明,代碼如下:

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

至此,整個 config.json 文件內容如下:

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 的能力進行配置,示例代碼如下: ```java 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();
}

```

代碼結構如下

webview.png

然後運行一個 MataPad Pro,執行我們的代碼:

MatePad Pro.png

點擊打開在線網頁,就能看到鴻蒙開發官網:

20220217_140714.png

總結

在 App 開發中,內嵌 WebView 始終佔有着一席之地。它能以較低的成本實現 Android 、iOS 和 Web 的複用。 -- 美團技術團隊

至此,我們通過 WebView 來訪問遠程網頁和本地 HTML 都成功了,但是這僅僅是很小的一個工作。

如果大家還想繼續研究 WebView,可以自己多多探索,如果大家看完我的文章,有興趣去做出一個 APP 內置瀏覽器功能,那我的目的也就達到了。

希望更多小夥伴加入鴻蒙開發的隊伍,下一篇文章,我們再見!

參考資料: - 官方WebView案例