鸿蒙星空的太白星 | WebView给元服务调用JS API指明方向
阅读原文时间:2023年08月15日阅读:1

​漆黑深夜夜凉如水,繁星盛开于无垠苍穹。清风徐来,一片薄云,夜空顿然失色,有些阴霾。天空中最亮的星,太白星,在薄云中依然闪耀,如同海上迷雾中的灯塔,为迷失方向的船只指明方向。

元服务是华为提供的一种面向未来的服务形态,具有独立入口和免安装等特性,支持运行在1+8+N设备上。在万物互联时代,提供了更丰富的入口、更智能的分发、更高效的转化,助力开发者快速抢占流量入口。

景区类型的元服务如果实现一键购票、游览路线推荐、智慧导览、智慧商店等,将大大提升旅客的兴致来自主游览。开发此类元服务过程中通常需要用到地图功能,例如在景区类型元服务的卡片中显示我的位置信息,通过推荐路线提供景区最佳游览路线。通常思路是PageAbility打开自定义地图,查询地图信息(POI)点,做路径规划、路径推荐等。通过卡片中内置导航功能,在景区内帮用户贴心的避开人从众。

想法是美好的,现实是骨感的。查阅了高德、百度、华为、腾讯地图能力的后发现,各大厂商对鸿蒙系统的支持能力参差不齐,都没有提供鸿蒙可用的SDK。商用APP的主体页面通常都是JS类的WEB页面,于是一直琢磨如何使用JS API的方式。最初的思路被局限在通过鸿蒙的JS集成地图的JS API来实现,但是最终被各种报错而折磨不堪。秉着只要思想不滑坡,方法总比问题多,冥冥中看到了鸿蒙漆黑星空中那颗最亮的星,Java UI组件之太白星WebView。

WebView组件灯塔般的星光一闪,解决问题的思路灵感乍现。立刻想到了JS类WEB页面通过startAbility跳转到mapAbility,来实现JS页面跳转到Java页面的逻辑。在mapAbility中开发地图页面,妙用Java UI框架中的Webview组件来加载本地Html文件,即可使用Html调用地图JS API接口。

敲黑板,画重点,关键几步听我娓娓道来。

1.准备地图的key。

参考地图厂商的JS API开发指导,申请地图的key,这里以高德地图为例说明。

2.完成WebView组件的初始化。

请认真参考WebView组件文档完成,千万不要跳过。

其中最关键的就是配置应用的网络权限,如果网络权限不对,还想调通JS API,那就等于是奢望。

打开“entry > src > main > config.json”文件,添加如下配置。

"module": {

"reqPermissions": [

  {

    "name": "ohos.permission.INTERNET"

  }]

}

3.新建资源文件。

“资源类型”请选择“Layout”。

布局文件内容中定义地图组件。

示例代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
        <ohos.agp.components.webengine.WebView
            ohos:id="$+id:ability_main_webview"
            ohos:height="600vp"
            ohos:width="match_parent"
            ohos:weight="1"/>
        <Text
            ohos:height="150vp"
            ohos:width="match_parent"
            ohos:text="hello map">
        </Text>
</DirectionalLayout>

4.针对JS类Web开发范式开发的主体页面,使用startAbility跳转到mapAbility,实现从JS页面跳转到Java页面。

说明开发UI的程序员习惯用JS,所以主体页面通常都是JS的。WebView组件是Java的,所以需要从JS页面跳转到Java页面。

新建mapAbility

示例代码如下:

Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
        .withBundleName("com.huawei.testjsmap.hmservice")
        .withAbilityName("com.huawei.testjsmap.mapAbility")
        .build();
intent.setOperation(operation);
startAbility(intent);

5.在mapAbility中开发地图页面,Webview加载本地Html文件来调用地图JS API接口。

说明:Java代码开发请参考Java UI框架文档

在资源文件“resources/rawfile”目录下增加map.html文件,参考地图JS开发指导编写Html文件。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>创建地图</title>
</head>
<script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=准备工作中申请的地图KEY"></script>
<style type="text/css">
    html,
    body {
        height: 100%;
        margin: 0px;
        padding: 0px;
    }
    #container {
        width: 100%;
        height: 100%;
    }
</style>
<body onload="initMap()">
<div id="container"></div>
<script type="text/javascript">
        function initMap() {
            var center = new TMap.LatLng(39.984104, 116.307503);
            //初始化地图
            var map = new TMap.Map("container", {
                rotation: 20,//设置地图旋转角度
                pitch:30, //设置俯仰角度(0~45)
                zoom:12,//设置地图缩放级别
                center: center//设置地图中心点坐标
            });
        }
    </script>
</body>
</html>

mapAbilityonstart方法中直接通过mapview.load打开一个拼装的URI地址: webView.load("https://example.com/rawfile/map.html");

至此问题的迷雾已破开,薄云消散,原本有些阴霾的苍穹,星光璀璨。鸿蒙星空恍若一个巨大的舞台,星有多大,舞台就有多大。剩下的要在元服务中实现哪些业务就看对应地图厂商JS API能力了。

一颗“彩蛋”流星划破天空。

“彩蛋”流星之本地调试技巧:

webAgent中通过复写processResourceRequest的方式实现本地文件加载,这种方式可以直接通过IDE工具打开Html页面进行调试,调试JS API的效率大大提升。

示例代码如下:

public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_map_main);
    WebView webView = (WebView) findComponentById(ResourceTable.Id_ability_main_webview);
    webView.getWebConfig().setJavaScriptPermit(true);
    webView.setWebAgent(new WebAgent() {
        @Override
        public ResourceResponse processResourceRequest(WebView webview, ResourceRequest request) {
            final String authority = "example.com";
            final String rawFile = "/rawfile/";
            Uri requestUri = request.getRequestUrl();
            if (authority.equals(requestUri.getDecodedAuthority())) {
                String path = requestUri.getDecodedPath();
                if (TextTool.isNullOrEmpty(path)) {
                    return super.processResourceRequest(webview, request);
                }
                if (path.startsWith(rawFile)) {
                    // 根据自定义规则访问资源文件
                    String rawFilePath = "entry/resources/rawfile/" + path.replace(rawFile, "");
                    String mimeType = URLConnection.guessContentTypeFromName(rawFilePath);
                    try {
                        Resource resource = getResourceManager().getRawFileEntry(rawFilePath).openRawFile();
                        ResourceResponse response = new ResourceResponse(mimeType, resource, null);
                        return response;
                    } catch (IOException e) {
                        HiLog.info(TAG, "open raw file failed");
                    }
                }
            }
            return super.processResourceRequest(webview, request);
        }
    });
    webView.load("https://example.com/rawfile/map.html");
}