乐于分享
好东西不私藏

UniApp 集成 OpenLayers 加载天地图 (Web-view双向通信方案)

本文最后更新于2026-03-13,某些文章具有时效性,若有错误或已失效,请在下方留言或联系老夜

UniApp 集成 OpenLayers 加载天地图 (Web-view双向通信方案)

1. 核心思路概述

由于 UniApp 的 小程序、App 端(Android/iOS)原生环境不存在 DOM 树,无法直接运行依赖 DOM 操作的 OpenLayers 库。本方案采用 web-view 组件作为容器,加载独立的 H5 页面来渲染地图,并通过uni.webview 桥接协议实现 H5 与 Native App 之间的双向通信(消息传递、方法调用)。

即:所有与地图相关的业务全写在h5页面,如有控权等需求就可通过双向通信拿到权限标识后,在h5页面单独处理。

注:以下代码在app端测试成功,其余端未测试

2. 前置准备

需下载官方桥接库 uni.webview.1.5.6.js 并置于项目静态资源目录(如 /static/dist_uni.webview.1.5.6.js),以便 H5 页面调用原生能力。

# 下载地址https://gitcode.com/dcloud/uni-app/blob/dev/dist/uni.webview.1.5.6.js

3. H5 地图页面实现 (map-view.html)

该文件为纯 H5 环境,负责地图渲染及与 App 端的交互逻辑。!!!一定记得修改天地图key,否者是白屏!!! 没有的上官网免费创建一个

<!DOCTYPE html><htmllang="zh-CN"><head>    <metacharset="UTF-8">    <!-- 视口配置:禁止用户缩放,确保地图容器尺寸与设备屏幕严格匹配,防止地图控件错位 -->    <metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">    <title>天地图</title>    <!-- 引入 OpenLayers 样式表 (CDN) -->    <linkrel="stylesheet"href="https://cdn.jsdelivr.net/npm/ol@v10.2.1/ol.css">    <style>        /* 全局样式重置:移除默认边距,确保占满全屏 */        bodyhtml { margin0padding0width100%height100%overflow: hidden; }        /* 地图容器:绝对定位覆盖全屏,作为 OpenLayers 的挂载点 */        #map { width100%height100%position: absolute; left0top0; }        /* 业务容器:相对定位,用于承载地图和浮层按钮 */        .view-map-container {          width100%;          height100%;          position: relative;        }        /* 模拟业务浮层:绝对定位于顶部,演示 H5 内部 UI 与地图的层级关系 */        .map-btn {          position: absolute;          top0;          left50%;          transformtranslateX(-50%);          /* 实际开发中需注意 z-index 以避免遮挡地图操作 */        }    </style></head><body>    <divclass="view-map-container">      <!-- OpenLayers 地图挂载节点 -->      <divid="map"></div>      <!-- 交互测试区域:触发 H5 向 App 发送消息 -->      <buttonclass="map-btn"onclick="handleClick()">发送消息给app</button>    </div>    <!-- 1. 引入 UniApp Webview 桥接库 (本地路径,需提前下载) -->    <scriptsrc="./dist_uni.webview.1.5.6.js"></script>    <!-- 2. 引入 OpenLayers 核心库 (CDN) -->    <scriptsrc="https://cdn.jsdelivr.net/npm/ol@v10.2.1/dist/ol.js"></script>    <script>        /**         * 【通信方向:App -> H5】         * 定义全局回调方法 getToken,供 App 端通过 evalJS 调用。         * 用于接收 App 传递的业务数据(如 Token、坐标等)。         */        window.getToken = function(token) {           console.log("📩 收到 uniapp 传来的 token:" + token);           // 此处可执行后续业务逻辑,如利用 token 请求受保护的地图服务        }        /**         * 【通信方向:H5 -> App】         * 处理按钮点击事件,向 App 端发送消息。         * 包含兼容性检查:在非 UniApp 环境(如普通浏览器)下不执行发送,防止报错。         */        function handleClick() {           if (window.uni && window.uni.postMessage) {             // 发送结构化数据:action 标识动作类型,params 携带具体参数             window.uni.postMessage({               data: {                 action'scanCode'// 通知 App 执行扫码或其他原生能力                 params: { type'qr' }               }             });           } else {             console.log('当前不在 UniApp 环境中,无法调用原生');             // Fallback 逻辑:开发调试时可在此处模拟返回结果           }        }        // 【配置项】天地图 API Key (TK)        const TK = '????????????';        localStorage.setItem("tdt-key"TK);        // 检查 OpenLayers 库是否加载成功,防止异步加载导致的初始化失败        if (!window.ol) {            console.error('OpenLayers 未加载');        } else {            initMap();        }        /**         * 地图初始化核心函数         */        function initMap() {            const ol = window.ol;            const imgUrl = `https://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${TK}`;            const labelUrl = `https://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${TK}`;            const imgSource = new ol.source.XYZ({                url: imgUrl,                wrapXfalse,                maxZoom18,                minZoom1            });            // 2. 创建注记数据源            const labelSource = new ol.source.XYZ({                url: labelUrl,                wrapXfalse,                maxZoom18,                minZoom1            });            // 3. 创建图层对象            const imgLayer = new ol.layer.Tile({ source: imgSource });            const labelLayer = new ol.layer.Tile({ source: labelSource });            // 4. 初始化地图实例            const map = new ol.Map({                target'map'// 绑定 DOM 节点 ID                layers: [imgLayer, labelLayer], // 叠加影像与注记图层                viewnew ol.View({                    // 坐标转换:将经纬度 [116.4074, 39.9042] 转换为 EPSG:3857 (Web Mercator)                    center: ol.proj.fromLonLat([116.407439.9042]),                    zoom12,                    minZoom1,                    maxZoom18                }),            });            console.log('✅ 天地图加载成功 (XYZ 模式)');            /**             * 【生命周期监听】             * 监听 UniApp JSBridge 就绪事件,确保桥接通道已建立后再进行通信。             */            document.addEventListener('UniAppJSBridgeReady'function() {              // 获取当前运行环境信息 (App/H5/小程序等)              uni.webView.getEnv(function(res) {                console.log('当前环境:' + JSON.stringify(res));              });              // 主动发送初始化完成消息给 App 端              uni.postMessage({                  data: {                      action'message' // 告知 App 地图已就绪                  }              });            });        }    </script></body></html>

4. UniApp 宿主页面实现

该文件为 .vue 组件,负责嵌入 H5 页面,接收 H5 消息及反向调用 H5 方法。

<template>  <viewclass="page-index-container">      <web-view        :src="webViewUrl"        @message="handleMessage"      ></web-view>  </view></template><scriptsetup>import { ref, getCurrentInstance, reactive } from 'vue';import { onLoad, onReady } from '@dcloudio/uni-app';let wv = null// 存储原生的 Webview 实例对象,用于高级控制const instance = getCurrentInstance();const webViewUrl = ref('/static/map/map-view.html');/** * 页面渲染完成后执行 */onReady(function() {  // 仅在 App 端执行以下原生操作  if (!instance) {  		console.error('无法获取组件实例');  		return;   }  const proxy = instance.proxy;  if (!proxy || !proxy.$scope) {    console.error('无法找到 $scope,请确认是否在 App 端运行');    return;  }  const currentWebview = proxy.$scope.$getAppWebview();  /**   * APP -> H5   * 调用 H5 中定义的 window.getToken 方法,传入模拟 Token   * 延时执行:等待 web-view 组件完成内部渲染,确保 children 数组已生成   */setTimeout(() => {if (currentWebview && currentWebview.children()) {			wv = currentWebview.children()[0];      const token='我是app端token'			wv.evalJS(`getToken(${token})`);    }	}, 1000);});/** * H5 -> APP * 消息接收处理器 * 接收来自 H5 的 postMessage 数据 */const handleMessage = (e) => {  const msg = e.detail?.data;  console.log('📩 收到 H5 消息:', msg);  // 业务逻辑:根据 msg.action 判断 H5 意图  // 例如:if (msg.action === 'scanCode') { uni.scanCode(...) }  // TODO: 验证消息合法性并执行相应原生操作};</script><style></style>

5. 关键技术细节说明

H5 -> App: H5 页面必须引入 uni.webview.x.x.x.js,并在 UniAppJSBridgeReady 事件触发后,使用 uni.postMessage 发送数据。App 端通过 <web-view @message="..."> 接收。

App -> H5: App 端需获取原生 webview 实例(通过 $getAppWebview().children()[0]),调用 wv.evalJS('functionName(args)') 直接执行 H5 全局作用域下的函数。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » UniApp 集成 OpenLayers 加载天地图 (Web-view双向通信方案)

猜你喜欢

  • 暂无文章