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服务端:持久化到 assets 表 latitude/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_records 的 location 字段为文本地址 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 标记)