更新记录

1.0.5(2026-10-19) 下载此版本

修复一些bug

1.0.4(2026-10-19) 下载此版本

  • 修复:半屏嵌入时导航视图顶部多出一条空白(Android 导航状态栏占位 + 系统窗口内边距),创建视图时关闭 setNaviStatusBarEnabled(false) 与 setFitsSystemWindows(false)

1.0.3(2026-10-19) 下载此版本

修复一些bug

查看更多

平台兼容性

uni-app(5.26)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ - - × √ √ √ -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.26)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - - -

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × × √

lj-amap-nav 高德导航(半屏)

在 uni-app 的 nvue 页面里嵌入一块半屏高德导航地图:导航视图按你指定的尺寸铺在页面上半屏,下半屏继续放自己的业务 UI,两种内容同屏共存。

支持 驾车 / 骑行 / 步行 三种方式、一键导航(自动取当前位置)、模拟导航、内置语音播报、单次 / 持续定位。

<lj-amap-nav ref="navi" style="height:400px" @location="onLocation"></lj-amap-nav>
this.$refs.navi.startRouteFromCurrent(39.909187, 116.397451, false)   // 从当前位置导航到天安门

Key 怎么给:推荐写进插件常量 utssdk/app-android/index.vue 的 API_KEY(Android)、utssdk/app-ios/index.vue 的 API_KEY(iOS),页面不用传,见「4.3」。用 :apikey 属性也可以,但 nvue 下不保证拿到,见「十二」。

打包必读:云打包与本地打包的依赖接法完全不同,接错的表现都是「一进页面就闪退」(NoClassDefFoundError: Lcom/amap/api/maps/MapsInitializer),详见「十一」。


目录

章节 内容
一 特性
二 平台支持
三 环境要求
四 接入步骤(4 步)
五 组件属性
六 方法 API
七 事件
八 错误码
九 典型场景代码
十 使用限制与注意事项
十一 打包注意事项(云打包 / 本地打包)
十二 Key 取不到(WARNING 未传入 apiKey / code=13)的排查
十三 常见问题 FAQ
十四 版本记录
十五 许可与声明

只想尽快跑起来:看「三 → 四」;查参数跳「五、六、七」;闪退/黑屏跳「十一、十二、十三」。


一、特性

特性 说明
半屏 / 任意尺寸嵌入 高度自己定,上半屏、上下分屏、三分之一屏都行
三种导航方式 驾车 / 骑行 / 步行,同一个组件内切换,无需重建页面
一键导航 只给终点,起点自动取当前位置
模拟导航 不用真实移动也能演示导航过程,适合室内调试
内置语音播报 使用高德自带语音,无需接入第三方 TTS
自动就近 骑行 / 步行终点过远时,自动把终点拉近到起点附近,避免算路失败
单次 / 持续定位 locateStart() 拿一次坐标;startContinuousLocation() 持续上报
事件回传 定位结果与运行日志都以组件事件回传,可实时显示在界面上
退出即清理 页面销毁自动停止导航、停止语音、释放定位

二、平台支持

平台 支持
App-Android ✅
App-iOS ✅
App-Harmony ❌
H5 / 小程序 / App-vue 页面 ❌
  • 组件只能用在 nvue 页面(.nvue 文件);
  • 内置能力版本:navi 11.2.100 / 3dmap 11.2.100 / location 11.2.100 / search 9.8.1。

三、环境要求

项 要求
HBuilderX 4.36 及以上
运行方式 必须使用自定义基座或正式打包,标准基座不含插件原生库
Android minSdkVersion 23 及以上,仅支持 arm64-v8a
页面类型 必须是 nvue 页面
高德 Key 必须自行申请(Android、iOS 各一个,不通用)
打包方式 云打包从 Maven 自动拉取(插件内不携带 jar);本地(离线)打包需自行准备 jar / so / assets,见「十一」

每次改动 uni_modules/lj-amap-nav/ 下的文件,都要重新制作一次自定义基座;只改自己的 pages/ 不用。


四、接入步骤(4 步)

4.1 导入插件

插件市场点「导入」,插件会出现在项目的 uni_modules/lj-amap-nav/ 下。

4.2 申请高德 Key

到高德开放平台 → 控制台 → 创建应用 → 添加 Key:

平台 必填信息 注意
Android 包名 + 签名 SHA1 包名用真机上的实际包名;SHA1 用正在运行的那个基座/安装包的签名
iOS Bundle Identifier 与证书里的 BundleId 一致
  • Key 绑错不会报错,只表现为「地图黑屏 / 算路失败(code=7)」;
  • 调试基座换了证书,SHA1 会变,Key 也要跟着更新;
  • 一个 Key 即可覆盖该 App 的地图 / 定位 / 算路 / 导航能力。

4.3 配置 Key(三种方式,选一个)

方式 A:写进插件常量(推荐,最稳)

// utssdk/app-android/index.vue 顶部
const API_KEY = '你的 Android Key'
// utssdk/app-ios/index.vue 顶部
const API_KEY = '你的 iOS Key'
  • 发布版这两个常量留空(避免泄露),使用者自己填;
  • 生效日志:apiKey 来源=builtin;
  • 注意:插件升级会覆盖这两个文件,升级后需要重新填。

方式 B:交给高德 SDK 读清单(只影响 Android,本地打包推荐)

在 AndroidManifest.xml 里写:

<meta-data android:name="com.amap.api.v2.apikey" android:value="你的高德Key" />
  • 插件自带的那份 utssdk/app-android/AndroidManifest.xml 不再声明这个 meta-data(留空会和宿主 App 的 Key 合并冲突),需要用方式 B 的话自己加进去;
  • 云打包:加在插件这份 AndroidManifest.xml(会自动合并);
  • 本地(离线)打包不会合并插件清单,必须手写进 AS 工程的 src/main/AndroidManifest.xml(见 11.3 ③);
  • 插件当前逻辑:只有拿到非空 Key 才会 setApiKey,不会把清单里的 Key 冲掉,两种方式可以并存。

好处:Key 跟着宿主工程走,插件升级不会被覆盖,所以本地打包优先推荐方式 B。

方式 C:页面用属性传(写法最省事,但 nvue 下不保证生效)

<lj-amap-nav ref="navi" style="height:400px" :apikey="amapKey"
    @location="onLocation" @log="onLog"></lj-amap-nav>
data() {
    const platform = uni.getSystemInfoSync().platform
    const amapKey = platform === 'ios' ? '你的 iOS Key' : '你的 Android Key'
    return { amapKey: amapKey }
}
  • 属性名必须全小写 apikey(api-key / apiKey 更容易传不进);
  • 若日志出现 WARNING 未传入 apiKey,说明属性没拿到,原因与解法见「十二」。

三种方式选一个即可。判断生效结果看启动日志:apiKey 来源=builtin(方式 A/B)或 apiKey 来源=apikey(方式 C)。

⚠️ 对外发布的插件包不要提交真实 Key。发布版 API_KEY 保持 '',由使用者自己填或走属性。

4.4 打自定义基座并运行

  1. 运行 → 制作自定义调试基座(Android / iOS 各提交一次);
  2. 运行 → 运行基座选择 → 勾「自定义调试基座」;
  3. 建议先卸载手机上旧的同名 App,再运行到真机(避免装的是旧包)。

正常启动日志(按顺序):

[lj-amap-nav] [life] NVLoad 开始
[lj-amap-nav] [life] apiKey 来源=builtin      ← 或 =apikey
[lj-amap-nav] [life] 高德 Key 与隐私合规已设置
[lj-amap-nav] [life] 地图初始化成功
[lj-amap-nav] [life] 导航实例创建成功
[lj-amap-nav] [view] 导航视图加载完成
  • 出现 WARNING 未传入 apiKey → Key 为空,算路必然 code=13,见「十二」;
  • 地图黑屏 → Key 与「包名 + SHA1 / BundleId」不匹配,见「8、错误码」。

五、组件属性

属性 类型 必填 说明
apikey String 与方式 A 二选一 高德 Key(仅方式 C 使用)。见 5.1
style String 是 必须给明确宽高,例如 style="height:400px";不支持 flex:1,不指定尺寸组件不显示
ref String 是 用于拿组件实例调方法:this.$refs.navi.xxx()

5.1 apikey

项 说明
取值 Android 传 Android Key、iOS 传 iOS Key(两把不通用)
写法 :apikey="变量" 或 apikey="你的Key",全小写
可靠性 nvue 下属性注入可能晚于组件初始化,稳妥做法是改用 API_KEY(方式 A)
是否生效 日志 apiKey 来源=apikey 为生效;来源=builtin 表示用的是插件常量

5.2 style

  • 必须给确定尺寸:style="height:400px"、style="width:750rpx;height:560rpx";
  • 不支持 flex:1;
  • 组件尺寸在创建时确定,运行中修改 :style 不会重新布局 —— 先算好尺寸再用 v-if 挂载;
  • 想做「半屏」:uni.getSystemInfoSync().windowHeight / 2。

5.3 ref

所有方法都通过 this.$refs.navi.xxx() 调用。拿不到实例时调用会静默失败,请确认 ref 名称一致。


六、方法 API

6.1 方法总览

分类 方法 说明
初始化 tryInit() / pageShow() / pageHide() 页面生命周期联动
导航方式 setNaviType(t) 切换 驾车 / 骑行 / 步行
算路 startRoute(sLat,sLng,eLat,eLng,emulator) 指定起终点
算路 startRouteFromCurrent(eLat,eLng,emulator) 一键导航(起点取当前位置)
算路 stopRoute() 停止导航
定位 locateStart() 单次定位
定位 startContinuousLocation(intervalMs) / stopContinuousLocation() 持续定位 / 停止
定位 isContinuousLocationRunning() 是否持续定位中
定位 useLastKnownLocation() 用最近一次已知位置兜底
定位 hasLocationPermission() / requestLocationPermission() 查权限 / 申请权限(仅 Android)
状态 getLastLocation() / hasLocationReady() 最近坐标 / 是否已定位
状态 getLastTts() / getLastError() / getNaviType() / clearError() 最近播报 / 最近错误 / 当前方式 / 清错误
日志 setLogLevel(level) / getLogLevel() 日志级别
回调 onLocationUpdate(cb) / onTtsUpdate(cb) / onErrorUpdate(cb) 函数式回调(备选,见 6.7)

读取类方法(getLastLocation() 等)的同步返回值在 nvue 下不可靠,只作调试参考;要拿数据请用事件(第七节)。

6.2 初始化与生命周期

方法 参数 返回 说明
tryInit() — void 初始化 / 补发视图生命周期,内部幂等,可重复调用
pageShow() — void 页面可见时调用(与 tryInit() 等价,二选一)
pageHide() — void 页面隐藏时调用,不会打断正在进行的导航
onReady() { this.$refs.navi.tryInit() },
onShow()  { this.$refs.navi.tryInit() },
onHide()  { this.$refs.navi.pageHide() }

6.3 导航方式与算路

setNaviType(t)

参数 类型 必填 说明
t String 是 'drive' 驾车(默认)/ 'ride' 骑行 / 'walk' 步行

正在导航时切换会先停止当前导航,切换后需要重新调用 startRoute*()。

this.$refs.navi.setNaviType('ride')

startRoute(sLat, sLng, eLat, eLng, emulator)

参数 类型 必填 说明
sLat Number 是 起点纬度
sLng Number 是 起点经度
eLat Number 是 终点纬度
eLng Number 是 终点经度
emulator Boolean 是 true 模拟导航 / false 实时导航
this.$refs.navi.startRoute(39.909187, 116.397451, 39.993185, 116.396612, false)

坐标必须是 gcj02。来自 GPS(wgs84)的坐标请先转换,否则偏移或算路失败。

startRouteFromCurrent(eLat, eLng, emulator) ⭐ 最常用

参数 类型 必填 说明
eLat Number 是 终点纬度
eLng Number 是 终点经度
emulator Boolean 是 true 模拟导航 / false 实时导航

流程:已有定位 → 直接算路;无定位 → 申请权限并定位 → 定位成功自动算路 → 算路成功自动起导航。首次安装也不需要点第二次。

this.$refs.navi.startRouteFromCurrent(39.909187, 116.397451, false)

stopRoute()

停止导航、停止语音、释放定位(持续定位一起停)。建议在 onUnload 里调用。

onUnload() { this.$refs.navi.stopRoute() }

6.4 定位

locateStart()

单次定位,结果通过 @location 回传。未授权时自动弹系统授权框,允许后自动继续。

this.$refs.navi.locateStart()

startContinuousLocation(intervalMs)

参数 类型 必填 默认 说明
intervalMs Number 否 2000 上报间隔(毫秒)。仅 Android 按此间隔;iOS 按系统回调频率。传 <=0 按 2000

每次上报都触发一次 @location;与单次定位共用同一事件通道;调用 locateStart() 会切回单次模式。

this.$refs.navi.startContinuousLocation(2000)

stopContinuousLocation()

停止持续定位,可再次 startContinuousLocation() 恢复。

isContinuousLocationRunning()

返回 Boolean,是否正在持续定位(同步返回值,仅调试参考)。

useLastKnownLocation()

用最近一次已知位置立即补发一次 @location(从未定位过则无动作)。

权限(仅 Android)

方法 返回 说明
hasLocationPermission() Boolean 是否已授予定位权限
requestLocationPermission() void 弹系统授权框申请权限

iOS 没有「主动申请」这一步,首次定位时系统自动弹窗。

页面不要自己调 plus.android.requestPermissions,拿不到回调;用本插件方法即可。

6.5 状态读取

方法 返回 说明
getLastLocation() String 最近坐标 "纬度,经度",未定位为空串
hasLocationReady() Boolean 是否已取得过定位
getLastTts() String 最后一条播报文本(iOS 当前返回空串)
getLastError() String 最后一次错误描述
getNaviType() String 当前方式:drive / ride / walk
clearError() void 清空错误记录

6.6 日志

方法 参数 返回 说明
setLogLevel(level) Number void 0 关闭 / 1 简洁 / 2 详细,默认 2
getLogLevel() — Number 当前级别

日志同时走两条通道:控制台(统一 [lj-amap-nav] 前缀)与 @log 事件(可直接显示在界面上)。

6.7 函数式回调(备选)

方法 回调参数 说明
onLocationUpdate(cb) text: String 定位成功回调(持续定位每次上报都回调)
onTtsUpdate(cb) text: String 播报文本(Android 有内容,iOS 暂不回调)
onErrorUpdate(cb) text: String 算路失败、自动就近等错误

nvue 下把函数传进组件方法可能不生效,这三个仅作备选,推荐用事件。


七、事件

7.1 @location(定位结果)⭐

字段 类型 说明
ok Boolean true 成功;false 失败
text String "纬度,经度",失败时为空串
lat Number 纬度,失败时 0
lng Number 经度,失败时 0
err String 失败原因,例如 定位失败 code=12 info=缺少定位权限
count Number 本次运行第几次成功定位(持续定位递增)

触发时机:单次定位成功一次;持续定位每次上报一次;失败也会触发 ok=false(务必把 err 显示出来)。

两端读取位置不同,推荐这样写以同时兼容:

onLocation(e) {
    let d = e.detail
    if (d == null || Object.keys(d).length === 0) {
        d = e             // iOS 上数据在事件对象顶层
    }
    if (d.ok === false) {
        this.errText = d.err
        return
    }
    this.locText = d.text    // "39.909187,116.397451"
    this.lat = d.lat
    this.lng = d.lng
}

7.2 @log(运行日志)

字段 类型 说明
line String 完整日志行,如 10:17:21 [loc] 定位成功 39.909187,116.397451
level Number 1 简洁 / 2 详细
seq Number 自增序号,可用于排序

读取方式同 @location(Android e.detail.line,iOS e.line)。把 line 直接显示在页面上,现场排查不用连电脑:

onLog(e) {
    let d = e.detail
    if (d == null || Object.keys(d).length === 0) d = e
    if (d.line) {
        this.logLines.unshift(d.line)
        if (this.logLines.length > 50) this.logLines.pop()
    }
}

7.3 事件绑定完整示例

<lj-amap-nav ref="navi" style="height:400px"
    @location="onLocation" @log="onLog"></lj-amap-nav>

八、错误码

@location 的 err 与 @log 里会带错误码:

码 含义 处理
-2 未授权定位权限(申请中 / 被拒绝) 允许后自动继续;拒绝则去系统设置开启
-3 定位初始化失败 多为 Key 或网络问题,看 err 详情
-4 定位未就绪 重试一次;持续出现请附日志反馈
7 Key 错误 Android Key 未绑当前「包名 + SHA1」;iOS Key 未绑当前 BundleId
12 缺少定位权限 检查系统权限开关(含「精确位置」)
13 Key 非法或为空 Key 没生效:WARNING 未传入 apiKey,见「十二」
19 / 20 骑行 / 步行起终点距离太长 插件已自动就近(骑行 20 km / 步行 5 km),一般无需处理
29 导航状态冲突 切换导航方式时插件会先停止当前导航,正常不会出现

九、典型场景代码

9.1 一键导航到指定点

this.$refs.navi.startRouteFromCurrent(39.909187, 116.397451, false)

9.2 指定起点 + 模拟导航(室内调试)

this.$refs.navi.startRoute(39.909187, 116.397451, 39.993185, 116.396612, true)

9.3 骑行 / 步行

this.$refs.navi.setNaviType('ride')      // 或 'walk'
this.$refs.navi.startRouteFromCurrent(39.909187, 116.397451, false)

终点过远时插件会自动就近到起点附近(骑行约 1.5 km / 步行约 0.6 km),日志会有提示。

9.4 持续定位并展示轨迹

<lj-amap-nav ref="navi" style="height:400px" @location="onLocation"></lj-amap-nav>
<view class="btns">
    <view class="btn" @click="startLoc">开始定位</view>
    <view class="btn" @click="stopLoc">停止定位</view>
</view>
<text v-for="(p, i) in track" :key="i">{{ p }}</text>
export default {
    data() {
        return { track: [] }
    },
    methods: {
        onLocation(e) {
            let d = e.detail
            if (d == null || Object.keys(d).length === 0) d = e
            if (d.ok === false) {
                console.log('定位失败:' + d.err)
                return
            }
            this.track.unshift(d.text)
            if (this.track.length > 6) this.track.pop()
        },
        startLoc() { this.$refs.navi.startContinuousLocation(2000) },
        stopLoc() { this.$refs.navi.stopContinuousLocation() }
    },
    onUnload() { this.$refs.navi.stopContinuousLocation() }
}

9.5 页面生命周期与清理

onReady()  { this.$refs.navi.tryInit() },
onShow()   { this.$refs.navi.tryInit() },
onHide()   { this.$refs.navi.pageHide() },
onUnload() { this.$refs.navi.stopRoute() }

十、使用限制与注意事项

  1. 只能用在 nvue 页面,app-vue 页面不支持;
  2. 必须给组件明确尺寸,flex:1 无效;
  3. 必须使用自定义基座,标准基座无法运行;改动插件目录后需重做基座;
  4. 坐标系为 gcj02,其它坐标系请先转换;
  5. 权限:首次定位会弹系统授权框,允许后自动继续;用户拒绝需到系统设置开启;
  6. 后台定位未开启:App 切到后台后定位会被系统挂起;
  7. Android 仅支持 arm64-v8a,x86 模拟器无法运行;
  8. 组件对象不要手动创建 / 销毁,用 v-if 控制显隐;
  9. Key 在组件创建时一次性生效,改了要重新进入页面。

十一、打包注意事项(云打包 / 本地打包)

插件内含高德 SDK(Android:AMapNavi / AMap3DMap / AMapLocation;iOS:AMapNavi + AMapLocation), 两种打包方式的依赖接法完全不同。接错的统一表现:一进页面就闪退, 崩溃日志 NoClassDefFoundError: Failed resolution of: Lcom/amap/api/maps/MapsInitializer;。

11.1 结论先行

打包方式 高德 SDK 怎么进包 关键点
云打包(制作自定义调试基座 / 云打包正式包) 由插件 utssdk/app-android/config.json 的 dependencies(maven)自动拉取 插件不携带 jar,全靠这个坐标;插件体积仅几十 KB
本地打包(离线 SDK + Android Studio) ① 推荐:AS 工程用 gradle 依赖同样从 Maven 拉;② 离线:自己放 jar / so / assets config.json 的 maven 坐标对本地打包无效(那套依赖只给云端构建用)

通用硬性条件:

  • 仅 nvue 页面(app-vue 页面不支持);
  • Android 仅 arm64-v8a;minSdkVersion ≥ 23;
  • 必须用自定义基座(标准基座不含插件原生库);
  • 必须自备高德 Key:Android 绑「包名 + 签名 SHA1」,iOS 绑 BundleId(绑错不报错,只表现为黑屏 / code=7)。

11.2 云打包

① 在插件 config.json 里声明 maven 依赖

uni_modules/lj-amap-nav/utssdk/app-android/config.json:

{
    "dependencies": [
        "com.amap.api:navi-3dmap-location-search:11.2.100_3dmap11.2.100_loc11.2.100_sea9.8.1"
    ],
    "project": {
        "repositories": [
            "maven { url 'https://maven.aliyun.com/repository/public' }",
            "maven { url 'https://repo1.maven.org/maven2' }"
        ]
    },
    "abis": [
        "arm64-v8a"
    ],
    "minSdkVersion": 23
}
  • 这是合包坐标(导航 + 3D 地图 + 定位 + 搜索,一个 jar 全含),与插件 libs/ 里的 jar 文件名完全对应,不会出现版本错配;
  • 该坐标已在 Maven Central 上核实存在(jar 约 95.8 MB / 100,458,122 字节,MD5 09D67A8FC86E1DEDE2E1CFAB1C057C58);
  • ⚠️ 不要拆成 com.amap.api:navi-3dmap:11.2.100_3dmap11.2.100:Maven Central 上 navi-3dmap 这个 artifact 最高只到 10.0.800_3dmap10.0.800(2024-08),没有 11.x,写 11.x 会直接 Could not find com.amap.api:navi-3dmap:... 构建失败;
  • com.amap.api:location:11.2.100 单独存在,但合包已包含它,不需要再单独声明;
  • 若你的构建环境会把 libs/*.jar 也编进 dex,请先删除 libs/ 里的 jar,避免 Duplicate class com.amap.api.*(详见 11.5 表格)。

② 插件不携带 jar(插件体积与 APK 体积双赢)

插件已删除 utssdk/app-android/libs/*.jar(原 95.8 MB)。原因:打包时 HBuilderX 会把 uni_modules/** 整体拷进 APK 的 assets/uni_modules/.../libs/,那份 jar 不参与编译、运行时也不在 classpath,却让 APK 白白大 94.6 MB。

实测对比(同一个离线工程):debug APK 180.6 MB → 删除 jar 后 ≈86 MB,与 debug / release 无关。

  • 所以云打包以 dependencies 为准;
  • 做离线打包时,自行从 Maven 下载同一个 jar(地址与 MD5 见 11.3)。

③ 宿主工程的 manifest.json

  • 权限(本插件需要的 10 个): INTERNET、ACCESS_NETWORK_STATE、ACCESS_WIFI_STATE、CHANGE_WIFI_STATE、 ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION、ACCESS_LOCATION_EXTRA_COMMANDS、 FOREGROUND_SERVICE、FOREGROUND_SERVICE_LOCATION、WAKE_LOCK
  • app-plus.distribute.android 下:"minSdkVersion": 23、"abiFilters": ["arm64-v8a"]
  • iOS:privacyDescription 补三条定位说明 (NSLocationWhenInUseUsageDescription / NSLocationAlwaysAndWhenInUseUsageDescription / NSLocationAlwaysUsageDescription)

④ 打完怎么验证依赖真的进包了

把基座 APK 当 zip 打开看两点:

  1. classes*.dex 里能搜到字符串 com/amap/api/maps/MapsInitializer → 依赖已进包;
  2. 若 jar 只出现在 assets/uni_modules/lj-amap-nav/utssdk/app-android/libs/、dex 里搜不到 → 没编译进去,运行时必然闪退。

11.3 本地打包(离线 SDK + Android Studio)

以 DCloud 离线工程为例(模块名一般是 simpleDemo,路径自定)。

① 依赖怎么进包:二选一

方案 A(推荐,需联网):AS 工程直接用 gradle 依赖,不用手工放 jar 和 so

// 根 build.gradle 的 allprojects.repositories 里补仓库
repositories {
    google()
    mavenCentral()
    maven { url 'https://maven.aliyun.com/repository/public' }
}
// simpleDemo/build.gradle 的 dependencies 里加
implementation 'com.amap.api:navi-3dmap-location-search:11.2.100_3dmap11.2.100_loc11.2.100_sea9.8.1'
  • lib/arm64-v8a/*.so 会自动打进 APK,不用再放 jniLibs;
  • ⚠️ 该坐标是 jar(不是 aar),jar 里的 assets/ 不会被自动合并 → 仍需按方案 B 的第 3 行手工合并 assets,否则地图黑屏、语音异常。

方案 B(完全离线):三样东西要放对位置

放到哪里 放什么 说明
<AS工程>/simpleDemo/libs/ 整个 navi-3dmap-location-search-...jar build.gradle 里通常已有 fileTree(dir:'libs', include:['*.aar','*.jar']),不用改依赖块
<AS工程>/simpleDemo/src/main/jniLibs/arm64-v8a/ jar 里 lib/arm64-v8a/ 下的 7 个 so 必须解出来:jar 内的 so 不会被加载(libAMapSDK_NAVI_v11_2_100.so 约 64.6 MB)
<AS工程>/simpleDemo/src/main/assets/ jar 里 assets/ 下全部文件(约 1657 个) 导航引擎资源(eyrie/Localizable/map_assets/navi/svg 等),缺了会黑屏、语音异常

jar 内 assets 的顶层目录都是高德自己的,与 uni-app 的 apps/、dcloud_control.xml 不冲突,可直接合并。

一键解压脚本(PowerShell,改前两个变量即可):

Add-Type -AssemblyName System.IO.Compression.FileSystem
$jar  = '你下载的\navi-3dmap-location-search-11.2.100_3dmap11.2.100_loc11.2.100_sea9.8.1.jar'
$proj = '你的离线工程\simpleDemo'

Copy-Item $jar (Join-Path $proj 'libs') -Force
$assetsOut = Join-Path $proj 'src\main\assets'
$jniOut    = Join-Path $proj 'src\main\jniLibs\arm64-v8a'
New-Item -ItemType Directory -Force -Path $jniOut | Out-Null

$zip = [System.IO.Compression.ZipFile]::OpenRead($jar)
foreach ($e in $zip.Entries) {
    $n = $e.FullName
    if ($n.EndsWith('/')) { continue }
    if ($n -like 'assets/*') {
        $t = Join-Path $assetsOut $n
        New-Item -ItemType Directory -Force -Path (Split-Path $t) | Out-Null
        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($e, $t, $true)
    } elseif ($n -like 'lib/arm64-v8a/*.so') {
        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($e, (Join-Path $jniOut (Split-Path $n -Leaf)), $true)
    }
}
$zip.Dispose()

② <AS工程>/simpleDemo/build.gradle

defaultConfig {
    applicationId "com.xxx.xxx"
    minSdkVersion 23            // 插件要求 ≥ 23
    multiDexEnabled true        // 高德类较多,务必开启
    ndk {
        abiFilters 'arm64-v8a'  // 插件只带 arm64 的 so
    }
}

③ <AS工程>/simpleDemo/src/main/AndroidManifest.xml

插件自带的 utssdk/app-android/AndroidManifest.xml(权限 + APSService + 高德 Key 的 meta-data)本地打包不会自动合并,需手动补:

<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application ...>
    <!-- 高德定位服务,插件清单里带的,本地打包需手动搬过来 -->
    <service android:name="com.amap.api.location.APSService" />
    ...
</application>

④ 本地打包时 config.json 的 maven 依赖可以留空

{ "dependencies": [], "abis": ["arm64-v8a"], "minSdkVersion": 23 }

同一份工程以后若改用云打包,记得把 maven 坐标补回去(见 11.2)。

⑤ 打包运行流程

  1. HBuilderX:发行 → 原生 App-本地打包 → 生成本地打包 App 资源;
  2. 把生成的资源覆盖到 <AS工程>/simpleDemo/src/main/assets/apps/<appid>/www;
  3. Android Studio Rebuild → 安装到手机;
  4. HBuilderX:运行到手机 → 运行基座选自定义调试基座。

11.4 页面写法(两种打包通用)

<!-- 必须 nvue 页面;必须给明确宽高,不支持 flex:1 -->
<lj-amap-nav v-if="naviReady" ref="navi" style="width:750rpx;height:560rpx"
    @location="onLocation" @log="onLog"></lj-amap-nav>
onReady() {
    this.naviReady = true      // 等页面渲染完再挂载组件
}

要点:

  • Key 优先写进插件 utssdk/app-android/index.vue 的 const API_KEY = '你的Key'(日志 apiKey 来源=builtin);
  • 用 :apikey="变量" 也可以(必须全小写),nvue 下不保证生效,见「十二」;
  • 用 v-if 延迟到 onReady 再挂载,避免初始化时属性还没到;
  • Key 在组件创建时一次性生效,改了要重新进页面;
  • 不要在页面里自己调 plus.android.requestPermissions 申请定位,用组件自带方法;
  • 坐标必须是 gcj02。

11.5 自检清单

正常日志(按顺序出现):

[lj-amap-nav] [life] NVLoad 开始
[lj-amap-nav] [life] apiKey 来源=builtin
[lj-amap-nav] [life] 地图初始化成功
[lj-amap-nav] [life] 导航实例创建成功
[lj-amap-nav] [view] 导航视图加载完成

崩溃日志位置:<项目>/unpackage/logs/android/<时间>_<包名>_crash.log

现象 原因 处理
NoClassDefFoundError: Lcom/amap/api/maps/MapsInitializer 高德类没进 dex(多半是跑在标准基座 / 旧基座) 云打包:补 maven 依赖并重打基座;本地打包:jar 放 libs、so 放 jniLibs、assets 合并
Duplicate class com.amap.api.* maven 依赖与手工放进 libs 的 jar 同时进包 二选一:删 libs 里的 jar,或清空 dependencies(插件本身不再携带 jar)
WARNING 未传入 apiKey 插件 API_KEY 与属性都为空 把 Key 写进 API_KEY;若走属性,检查是否全小写
地图黑屏 / 算路 code=7 Key 与「包名 + SHA1」(iOS 为 BundleId)不匹配 高德后台核对签名;换基座后 SHA1 会变,Key 要同步更新
code=13 Key 非法或为空 同 WARNING 未传入 apiKey
code=-2 / code=12 没有定位权限 系统设置里允许定位(含「精确位置」)
code=19/20 骑行 / 步行起终点太远 组件已自动就近,属正常提示
地图空白但不崩 缺 so 或 assets 检查 jniLibs/arm64-v8a 的 7 个 so、assets/ 是否已合并

十二、Key 取不到(WARNING 未传入 apiKey / code=13)的排查

12.1 现象

页面已经写了 :apikey="amapKey",日志却是:

[lj-amap-nav] [life] NVLoad 开始
[lj-amap-nav] [life] WARNING 未传入 apiKey:请在页面用 :apikey 传入你的高德 Key(插件内不含 Key)
[lj-amap-nav] [life] 高德 Key 与隐私合规已设置
[lj-amap-nav] [life] 地图初始化成功
[lj-amap-nav] [life] 导航实例创建成功
...
[lj-amap-nav] [navi] ERROR 算路失败 code=13(驾车) 算路失败,key非法或过期

定位能成功([loc] 定位成功 ...),但一算路就 code=13。

12.2 原因:nvue 里属性的注入时机晚于组件初始化

Weex 创建组件
  └─ 创建原生视图 → 组件 NVLoad()        ← 此刻读 apikey,仍是默认空串
  └─ 把 :apikey 写进组件属性              ← 属性到这一步才注入
  └─ NVLoaded / NVLayouted

而 Key 在 NVLoad 阶段就被用掉了(高德要求设置 Key 早于创建导航实例),之后再补设也不生效,最终算路拿到空 Key → code=13。

12.3 为什么这些写法都没用

写法 为什么无效
apikey="你的Key"(静态属性) 同样是「组件创建之后」才注入
:apikey="常量" / :apikey="computed" 与取值方式无关,注入时机不变
:apikey + :api-key 双写 两个属性都还没注入
v-if 等 onReady 再创建组件 只改变「何时创建组件」,不改变「创建与注入的先后」

12.4 解法(三种,按省事程度排序)

A. 把 Key 写进插件常量(推荐,最稳)

// utssdk/app-android/index.vue 顶部
const API_KEY = '你的高德Key'

日志会变成 apiKey 来源=builtin。对外发布的插件包不要把真实 Key 提交上去,发布版保持 '',由使用者自己填。

B. 交给高德 SDK 读清单

在 AndroidManifest.xml 里加:

<meta-data android:name="com.amap.api.v2.apikey" android:value="你的高德Key" />

注意插件里要「有 Key 才设置」,否则空串会把清单里的 Key 覆盖掉。

C. 页面属性传 + 延迟挂载组件

v-if 等到 onReady 再创建组件,同时用全小写 :apikey。这是对使用者最省事的写法,但仍不如 A 稳。

12.5 自检

日志 含义
apiKey 来源=builtin 用的是插件常量 API_KEY(推荐路径)
apiKey 来源=apikey 用的是页面属性(nvue 下不保证能拿到)
WARNING 未传入 apiKey 两者都为空 → Key 为空,算路必然 code=13

十三、常见问题 FAQ

Q1:组件区域空白,只有页面背景色?

  1. 是否给了明确 height(flex:1 无效);
  2. 是否用的自定义基座;
  3. 页面是不是 nvue。

Q2:一进页面就闪退 / NoClassDefFoundError: com.amap.api...? 高德类没进包。云打包检查 config.json 的 maven 依赖并重打基座;本地打包检查 jar / so / assets。也确认不是跑在标准基座上。详见「11.5」。

Q3:地图黑屏 / 一点导航就失败(code=7)? Key 与平台身份不匹配:Android 检查「包名 + SHA1」,iOS 检查 BundleId。换基座后 SHA1 会变,Key 要同步更新。

Q4:算路一直 code=13 key非法或过期? Key 没生效(多半为空)。看日志有没有 WARNING 未传入 apiKey,按「十二」处理。

Q5:点了定位一直停在「正在定位」?

  1. 看面板/日志里的 err;
  2. 系统定位服务是否打开;
  3. 室内可能长时间拿不到坐标,可到窗边或改用持续定位等几秒;
  4. 权限被拒绝的话,去系统设置手动开启。

Q6:首次安装点「一键导航」没反应? 弹系统授权框时点「允许」即可,插件会自动继续,不需要再点一次。点了「拒绝」才需要去系统设置开启。

Q7:骑行 / 步行点了没反应? 多半是终点太远(code=19/20)。插件会自动就近,日志里有提示;也可直接把终点设在起点附近。

Q8:退出页面后语音还在播? onUnload 里调用 stopRoute()(插件在页面销毁时也会自动停止)。如果拦截了返回(onBackPress 返回 true),页面没真正销毁,就不会触发清理。

Q9:切换导航方式后导航没了? 正在导航时切换会先停止当前导航,切换后需要重新调用 startRoute*()。

Q10:@location 收到了但拿不到参数? 两端读取位置不同:Android 在 e.detail,iOS 在事件对象顶层,按 7.1 的写法兼容。

Q11:改了 Key / 改了插件代码,为什么没生效?

  • 只改 Key(常量或属性)→ 重新进页面即可;
  • 改了 uni_modules/lj-amap-nav/ 下任何文件 → 必须重打自定义基座。

十四、版本记录

v1.0.1(2026-10-19)

  • 文档合并为单一 README:原独立的 打包注意事项.md、changelog.md 内容全部并入本文(不再随插件分发多个文档)
  • 补充「本地打包 / 云打包」下 Key 配置的差异(原 changelog 条目):云打包会自动合并插件自带的 AndroidManifest.xml(含高德 Key 的 meta-data 与定位服务声明),三种 Key 方式都可用;本地(离线)打包不会自动合并,若采用「清单方式」配 Key,必须把 meta-data 手写进 AS 工程的 src/main/AndroidManifest.xml,否则表现为地图黑屏 / code=7
  • 新增「十一、打包注意事项(云打包 / 本地打包)」:maven 依赖、libs jar 说明、离线工程 so / assets 解压脚本、build.gradle、清单合并、自检清单
  • 新增「十二、Key 取不到的排查」:WARNING 未传入 apiKey / code=13 的现象、原因、无效写法与三种解法
  • Key 配置增加「写进插件常量 API_KEY」路径(日志 apiKey 来源=builtin),与属性方式并存,三种方式任选
  • Android 依赖改为纯 Maven 拉取:config.json 只保留合包坐标 com.amap.api:navi-3dmap-location-search:11.2.100_3dmap11.2.100_loc11.2.100_sea9.8.1,并删除插件内 95.8 MB 的 jar
    • 修正过一处无效坐标:com.amap.api:navi-3dmap 在 Maven Central 最高只有 10.0.800_3dmap10.0.800,没有 11.x,写 navi-3dmap:11.2.100_... 会 Could not find 构建失败
    • 收益:插件体积 96 MB → 几十 KB;APK 里不再有 assets/uni_modules/.../libs/*.jar 这份 94.6 MB 的冗余(实测 debug APK 180.6 MB → ≈86 MB)
    • 离线打包改为两种方式:AS 工程用 gradle 依赖(推荐)或手工准备 jar / so / assets,详见「11.3」

v1.0.0(首个发布版本 · 2026-10-19)

  • 三种导航方式:驾车 / 骑行 / 步行,同一组件内切换(Android / iOS 双端)
  • 半屏嵌入:按 style 指定尺寸,可与业务 UI 同屏
  • 一键导航、模拟导航、内置语音播报
  • 骑行 / 步行自动就近(骑行 20 km / 步行 5 km)
  • 单次定位 locateStart()、持续定位 startContinuousLocation(intervalMs)
  • 事件回传:@location(坐标 / 错误码 / 回调次数)、@log(运行日志)
  • 首次安装自动申请定位权限,授权后自动继续
  • 页面销毁自动停止导航、停止语音、释放定位
  • 已知限制:Android 仅 arm64-v8a、minSdkVersion 23;必须使用自定义基座;iOS 不支持后台定位

十五、许可与声明

  • 导航、地图、定位能力由高德开放平台提供,使用时须遵守《高德地图开放平台隐私权政策》及高德相关服务条款;
  • 使用前请自行在高德开放平台申请 Key,Key 的配额与安全由申请者负责。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

<uses-permission android:name="android.permission.INTERNET"/> —— 加载地图瓦片、发起算路与导航请求 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> —— 判断网络状态(高德 SDK 请求与定位辅助) <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> —— 高德定位辅助(WiFi 定位) <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> —— 高德定位辅助 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> —— 精确定位:定位、实时导航、一键导航起点 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> —— 粗略定位(精确定位不可用时的降级) <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/> —— 高德定位 SDK 内部使用 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> —— 导航/定位前台服务声明 <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/> —— 前台定位服务声明 <uses-permission android:name="android.permission.WAKE_LOCK"/> —— 导航过程中保持屏幕与定位唤醒 iOS(Info.plist 权限描述,插件已自带): NSLocationWhenInUseUsageDescription —— 使用期间获取位置,用于路线规划与实时导航 NSLocationAlwaysAndWhenInUseUsageDescription —— 导航过程中后台持续获取位置 NSLocationAlwaysUsageDescription —— 同上(兼容旧系统)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件本身不采集、不上传任何用户数据,定位与导航结果仅在本机内存中使 用,不会回传至插件作者或开发者的服务器。 插件集成的高德地图 SDK(Android:AMapNavi / AMapLocation 11.2.100; iOS:AMapNavi 11.2.100 + AMapLocation 2.12.2)为提供地图渲染、定位、 路径规划、实时导航与语音播报能力,会采集并使用以下信息,并发送至高德 的服务器(*.amap.com 域名): 1. 位置信息:经纬度、速度、方向、定位精度; 2. 设备信息:设备型号、系统版本、网络类型与状态、设备标识符等; 3. 业务请求数据:起点/终点坐标、途经点、算路与导航请求参数。 以上数据由高德 SDK 用于地图与导航服务,插件不做额外留存或二次转发。 数据收集与处理规则详见《高德地图开放平台隐私权政策》: https://lbs.amap.com/pages/privacy/

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。