外观
定位使用规范
1. 定位数据模型
1.1 客户端定位结果(Android)
kotlin
data class LocationResult(
val latitude: Double,
val longitude: Double,
val coordinateSystem: CoordinateSystem = CoordinateSystem.GCJ02,
val address: String = "",
val provider: String = "amap", // 定位SDK名称:amap / baidu / system
val timestamp: Long = System.currentTimeMillis(),
val accuracy: Float? = null, // 精度(米),SDK支持时提供
val altitude: Double? = null // 海拔(米),SDK支持时提供
)
enum class CoordinateSystem {
WGS84, // GPS原生坐标
GCJ02, // 火星坐标系(高德/腾讯)
BD09 // 百度坐标系
}1.2 服务端 DTO 字段规范
所有涉及定位的 DTO 必须遵循以下三元组:
kotlin
val latitude: Double? // 纬度(统一使用 GCJ-02)
val longitude: Double? // 经度(统一使用 GCJ-02)
val locationDesc: String? // 地址描述(逆地理编码结果)涉及定位的 DTO 清单:
| DTO | 使用场景 | 额外字段 |
|---|---|---|
CreateAssetRequest | 新增资源定位 | - |
CreateAlbumPhotoRequest | 相册拍摄定位 | altitude(可选) |
CreateActivityRequest | 活动创建定位 | - |
CheckInRequest | 签到现场定位 | - |
CheckInConfigRequest | 签到围栏锚点定位 | - |
1.3 数据库存储规范
涉及定位的实体字段:
sql
latitude DOUBLE DEFAULT NULL, -- 纬度(GCJ-02)
longitude DOUBLE DEFAULT NULL, -- 经度(GCJ-02)
location_desc VARCHAR(200) DEFAULT NULL -- 地址描述(VARCHAR 限制 200 字符)涉及定位的表:
| 表名 | 字段 |
|---|---|
assets | latitude, longitude, location_desc |
activities | latitude, longitude, location_desc |
check_in_configs | latitude, longitude, location_desc |
check_in_records | latitude, longitude, location_desc |
album_photos | latitude, longitude, location_desc |
2. 定位 SDK 接入
2.1 通用接口(LocationProvider)
客户端定位通过 LocationProvider 接口抽象,各 SDK 各自实现:
kotlin
interface LocationProvider {
/** 定位SDK名称 */
val providerName: String
/** 单次定位 */
fun requestOnce(): Flow<LocationResult>
/** 持续定位 */
val currentLocation: StateFlow<LocationResult?>
/** 释放资源 */
fun destroy()
}2.2 当前实现
高德定位 SDK(AmapLocationProvider)
严格按照官方文档实现:https://lbs.amap.com/api/android-location-sdk/guide/android-location/getlocation
- 位置:
core/common/location/AmapLocationProvider.kt - 定位模式:
Hight_Accuracy(GPS + 网络,优先返回最高精度结果) - 获取方式:
setOnceLocation(true)+setOnceLocationLatest(true)— 单次定位,返回最近 3s 内精度最高的结果 - 超时:
setHttpTimeOut(20000)— 20 秒(官方建议不低于 8000ms) - 输出坐标系:GCJ-02(官方文档说明:国内始终返回高德类型坐标)
- 地址信息:
isNeedAddress = true,GPS 定位不返回地址(官方文档说明),地址/描述均为空时降级为坐标字符串 - Key 无效退化处理:AMap Key 被拒绝时 SDK 降级到 Android 系统定位,返回 WGS-84 坐标。代码自动检测(
address/description均为空)并执行 WGS-84 → GCJ-02 偏移转换 + Android Geocoder 逆地理编码 - 隐私合规:
updatePrivacyShow/updatePrivacyAgree在构造时调用
2.3 新增 SDK 的步骤
- 实现
LocationProvider接口 - 通过
LocationService.registerProvider(provider)注册 - 按需调用
LocationService.switchProvider(name)切换主提供者 - 在
CodeNoteApplication中初始化 LocationResult.provider自动使用providerName字段
3. 调用范式
3.1 单次定位(推荐)
kotlin
// Collect 一次获取
val result = LocationService.requestOnce().firstOrNull()
// 使用
CreateAssetRequest(
latitude = result?.latitude,
longitude = result?.longitude,
locationDesc = result?.address
)
// 可选的元信息
Log.d("LocationTag", "provider=${result?.provider}, coords=${result?.coordinateSystem}, acc=${result?.accuracy}")单次定位流程:
- 检查定位权限
- 请求 10s 超时的单次定位
- 获取
LocationResult - 填入 DTO 后上传服务端
- 定位失败时返回
null,调用方自行处理(不强制阻断流程)
3.2 持续定位(地图展示)
kotlin
collect(LocationService.currentLocation) { location ->
// 更新地图标记
}只在地图页面使用持续定位,其他场景一律用单次定位。
3.3 权限检查(各端自行处理)
| 平台 | 权限 | 备注 |
|---|---|---|
| Android | ACCESS_FINE_LOCATION + ACCESS_COARSE_LOCATION | 运行时请求 |
| 服务端 | 无需权限 | 仅接收客户端传入坐标 |
| 管理后台 | 无需定位功能 | 仅展示已有数据 |
4. 各端使用场景
4.1 新增资源定位
Android:资源创建页 → 自动获取定位 → 填入 CreateAssetRequest服务端:持久化到 assets 表 latitude/longitude/location_desc管理后台:资源详情展示经纬度和描述
4.2 活动签到定位
流程:
- 管理后台配置签到活动时设置
CheckInConfigRequest(含锚点坐标 + 围栏半径) - Android 客户端签到前调用
requestOnce()获取定位 - 服务端
CheckInService用人haversine计算客户端坐标与锚点距离,超过半径则拒绝 - 签到记录写入
check_in_records表
4.3 相册水印定位
Android:拍摄照片后 → 获取定位 → 写入照片 EXIF + AlbumPhoto 记录 水印:locationDesc 写入图片水印文字(如"拍摄于 XX 街道")
4.4 水印相机(规划中)
与相册相同的数据通道,需额外处理:
- 实时定位叠加到相机取景预览
- 定位写入图片 EXIF(AGPS 数据)
locationDesc渲染为图片上角水印文字- 海拔:
LocationResult.altitude渲染到水印文字(可选开关控制显示) - 手动重新定位:水印相机顶部操作栏提供重新定位按钮(
Icons.Default.MyLocation),点击后清空定位/天气缓存并重新请求,预览 UI 同步更新
4.5 通行证核验定位
管理后台:通行证使用记录 pass_usage_records 的 location 字段为文本地址 Android 扫码核验:可选携带设备定位,记录到 deviceInfo
5. 坐标系统
5.1 当前规范
| 环节 | 坐标系 | 说明 |
|---|---|---|
| 高德 SDK 定位 | GCJ-02 | SDK 原生输出 |
| 服务端存储 | GCJ-02 | 前端上报即存,不转换 |
| 地图展示 | GCJ-02 | 高德/腾讯地图原生支持 |
| 百度地图展示 | 需转换为 BD-09 | 使用第三方工具类转换 |
5.2 坐标转换
需要引入百度/其他地图时,在客户端侧完成转换后上报 GCJ-02:
BD-09 ↔ GCJ-02 转换公式
GCJ-02 ↔ WGS84 转换公式原则:服务端只存储 GCJ-02,所有坐标转换在客户端完成。
6. 扩展指南
6.1 新增定位 SDK 步骤
- 实现
LocationProvider接口 - 通过
LocationService.registerProvider(provider)注册 - 按需调用
LocationService.switchProvider(name)切换 - 在
CodeNoteApplication中初始化 LocationResult.provider自动使用providerName字段- 更新本文档
6.2 回退策略
高德定位失败时 → 自动降级到 Android 系统定位(LocationManager):
kotlin
// LocationService 中的兜底逻辑已示例,实际由 Provider 各管各的
// 方案:注册 2 个 Provider,requestOnce() 只走 primaryProvider
// 若需要多 Provider 依次尝试,外层自行编排6.3 字段扩展
如需新增定位相关字段(如 bearing 方向):
- 客户端
LocationResult追加可选字段 - 服务端 DTO 追加对应可选字段
- 数据库追加对应列(标记
DEFAULT NULL向后兼容) - Service 层透传即可
- 更新本文档
已扩展的字段:
| 字段 | 类型 | 说明 | 使用场景 |
|---|---|---|---|
altitude | Double? | 海拔(米) | 水印相机(Altitudes 标记) |