Skip to content

定位使用规范

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 字符)

涉及定位的表:

表名字段
assetslatitude, longitude, location_desc
activitieslatitude, longitude, location_desc
check_in_configslatitude, longitude, location_desc
check_in_recordslatitude, longitude, location_desc
album_photoslatitude, 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 的步骤

  1. 实现 LocationProvider 接口
  2. 通过 LocationService.registerProvider(provider) 注册
  3. 按需调用 LocationService.switchProvider(name) 切换主提供者
  4. CodeNoteApplication 中初始化
  5. 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}")

单次定位流程:

  1. 检查定位权限
  2. 请求 10s 超时的单次定位
  3. 获取 LocationResult
  4. 填入 DTO 后上传服务端
  5. 定位失败时返回 null,调用方自行处理(不强制阻断流程)

3.2 持续定位(地图展示)

kotlin
collect(LocationService.currentLocation) { location ->
    // 更新地图标记
}

只在地图页面使用持续定位,其他场景一律用单次定位。

3.3 权限检查(各端自行处理)

平台权限备注
AndroidACCESS_FINE_LOCATION + ACCESS_COARSE_LOCATION运行时请求
服务端无需权限仅接收客户端传入坐标
管理后台无需定位功能仅展示已有数据

4. 各端使用场景

4.1 新增资源定位

Android:资源创建页 → 自动获取定位 → 填入 CreateAssetRequest服务端:持久化到 assetslatitude/longitude/location_desc管理后台:资源详情展示经纬度和描述

4.2 活动签到定位

流程

  1. 管理后台配置签到活动时设置 CheckInConfigRequest(含锚点坐标 + 围栏半径)
  2. Android 客户端签到前调用 requestOnce() 获取定位
  3. 服务端 CheckInService 用人 haversine 计算客户端坐标与锚点距离,超过半径则拒绝
  4. 签到记录写入 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_recordslocation 字段为文本地址 Android 扫码核验:可选携带设备定位,记录到 deviceInfo


5. 坐标系统

5.1 当前规范

环节坐标系说明
高德 SDK 定位GCJ-02SDK 原生输出
服务端存储GCJ-02前端上报即存,不转换
地图展示GCJ-02高德/腾讯地图原生支持
百度地图展示需转换为 BD-09使用第三方工具类转换

5.2 坐标转换

需要引入百度/其他地图时,在客户端侧完成转换后上报 GCJ-02:

BD-09 ↔ GCJ-02 转换公式
GCJ-02 ↔ WGS84 转换公式

原则:服务端只存储 GCJ-02,所有坐标转换在客户端完成。


6. 扩展指南

6.1 新增定位 SDK 步骤

  1. 实现 LocationProvider 接口
  2. 通过 LocationService.registerProvider(provider) 注册
  3. 按需调用 LocationService.switchProvider(name) 切换
  4. CodeNoteApplication 中初始化
  5. LocationResult.provider 自动使用 providerName 字段
  6. 更新本文档

6.2 回退策略

高德定位失败时 → 自动降级到 Android 系统定位(LocationManager):

kotlin
// LocationService 中的兜底逻辑已示例,实际由 Provider 各管各的
// 方案:注册 2 个 Provider,requestOnce() 只走 primaryProvider
// 若需要多 Provider 依次尝试,外层自行编排

6.3 字段扩展

如需新增定位相关字段(如 bearing 方向):

  1. 客户端 LocationResult 追加可选字段
  2. 服务端 DTO 追加对应可选字段
  3. 数据库追加对应列(标记 DEFAULT NULL 向后兼容)
  4. Service 层透传即可
  5. 更新本文档

已扩展的字段

字段类型说明使用场景
altitudeDouble?海拔(米)水印相机(Altitudes 标记)