在 Hybrid WebView 中用 AMap.Geolocation 触达系统原生定位

一、为何没有采用高德 Android 原生定位 SDK?

我的项目架构是 Hybrid:Android 外壳 + 内嵌 WebView 跑前端页面。
起初我考虑直接集成 高德 Android 定位 SDK,但这意味着:

  • 需要原生开发经验(权限、前台服务、生命周期、功耗策略等);
  • 轨迹、UI、上传等逻辑得在原生与 Web 双端同步维护,复杂度高。

因此我转向了高德 JS SDK(AMap.Geolocation)
Web 端负责定位与轨迹逻辑,但运行环境放在 Android WebView 内,并且 为 WebView 正确授予系统定位权限。这样 AMap.Geolocation 就会走 系统原生定位通道,而不是传统的 IP/浏览器定位,无需额外集成原生定位 SDK

二、AMap.Geolocation 的多源融合

要理解 Hybrid 模式下为什么能精确定位,先看一下官方文档中对 AMap.Geolocation 的描述:
Geolocation说明

简单来说,AMap.Geolocation 内部有三层定位逻辑:

浏览器定位(HTML5 Geolocation)
高精度 IP 定位(PC 默认优先)
Android 原生定位(Hybrid 辅助)

而只要 WebView 本身获得了系统定位权限,高德 JS SDK 就会自动调用原生定位接口返回真实的经纬度数据。

三、项目实战:行迹记录功能中的 Hybrid 定位集成

下面结合我的项目代码,展示整个方案的具体实现。

3.1 Web 前端:调用高德 JS SDK 获取定位与轨迹

Web 端通过 Vue 组件封装了一个“行迹记录”页面,在用户点击“开始记录”后,会启动定时获取定位点,并用 AMap.Polyline 连接成轨迹线。

1
2
3
4
5
6
7
8
9
10
AMap.plugin('AMap.Geolocation', function () {
const geolocation = new AMap.Geolocation({
enableHighAccuracy: true, // 启用高精度模式
timeout: 5000, // 超时时间
zoomToAccuracy: true, // 定位成功后自动调整视野
position: 'RB' // 定位按钮位置
});

map.addControl(geolocation);
});

通过定时调用 getCurrentPosition(),将所有点保存到数组中,并绘制轨迹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
getLocation() {
mapGeoLocation.getCurrentPosition((status, result) => {
// this.toast(status)
if (result.status !== 0) {
window.$message.error('定位失败:' + result.message)
return
}

let position = result.position; // [lng, lat]
this.paths.push(position)

if (this.paths.length === 1) {
this.addStartPointMarker(this.paths[0])
} else {
let p1 = this.paths[this.paths.length - 2]
let p2 = this.paths[this.paths.length - 1]
this.addPolyline(p1, p2)
let distance = AMap.GeometryUtil.distance(p1, p2);
this.total_length += distance
}
});
},

3.2 Android 原生层:授权 WebView 使用系统定位

Web 页面能否成功定位,关键在于 原生层要先为 WebView 打开定位能力。

1
2
3
4
5
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false); // 授权网页调用定位
super.onGeolocationPermissionsShowPrompt(origin, callback);
}

同时需要申请系统级定位权限:

1
2
3
4
5
6
7
8
9
private void requestLocationPermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
}, 1);
}
}

并在 WebSettings 中开启地理定位支持:

1
2
3
4
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setGeolocationEnabled(true);

这样,Web 页面内的高德定位请求就能获得系统级授权。

3.3 JS 与原生的桥接:Hybrid 通信接口

在原生中通过 addJavascriptInterface 暴露接口;

1
webView.addJavascriptInterface(new WebAppInterface(), "Android");
1
2
3
4
5
6
7
8
9
10
11
12
class WebAppInterface {
@JavascriptInterface
public void requestLocationPermission() {
MainActivity.this.requestLocationPermission();
}

@JavascriptInterface
public void keepScreenOn() {
runOnUiThread(() ->
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
}
}

在前端调用:

1
2
3
4
if (window.Android) {
window.Android.requestLocationPermission()
window.Android.keepScreenOn()
}

获取定位权限

参考文档

高德地图JS API文档 —— Geolocation)
Android WebView 官方指南