Flutter定位开发实战:权限申请、坐标转换与地址解析完整流程
·
最近在做一个 Flutter 项目,需要实现:
- 获取用户当前位置
- 展示当前位置名称
- 支持 iOS 和 Android
- 用户拒绝授权时能够降级处理
刚开始以为很简单:
Geolocator.getCurrentPosition()
结果真正落地后才发现,定位功能远比想象中复杂:
- Android 和 iOS 权限配置不同
- 用户可能拒绝定位授权
- 国内地图坐标系和 GPS 坐标系不一致
- API Key 不能直接写进客户端
- 定位失败时需要有降级方案
本文把完整实现流程记录下来。
一、项目依赖
dependencies:
flutter:
sdk: flutter
geolocator: ^10.1.0
permission_handler: ^11.0.1
http: ^1.1.0
flutter pub get
二、配置定位权限
Android
android/app/src/main/AndroidManifest.xml
<manifest>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
</manifest>
如果是骑手、轨迹追踪等场景,可以额外增加:
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
普通 App 不建议申请后台定位。
iOS
ios/Runner/Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>用于获取当前位置信息</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>用于持续获取位置服务</string>
这里漏配置是最常见的问题之一。
很多人遇到:
定位无响应
实际上是权限描述没有配置。
三、封装定位服务
创建:
lib/utils/location_service.dart
import 'package:flutter/foundation.dart';
import 'package:geolocator/geolocator.dart';
class LocationService {
static Future<Position?> getCurrentPosition() async {
final serviceEnabled =
await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
await Geolocator.openLocationSettings();
return null;
}
LocationPermission permission =
await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission =
await Geolocator.requestPermission();
}
if (
permission == LocationPermission.denied ||
permission == LocationPermission.deniedForever
) {
await Geolocator.openAppSettings();
return null;
}
try {
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: const Duration(seconds: 8),
);
} catch (e) {
debugPrint('定位失败: $e');
return null;
}
}
}
四、为什么定位成功了地图还会偏移?
这是国内定位开发最容易踩的坑。
很多开发者拿到经纬度后直接使用
position.latitude
position.longitude
然后发现:
地图标点偏移
位置不准确
原因是:
GPS原始坐标:WGS84
国内地图坐标:
GCJ02
两者并不一致。
在国内地图场景中,建议统一转换为 GCJ02 后再进行展示和计算。
五、为什么坐标转换要放后端?
很多项目喜欢:
客户端直接请求地图服务
这样虽然开发快,但有一个问题:
API Key暴露
只要别人反编译 APK:
Key直接泄露
后续可能产生大量盗刷。
因此推荐:
Flutter
↓
业务后端
↓
位置服务
统一由后端代理调用。
六、后端实现坐标转换与逆地理编码
Node.js 示例:
require('dotenv').config()
const express = require('express')
const axios = require('axios')
const app = express()
app.use(express.json())
统一请求头:
const LTS_HEADERS = {
Authorization: `Bearer ${process.env.LTS_API_KEY}`,
'Content-Type': 'application/json',
}
接口:
app.post('/api/location/resolve', async (req, res) => {
const { lat, lng } = req.body
try {
const convRes = await axios.post(
'https://lts.maiyun.net/api/service/geoconv',
{
from: 0,
points: [{ lat, lng }]
},
{
headers: LTS_HEADERS
}
)
if (
convRes.data.result !== 1 ||
!convRes.data.list?.length
) {
throw new Error('坐标转换失败')
}
const gcj02 = convRes.data.list[0]
const geoRes = await axios.post(
'https://lts.maiyun.net/api/service/geocode',
{
from: 3,
point: {
lat: gcj02.lat,
lng: gcj02.lng
}
},
{
headers: LTS_HEADERS
}
)
res.json({
gcj02Lat: gcj02.lat,
gcj02Lng: gcj02.lng,
address:
geoRes.data.address?.name ?? ''
})
} catch (e) {
res.status(500).json({
error: '位置解析失败'
})
}
})
七、定位失败怎么办?
真实用户环境里
关闭GPS
拒绝授权
系统限制
弱网环境
都可能导致定位失败。
因此建议增加降级策略。
例如:
GPS定位失败
↓
IP粗略定位
↓
用户手动选择位置
不要把定位成功率完全押在 GPS 上。
八、Flutter调用后端
final result =
await ApiService.resolveLocation(
position.latitude,
position.longitude,
);
获取返回结果:
setState(() {
_lat =
(result['gcj02Lat'] as num).toDouble();
_lng =
(result['gcj02Lng'] as num).toDouble();
_address =
result['address'] ?? '';
});
注意:
as num
不要直接:
as double
否则后端返回整数时容易出现:
type int is not a subtype of double
九、几个真实踩坑记录
| 问题 | 原因 | 解决方案 |
|---|---|---|
| iOS定位无响应 | Info.plist缺权限描述 | 补齐NSLocation字段 |
| Android无法定位 | Manifest缺权限声明 | 增加ACCESS_FINE_LOCATION |
| 地图标点偏移 | WGS84直接展示 | 转GCJ02 |
| 定位一直等待 | 没设置超时 | 增加timeLimit |
| API被盗刷 | Key写在客户端 | 后端代理 |
| 定位失败白屏 | 没做降级 | 增加IP定位和手动选择 |
十、总结
一个看似简单的定位功能,实际涉及:
- 权限管理
- 系统兼容
- 坐标转换
- 地址解析
- 接口安全
- 异常降级
真正上线后,往往不是定位接口本身最耗时间,而是各种边界情况处理。
本文示例中使用的位置服务接口完成坐标转换和逆地理编码,同类能力在地图服务平台中都比较常见。选择时重点关注:
- 坐标转换支持情况
- 逆地理编码准确率
- 接口稳定性
- 调用成本
把这些基础能力做好之后,附近门店、轨迹记录、顺风车、配送、骑手定位等场景基本都能顺利落地。
更多推荐
所有评论(0)