更新记录
1.0.6(2025-12-10)
删除无用的 ios 资源,避免打包太大
1.0.5(2025-12-10)
修复 ios demo 报错问题
1.0.4(2025-12-10)
修复demo报错问题
查看更多平台兼容性
uni-app x(4.85)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 5.0 | 12 | 12 | × |
pow-amapx
开发文档
UTS 语法 UTS API插件 UTS uni-app兼容模式组件 UTS 标准模式组件 Hello UTS
已支持:
- 高德sdk,鸿蒙+安卓+ios,单次定位+持续定位+后台定位,地图控制以及绘制线+绘制圆+绘制多边形
- 只支持 uniappx,不支持 uniapp
- 导航功能增加后计划调整价格
待支持:
- 地图更多控制功能
- 地图添加 marker 功能
- 导航功能
使用方式
- 在插件市场导入本插件到工程中(试用也可以)
- 【鸿蒙】把示例工程根目录中的
harmony-configs复制到自己工程根目录 - 【鸿蒙】鸿蒙不用打自定义基座,直接仿照示例工程中的
index.uvue中的getHarmonyAppId()方法,在自己项目中调用getHarmonyAppId()获取鸿蒙的专属appIdentifier - 申请高德地图的key。(鸿蒙要把
专属appIdentifier粘贴到高德地图key的申请页面) - 【鸿蒙,安卓,iOS】参考示例工程的
index.uvue中的initAmapSDK方法,调用插件的setAmapKey方法 - 【安卓,iOS】打自定义基座(鸿蒙不需要打)
- 【安卓,iOS】运行到自定义基座,【鸿蒙】直接运行
- 【鸿蒙,安卓,iOS】参考示例工程的
index.uvue中的申请定位权限,单次定位,持续定位方法 - 【鸿蒙】鸿蒙平台如果想调用持续后台定位,需要参考示例工程的
App.uvue,在自己工程的App.uvue的onShow调用amapOnAppShow(),在onHide调用amapOnAppHide()
接口示例
接口功能
<template>
<view class="container">
<text class="title">系统功能</text>
<view class="content">
<button type="primary" class="btn" size="mini" @click="jianchadingweiquanxian">检查定位权限</button>
<!-- #ifdef APP-HARMONY -->
<button type="primary" class="btn" @click="reqHarmonyAppId" size='mini'>获取鸿蒙AppId</button>
<!-- #endif -->
<button type="primary" class="btn" size="mini" @click="goToMap">跳转到地图</button>
</view>
<text class="title">定位功能</text>
<view class="content">
<button type="primary" class="btn" size="mini" @click="dancidingwei">单次定位</button>
<button type="primary" class="btn" size="mini" @click="chixudingwei">持续定位</button>
<button type="primary" class="btn" size="mini" @click="jieshuchixudingwei">结束持续定位</button>
</view>
<text class="title">搜索功能</text>
<view class="content">
<button type="primary" class="btn" size="mini" @click="searchPoi">关键词搜索</button>
<button type="primary" class="btn" size="mini" @click="searchNearby">周边搜索</button>
</view>
<view class="content">
<button type="primary" class="btn" size="mini" @click="searchGeocode">地理编码</button>
<button type="primary" class="btn" size="mini" @click="searchRegeocode">逆地理编码</button>
</view>
<text class="title">工具功能</text>
<view class="content">
<button type="primary" class="btn" size="mini" @click="calcDistance">计算距离</button>
<button type="primary" class="btn" size="mini" @click="calcArea">计算面积</button>
<button type="primary" class="btn" size="mini" @click="convertCoord">坐标转换</button>
</view>
<!-- 结果显示区域 -->
<text class="title">结果</text>
<scroll-view class="result-area" scroll-y="true">
<text class="result-text">{{resultText}}</text>
</scroll-view>
</view>
</template>
<script lang="uts" setup>
import {
setAmapKey,
getAmapLocation,
startAmapLocation,
stopAmapLocation,
checkAndRequestLocationPermission,
searchAmapPoisWithKeywords,
searchAmapPoisNearby,
searchAmapGeocode,
searchAmapRegeocode,
amapLineDistance,
amapCaculateArea,
amapCoordFromOtherCoord
} from '@/uni_modules/pow-amapx' // 导入插件内的方法
// 当前位置(用于搜索)
let currentLat = ref(39.91054)
let currentLon = ref(116.398111)
let resultText = ref('点击按钮测试功能...')
// #ifdef APP-HARMONY
import {
getHarmonyAppId
} from '@/uni_modules/pow-amapx'
const reqHarmonyAppId = () => {
// 获取鸿蒙AppId , 高德后台要填这个字段
let appid = getHarmonyAppId()
console.log(`appid: ${appid}`)
uni.showModal({
title: '鸿蒙AppId',
content: appid,
confirmText: '复制到剪切板',
cancelText: '取消',
success: res => {
if (res.confirm) {
uni.setClipboardData({
data: appid,
success: () => {
uni.showToast({
title: '已复制到剪切板'
})
}
})
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
// #endif
const initAmapSDK = ()=> {
/* setTencentKey
接收4个参数,分别是
1. ioskey
2. 安卓key
3. 鸿蒙key
*/
setAmapKey(
'2d3da96f1736d9403288c6ed95a5e85f',
'72566fdc715020e355f355e4d9b7ceb1',
'dc45c88c0fb6dbd5ffb54cd33475ab48')
}
onReady(() => {
uni.setNavigationBarTitle({
title: '高德demo'
})
initAmapSDK()
})
const jianchadingweiquanxian = () => {
console.log('请求定位权限');
checkAndRequestLocationPermission(res => {
console.log(`定位权限状态:${JSON.stringify(res)}`)
uni.showToast({
title: `请求权限回调:${JSON.stringify(res)}`,
icon: 'none'
})
})
}
const dancidingwei = () => {
uni.showLoading({
title: '正在定位...'
})
resultText.value = '正在定位...'
getAmapLocation({
needAddress: true, //是否需要返回位置描述
}, res => {
uni.hideLoading()
console.log(` 调用方收到定位结果:${JSON.stringify(res)}`)
// 更新当前位置
const lat = res.getNumber('lat')
const lon = res.getNumber('lon')
if (lat != null && lon != null) {
currentLat.value = lat
currentLon.value = lon
}
// 显示结果
const address = res.getString('address')
const city = res.getString('city')
let text = `定位成功!\n`
text += `经度: ${lon}\n`
text += `纬度: ${lat}\n`
if (city != null) text += `城市: ${city}\n`
if (address != null) text += `地址: ${address}`
resultText.value = text
uni.showToast({
title: `定位成功`,
icon: 'success'
})
})
}
const chixudingwei = ()=>{
resultText.value = '开始持续定位...'
startAmapLocation({
interval: 2000, // 定位间隔,单位毫秒,默认是2000
enableBg: true, // 是否开启后台定位, 默认false
needAddress: true, //是否需要返回位置描述
bgTitle: '定位中', // 后台定位时显示的标题
}, res=>{
console.log(`持续定位结果:${JSON.stringify(res)}`)
// 更新当前位置
const lat = res.getNumber('lat')
const lon = res.getNumber('lon')
if (lat != null && lon != null) {
currentLat.value = lat
currentLon.value = lon
}
// 显示结果
const address = res.getString('address')
let text = `持续定位中...\n`
text += `经度: ${lon}\n`
text += `纬度: ${lat}\n`
if (address != null) text += `地址: ${address}`
resultText.value = text
})
}
const jieshuchixudingwei = ()=>{
stopAmapLocation({}, res=>{
console.log(`停止持续定位结果:${JSON.stringify(res)}`)
resultText.value = `停止持续定位: ${JSON.stringify(res)}`
uni.showToast({
title: `停止持续定位结果:${JSON.stringify(res)}`,
icon: 'none'
})
})
}
// ========== 搜索功能 ==========
const searchPoi = () => {
resultText.value = '正在搜索POI...'
searchAmapPoisWithKeywords('餐厅', '北京', (res: UTSJSONObject) => {
console.log('POI搜索结果:', JSON.stringify(res))
const errCode = res.getNumber('errCode')
if (errCode == 0) {
const pois = res.getArray<UTSJSONObject>('pois')
if (pois != null && pois.length > 0) {
let text = `找到 ${pois.length} 个结果:\n`
for (let i = 0; i < Math.min(5, pois.length); i++) {
const poi = pois[i]
text += `${i+1}. ${poi.getString('name')}\n`
}
resultText.value = text
} else {
resultText.value = '未找到结果'
}
} else {
resultText.value = `搜索失败: ${errCode}`
}
})
}
const searchNearby = () => {
resultText.value = '正在搜索周边...'
searchAmapPoisNearby(currentLat.value, currentLon.value, 1000, (res: UTSJSONObject) => {
console.log('周边搜索结果:', JSON.stringify(res))
const errCode = res.getNumber('errCode')
if (errCode == 0) {
const pois = res.getArray<UTSJSONObject>('pois')
if (pois != null && pois.length > 0) {
let text = `周边 ${pois.length} 个POI:\n`
for (let i = 0; i < Math.min(5, pois.length); i++) {
const poi = pois[i]
text += `${i+1}. ${poi.getString('name')}\n`
}
resultText.value = text
} else {
resultText.value = '周边无POI'
}
} else {
resultText.value = `搜索失败: ${errCode}`
}
})
}
const searchGeocode = () => {
resultText.value = '正在进行地理编码...'
searchAmapGeocode('天安门', '北京', (res: UTSJSONObject) => {
console.log('地理编码结果:', JSON.stringify(res))
const errCode = res.getNumber('errCode')
if (errCode == 0) {
const addressList = res.getArray<UTSJSONObject>('addressList')
if (addressList != null && addressList.length > 0) {
const addr = addressList[0]
const lat = addr.getNumber('lat')
const lon = addr.getNumber('lon')
const name = addr.getString('name')
resultText.value = `地理编码成功!\n地址: ${name}\n经度: ${lon}\n纬度: ${lat}`
} else {
resultText.value = '未找到地理编码结果'
}
} else {
resultText.value = `地理编码失败: ${errCode}`
}
})
}
const searchRegeocode = () => {
resultText.value = '正在进行逆地理编码...'
searchAmapRegeocode(currentLat.value, currentLon.value, (res: UTSJSONObject) => {
console.log('逆地理编码结果:', JSON.stringify(res))
const errCode = res.getNumber('errCode')
if (errCode == 0) {
const address = res.getString('address') ?? ''
const city = res.getString('city') ?? ''
const district = res.getString('district') ?? ''
resultText.value = `逆地理编码成功!\n地址: ${address}\n城市: ${city}\n区县: ${district}`
} else {
resultText.value = `逆地理编码失败: ${errCode}`
}
})
}
// ========== 工具功能 ==========
const calcDistance = () => {
// 计算当前位置到天安门的距离
const tiananmenLat = 39.9087
const tiananmenLon = 116.3975
const distance = amapLineDistance(currentLat.value, currentLon.value, tiananmenLat, tiananmenLon)
resultText.value = `当前位置到天安门的直线距离:\n${distance.toFixed(2)} 米\n(约 ${(distance/1000).toFixed(2)} 公里)`
}
const calcArea = () => {
// 计算一个区域的面积(左上角到右下角)
const lat1 = 39.92
const lng1 = 116.38
const lat2 = 39.90
const lng2 = 116.42
const area = amapCaculateArea(lat1, lng1, lat2, lng2)
resultText.value = `区域面积:\n${area.toFixed(2)} 平方米\n(约 ${(area/1000000).toFixed(4)} 平方公里)`
}
const convertCoord = () => {
// GPS坐标转高德坐标示例
const gpsLat = 39.9087
const gpsLon = 116.3975
const result = amapCoordFromOtherCoord('gps', gpsLat, gpsLon)
const newLat = result.getNumber('lat')
const newLon = result.getNumber('lon')
resultText.value = `GPS坐标转换:\n原坐标: ${gpsLon}, ${gpsLat}\n高德坐标: ${newLon}, ${newLat}`
}
const goToMap = () => {
uni.navigateTo({
url: './map'
})
}
</script>
<style lang="scss">
.title {
font-size: 18px;
font-weight: bold;
color: #000;
margin-top: 20px;
margin-left: 10px;
}
.container {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 750rpx;
height: 100%;
}
.content {
margin-top: 10px;
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
flex-wrap: wrap;
}
.btn {
margin-left: 10px;
margin-top: 5px;
}
.result-area {
flex: 1;
min-height: 200rpx;
background-color: #f5f5f5;
padding: 20rpx;
margin: 10px;
border-radius: 10rpx;
width: 100%;
box-sizing: border-box;
margin-left: 0;
margin-right: 0;
padding-left: 10px;
padding-right: 10px;
}
.result-text {
font-size: 14px;
color: #333;
line-height: 1.6;
}
</style>
地图功能
<template>
<view class="container">
<pow-amapx
ref="mapRef"
class="native-map"
:center='mapCenter'
:zoomLevel='mapZoomLevel'
@load="onMapLoad"
@mapLoaded="onMapLoaded"
@mapRendered="onMapRendered"
></pow-amapx>
<!-- 地图控制按钮 -->
<view class="section">
<text class="section-title">地图控制</text>
<view class="btns">
<button class="btn" size="mini" type="primary" @click="moveCenter">移动中心点</button>
<button class="btn" size="mini" type="primary" @click="zoomIn">放大</button>
<button class="btn" size="mini" type="primary" @click="zoomOut">缩小</button>
<button class="btn" size="mini" type="primary" @click="getMapInfo">获取地图信息</button>
</view>
<view class="btns">
<button class="btn" size="mini" type="default" @click="setMapTypeNormal">普通地图</button>
<button class="btn" size="mini" type="default" @click="setMapTypeSatellite">卫星地图</button>
<button class="btn" size="mini" type="default" @click="setMapTypeNight">夜间地图</button>
<button class="btn" size="mini" type="default" @click="setMapTypeNavi">导航地图</button>
</view>
<view class="btns">
<button class="btn" size="mini" :type="trafficEnabled ? 'warn' : 'primary'" @click="toggleTraffic">{{trafficEnabled ? '关闭路况' : '开启路况'}}</button>
<button class="btn" size="mini" :type="compassEnabled ? 'warn' : 'primary'" @click="toggleCompass">{{compassEnabled ? '隐藏指南针' : '显示指南针'}}</button>
<button class="btn" size="mini" :type="scaleEnabled ? 'warn' : 'primary'" @click="toggleScale">{{scaleEnabled ? '隐藏比例尺' : '显示比例尺'}}</button>
</view>
</view>
<!-- 绘制功能按钮 -->
<view class="section">
<text class="section-title">绘制功能</text>
<view class="btns">
<button class="btn" size="mini" type="primary" @click="drawPolyline">画折线</button>
<button class="btn" size="mini" type="warn" @click="removePolyline">删除折线</button>
<button class="btn" size="mini" type="primary" @click="drawCircle">画圆形</button>
<button class="btn" size="mini" type="warn" @click="removeCircle">删除圆形</button>
</view>
<view class="btns">
<button class="btn" size="mini" type="primary" @click="drawPolygon">画多边形</button>
<button class="btn" size="mini" type="warn" @click="removePolygon">删除多边形</button>
<button class="btn" size="mini" type="primary" @click="drawTexturedPolyline">画纹理线</button>
<button class="btn" size="mini" type="default" @click="clearAllOverlays">清除所有</button>
</view>
</view>
<!-- 结果显示区域 -->
<scroll-view class="result-area" scroll-y="true">
<text class="result-text">{{resultText}}</text>
</scroll-view>
</view>
</template>
<script>
import lineTextureData from '../../static/linetexture.json'
export default {
data() {
return {
mapCenter: '116.398111,39.91054',
mapZoomLevel: 12,
resultText: '点击按钮测试地图控制功能...',
trafficEnabled: false,
compassEnabled: false,
scaleEnabled: true,
// 绘制数据
polylineData: {
id: 'polyline001',
points: [
'116.362209,39.887487',
'116.422897,39.878002',
'116.372105,39.90651',
'116.428945,39.89663'
],
width: 10,
color: '#FF0000',
isDottedLine: false
},
circleData: {
id: 'circle001',
lat: 39.91054,
lng: 116.398111,
radius: 1000,
lineWidth: 5,
strokeColor: '#FF0000',
fillColor: '#50FF0000'
},
polygonData: {
id: 'polygon001',
points: [
'116.404,39.915',
'116.408,39.917',
'116.412,39.919',
'116.412,39.921',
'116.410,39.923',
'116.406,39.923',
'116.404,39.921'
],
lineWidth: 5,
strokeColor: '#0000FF',
fillColor: '#500000FF'
},
texturedPolylineData: {
id: 'texturedPolyline001',
points: [
'116.352209,39.897487',
'116.402897,39.888002',
'116.362105,39.91651',
'116.418945,39.90663',
'116.438945,39.92663'
],
width: 20,
texture: lineTextureData.imageBase64
}
}
},
methods: {
// ========== 地图事件 ==========
onMapLoad() {
console.log('地图组件加载完成')
this.resultText = '地图组件加载完成'
},
onMapLoaded(e: UniNativeViewEvent) {
console.log('地图已加载')
this.resultText = '地图已加载'
},
onMapRendered(e: UniNativeViewEvent) {
console.log('地图已渲染')
this.resultText = '地图已渲染'
},
// ========== 地图控制 ==========
moveCenter() {
const lat = 39.9 + Math.random() * 0.1
const lon = 116.3 + Math.random() * 0.2
this.mapCenter = `${lon},${lat}`
this.resultText = `中心点移动到: ${lon.toFixed(6)}, ${lat.toFixed(6)}`
},
zoomIn() {
if (this.mapZoomLevel < 20) {
this.mapZoomLevel += 1
this.resultText = `缩放级别: ${this.mapZoomLevel}`
}
},
zoomOut() {
if (this.mapZoomLevel > 3) {
this.mapZoomLevel -= 1
this.resultText = `缩放级别: ${this.mapZoomLevel}`
}
},
getMapInfo() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
const center = mapRef.$callMethod('getCenter') as UTSJSONObject
const zoom = mapRef.$callMethod('getZoomLevel') as number
const lat = center.getNumber('lat') ?? 0
const lon = center.getNumber('lon') ?? 0
this.resultText = `当前地图信息:\n中心点: ${lon.toFixed(6)}, ${lat.toFixed(6)}\n缩放级别: ${zoom.toFixed(1)}`
}
},
setMapTypeNormal() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setMapType', 1)
this.resultText = '已切换到普通地图'
}
},
setMapTypeSatellite() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setMapType', 2)
this.resultText = '已切换到卫星地图'
}
},
setMapTypeNight() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setMapType', 3)
this.resultText = '已切换到夜间地图'
}
},
setMapTypeNavi() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setMapType', 4)
this.resultText = '已切换到导航地图'
}
},
toggleTraffic() {
this.trafficEnabled = !this.trafficEnabled
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('showTraffic', this.trafficEnabled)
this.resultText = this.trafficEnabled ? '已开启实时路况' : '已关闭实时路况'
}
},
toggleCompass() {
this.compassEnabled = !this.compassEnabled
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setCompassEnabled', this.compassEnabled)
this.resultText = this.compassEnabled ? '已显示指南针' : '已隐藏指南针'
}
},
toggleScale() {
this.scaleEnabled = !this.scaleEnabled
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('setScaleControlsEnabled', this.scaleEnabled)
this.resultText = this.scaleEnabled ? '已显示比例尺' : '已隐藏比例尺'
}
},
// ========== 绘制功能 ==========
drawPolyline() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('drawPolyline', JSON.stringify(this.polylineData))
this.resultText = '已绘制折线'
}
},
removePolyline() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('removePolyline', '{"id":"polyline001"}')
this.resultText = '已删除折线'
}
},
drawCircle() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('drawCircle', JSON.stringify(this.circleData))
this.resultText = '已绘制圆形'
}
},
removeCircle() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('removeCircle', '{"id":"circle001"}')
this.resultText = '已删除圆形'
}
},
drawPolygon() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('drawPolygon', JSON.stringify(this.polygonData))
this.resultText = '已绘制多边形'
}
},
removePolygon() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('removePolygon', '{"id":"polygon001"}')
this.resultText = '已删除多边形'
}
},
drawTexturedPolyline() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('drawTexturedPolyline', JSON.stringify(this.texturedPolylineData))
this.resultText = '已绘制纹理折线'
}
},
clearAllOverlays() {
const mapRef = this.$refs['mapRef'] as ComponentPublicInstance
if (mapRef != null) {
mapRef.$callMethod('removeAllPolylines')
mapRef.$callMethod('removeAllCircles')
mapRef.$callMethod('removeAllPolygons')
this.resultText = '已清除所有覆盖物'
}
}
}
}
</script>
<style>
.section {
padding: 10rpx 20rpx;
background-color: #f8f8f8;
margin-top: 10rpx;
}
.section-title {
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.btn {
margin-left: 10rpx;
margin-top: 10rpx;
}
.btns {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding-top: 10rpx;
padding-bottom: 10rpx;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.native-map {
height: 35%;
width: 100%;
}
.result-area {
flex: 1;
background-color: #fff;
padding: 20rpx;
margin: 10rpx;
border-radius: 10rpx;
border: 1px solid #eee;
}
.result-text {
font-size: 26rpx;
color: #333;
line-height: 1.6;
}
</style>

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 1700
赞赏 0
下载 11978005
赞赏 1821
赞赏
京公网安备:11010802035340号