高频获取定位(GPS)如何做到合规:法律、审核、系统机制与落地方案
摘要(先看结论)
- 在中国,"定位/行踪轨迹"属于敏感个人信息 ,必须满足"特定目的 + 充分必要 + 严格保护措施",并通常需要"单独同意"。 来源:《中华人民共和国个人信息保护法》第二十八条、第二十九条(节选)
敏感个人信息是一旦泄露或者非法使用,容易导致自然人的人格尊严受到侵害或者人身、财产安全受到危害的个人信息,包括......行踪轨迹......等信息。
只有在具有特定的目的和充分的必要性,并采取严格保护措施的情形下,个人信息处理者方可处理敏感个人信息。
处理敏感个人信息应当取得个人的单独同意;法律、行政法规规定处理敏感个人信息应当取得书面同意的,从其规定。
- 监管与应用商店并不会只盯"有没有申请定位权限",更关注:是否必要、是否明示目的、是否在同意前采集、是否存在"超频采集/超范围采集"。 来源:《App违法违规收集使用个人信息行为认定方法》(国信办秘字〔2019〕191 号附件,节选)
未逐一列出 App(包括委托的第三方或嵌入的第三方代码、插件)收集使用个人信息的目的、方式、范围等。
在申请打开可收集个人信息的权限,或申请收集用户身份证号、银行账号、行踪轨迹等个人敏感信息时,未同步告知用户其目的,或者目的不明确、难以理解。
征得用户同意前就开始收集个人信息或打开可收集个人信息的权限。
用户明确表示不同意后,仍收集个人信息或打开可收集个人信息的权限,或频繁征求用户同意、干扰用户正常使用。
收集个人信息的频度等超出业务功能实际需要。
- iOS 不申请"始终授权"不会导致"前台拿不到定位"。只要拿到"前台授权"仍可在前台获取定位;差异主要在"后台/被系统杀掉后能否继续拿到更新,以及系统是否会为了位置事件重新拉起应用"。 来源:Apple Core Location(定位授权要点,转述)
- "始终授权"会让定位更新在任意时间可用,并允许系统在部分更新场景下静默拉起应用处理更新。
- iOS 判断"正在使用"通常包含:前台,以及从前台切到后台的短暂时间窗口。
- 合规的"高频定位"要把"高频"压缩为用户可感知的前台短会话 ,并把后台改造为事件驱动 + 降级定位;再配齐隐私披露、开关、留存周期、脱敏与审计。
0. 先定义:什么叫"频繁访问 GPS 信息"
合规语境里,"频繁访问"通常不是指你在代码里 call 了多少次 API,而是指:
- 频繁触发权限链路:在不必要的时机申请定位权限、用户拒绝后仍频繁弹窗/干扰使用。
- 频繁/持续采集定位数据:在业务不必要时保持订阅、短间隔持续更新、后台持续运行、或把定位当作"埋点通参"长期采集。
监管文本里也会用更"可操作"的口径描述:例如"收集个人信息的频度等超出业务功能实际需要"。
来源:《App违法违规收集使用个人信息行为认定方法》第四部分第 4 项(节选)
收集个人信息的频度等超出业务功能实际需要。
1. 法律与监管:为什么 App 不能随意采集 GPS(定位)
1.1 哪些法律规则会约束定位数据采集
你在工程上做定位能力建设时,至少要把这三类规则当成"硬边界":
- 敏感个人信息:行踪轨迹属于敏感个人信息,处理需满足"特定目的 + 充分必要 + 严格保护措施",并通常需要"单独同意"。
- 最小必要与目的限定:处理个人信息要"明确合理目的、与目的直接相关、影响最小",并且"不得过度收集"。
- App 专项治理可执行口径:监管在落地层面常用《认定方法》判断是否"未明示目的方式范围、未经同意、违反必要原则、频繁征求同意、收集频度超出需要"等。
来源:《中华人民共和国个人信息保护法》第二十八条、第二十九条(节选)
敏感个人信息是一旦泄露或者非法使用,容易导致自然人的人格尊严受到侵害或者人身、财产安全受到危害的个人信息,包括......行踪轨迹......等信息。
只有在具有特定的目的和充分的必要性,并采取严格保护措施的情形下,个人信息处理者方可处理敏感个人信息。
处理敏感个人信息应当取得个人的单独同意;法律、行政法规规定处理敏感个人信息应当取得书面同意的,从其规定。
来源:《中华人民共和国个人信息保护法》第五条、第六条、第七条(节选)处理个人信息应当遵循合法、正当、必要和诚信原则,不得通过误导、欺诈、胁迫等方式处理个人信息。
处理个人信息应当具有明确、合理的目的,并应当与处理目的直接相关,采取对个人权益影响最小的方式。收集个人信息,应当限于实现处理目的的最小范围,不得过度收集个人信息。
处理个人信息应当遵循公开、透明原则,公开个人信息处理规则,明示处理的目的、方式和范围。
来源:《App违法违规收集使用个人信息行为认定方法》(节选)未逐一列出 App(包括委托的第三方或嵌入的第三方代码、插件)收集使用个人信息的目的、方式、范围等。
在申请打开可收集个人信息的权限,或申请收集用户身份证号、银行账号、行踪轨迹等个人敏感信息时,未同步告知用户其目的,或者目的不明确、难以理解。
征得用户同意前就开始收集个人信息或打开可收集个人信息的权限。
用户明确表示不同意后,仍收集个人信息或打开可收集个人信息的权限,或频繁征求用户同意、干扰用户正常使用。
收集个人信息的频度等超出业务功能实际需要。
1.2 违法违规有哪些风险,责任是什么
工程上最需要关心的不是"理论上会不会违法",而是"会不会被下架/通报/罚款/业务被叫停"。典型风险链路:
- 监管处罚与业务叫停 :包括责令改正、警告、没收违法所得、责令暂停或终止提供服务;拒不改正或情节严重会有更高额度罚款,并可能责令停业整顿、吊销许可/执照。 来源:《中华人民共和国个人信息保护法》第六十六条(节选)
违反本法规定处理个人信息......由履行个人信息保护职责的部门责令改正,给予警告,没收违法所得,对违法处理个人信息的应用程序,责令暂停或者终止提供服务;拒不改正的,并处一百万元以下罚款......
......情节严重的......并处五千万元以下或者上一年度营业额百分之五以下罚款,并可以责令暂停相关业务或者停业整顿、通报有关主管部门吊销相关业务许可或者吊销营业执照......
- 应用商店处置:被要求整改、下架、限制更新;新版本卡审,尤其是涉及后台定位/持续定位的。
- 民事与声誉风险:用户投诉、媒体曝光、舆情;成本往往比一次"技术重构"更高。
1.3 谁来检查
现实里通常是"多方并行":
- 监管侧:网信、工信、公安、市场监管等部门及其专项行动/委托检测。
- 分发侧:各 Android 应用商店的隐私合规模型与人工复核,iOS 的审核。
- 社会监督:用户投诉举报与第三方测评。
2. 他们怎么检查"频繁访问 GPS":静态 + 动态,Android + iOS 分开讲
下面这部分是为了回答一个工程常见误区:很多团队以为"只要权限弹窗时用户点了同意就行"。实际上检查方会把"权限声明、调用链路、运行时行为、数据流向、频率"一起看。
2.1 Android:应用商店与监管常见检查点
2.1.1 静态扫描(不运行 App 也能发现的)
- AndroidManifest 权限 :
ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION、ACCESS_BACKGROUND_LOCATION是否声明,是否与业务匹配。ACCESS_COARSE_LOCATION:允许获取粗略位置,通常来自基站/Wi‑Fi 等网络定位能力,精度一般在"城市/街区/几百米级"。适合"附近内容粗筛""天气/城市级推荐"等不需要精确坐标的场景。ACCESS_FINE_LOCATION:允许获取精确位置 ,通常包含 GPS 与更高精度的融合定位能力,精度可到"十米级甚至更好"。适合"导航/轨迹/到店距离/打点核验"等必须依赖精确坐标的场景。补充:在 Android 12+ 上,即使你请求的是FINE,用户也可能只授予"近似位置",因此工程上要能在"被降级到粗略"时继续工作或给出解释。ACCESS_BACKGROUND_LOCATION:允许在App 进入后台 后仍持续/定期获取位置更新(Android 10+ 把后台定位能力显式拆出来单独管控)。它通常意味着更严格的商店审核与更强的"必要性叙事",并且在 Android 11+ 上通常不能与前台定位权限一起在同一次弹窗里申请,往往需要先拿到前台定位(COARSE/FINE)再引导用户到系统页面开启后台定位。
- 后台能力痕迹:前台服务与服务类型、后台任务框架、保活组件、广播/自启动能力是否与"持续定位"组合出现。
- 第三方库代码与调用链:定位/地图/风控/广告等第三方库是否包含定位采集路径;是否存在"初始化即开启定位"的模式(例如应用启动就订阅)。
- 隐私合规文本一致性 :隐私政策与权限申请弹窗/应用内说明是否对得上。《认定方法》明确把"未逐一列出目的方式范围""申请敏感权限未同步告知目的"作为问题情形。 来源:《App违法违规收集使用个人信息行为认定方法》第二部分第 1 项、第 3 项(节选)
未逐一列出 App(包括委托的第三方或嵌入的第三方代码、插件)收集使用个人信息的目的、方式、范围等。
在申请打开可收集个人信息的权限,或申请收集用户身份证号、银行账号、行踪轨迹等个人敏感信息时,未同步告知用户其目的,或者目的不明确、难以理解。
2.1.2 动态检测(运行 App、看行为)
- 同意前是否采集 :用户尚未同意前是否已经开始拿定位/上报定位。《认定方法》将"征得同意前就开始收集"列为问题情形。 来源:《App违法违规收集使用个人信息行为认定方法》第三部分第 1 项(节选)
征得用户同意前就开始收集个人信息或打开可收集个人信息的权限。
- 频率是否超出必要 :是否以异常短间隔持续采集、是否在非业务场景仍采集。《认定方法》把"收集频度超出业务需要"列为问题情形。 来源:《App违法违规收集使用个人信息行为认定方法》第四部分第 4 项(节选)
收集个人信息的频度等超出业务功能实际需要。
- 这类规则通常不会给一个"法律意义上的固定秒数",更常见的是按"是否与场景匹配"来判断:你在没业务理由时还在持续收点,或者把"高频"开成了默认常态,就容易被认定为超出必要。
- 工程上可以用一个可解释的口径来定义"异常短/频繁"(用来对齐研发、合规、测试与自查),例如:
- 前台导航/运动轨迹 :
1~5s一次可以解释,但必须是用户显式触发、强可感知、严格限时;如果变成"进入 App 就每 1s 采一次且持续数十分钟",就很难自证必要。 - 附近/门店距离/到店推荐 :更常见是
10~60s一次或按最小位移 = 20~100m触发;如果你在列表页滑动/停留就每秒取点,通常会被视为异常。 - 后台 :原则上不做"定时高频",而用围栏/显著位置变化/区域等事件驱动;后台还每
1~5s取点几乎不可解释。
- 前台导航/运动轨迹 :
- "多少次算频繁"也很少按"单日 N 次"硬切(不同机型/系统/定位 API 自己也会合并/节流),检查更看你是否具备:
- 可审计的"触发条件"(用户动作/明确业务场景)
- 明确的"会话边界"(开始/停止/超时)
- 频率参数(采集间隔/最小位移/精度策略)与上报策略能证明"最小必要"
- 后台行为:退到后台是否仍在采集、是否通过前台服务"绕过"后台限制。
- 数据流向:抓包/代理/系统日志/行为录制,验证定位是否被上传、上传是否有脱敏、是否与声明一致。
2.1.3 额外约束:Google Play(如果上架)
Google Play 对后台定位非常明确:只有当"核心功能需要且用户显著受益"时才允许,并要求披露、隐私政策、演示视频与审批流程;不通过可能被拒、屏蔽更新或下架。
来源:Google Play(了解后台位置信息权限,节选)
只有当应用的核心功能需要时,您的应用才应请求在后台获取位置信息。
后台位置信息只有在能够让用户显著受益且与应用的核心功能相关的情况下才可使用。
您不得完全出于广告投放或数据分析目的而请求用户授予位置信息权限。
......需要在后台获取位置信息的应用必须获得批准。若未获得批准,您的应用更新可能遭到屏蔽,并且您的应用可能会从 Google Play 下架。
2.2 iOS:审核常见检查点
2.2.1 静态扫描
- Info.plist Usage Description :是否包含定位用途描述 key,且文案是否与功能一致。Apple 文档明确:缺少所需 key 时,"授权请求会立即失败"。 来源:Apple Core Location(定位授权要点,转述)
若 Info.plist 缺少所需 key,授权请求会立即失败。
- 后台定位能力开关 :是否开启了后台定位能力(例如
UIBackgroundModes里的location),是否与实际场景匹配。 - 二进制与第三方库:是否存在持续定位、后台唤醒、绕过用户感知的实现路径;第三方库的定位调用也可能成为拒审点。
下面给一组最小模板,用来对照 iOS 侧的权限声明与定位获取方式:
Info.plist:Usage Description 与后台定位能力
xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>用于提供附近门店与到店距离展示</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>用于在行程进行中持续记录轨迹(可随时关闭)</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
Swift:请求授权 + 获取经纬度 + 反向地理编码
swift
import CoreLocation
final class LocationService: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
private let geocoder = CLGeocoder()
var onLocation: ((CLLocation) -> Void)?
var onPlacemark: ((CLPlacemark) -> Void)?
var onAuthorizationChanged: ((CLAuthorizationStatus) -> Void)?
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
manager.distanceFilter = 20
}
func requestWhenInUse() {
manager.requestWhenInUseAuthorization()
}
func requestAlways() {
manager.requestAlwaysAuthorization()
}
func startUpdating() {
manager.startUpdatingLocation()
}
func stopUpdating() {
manager.stopUpdatingLocation()
}
func enableBackgroundUpdatesIfNeeded() {
manager.allowsBackgroundLocationUpdates = true
manager.pausesLocationUpdatesAutomatically = true
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
onAuthorizationChanged?(manager.authorizationStatus)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
onLocation?(location)
}
func reverseGeocode(_ location: CLLocation) {
geocoder.reverseGeocodeLocation(location) { [weak self] placemarks, _ in
guard let placemark = placemarks?.first else { return }
self?.onPlacemark?(placemark)
}
}
}
2.2.2 动态测试
- 是否"功能驱动授权" :Apple 明确建议:只在用户进入需要定位的功能时再请求授权,启动就弹窗会降低通过率与用户信任。 来源:Apple Core Location(定位授权要点,转述)
仅在用户进入"确实需要定位"的功能时再发起授权请求。
- 前后台行为是否符合你宣称的场景:例如你申请"始终授权",却无法证明后台定位的必要性;或用户不知情就持续采集。
- 定位频率与耗电影响:持续高精定位很容易在评审与用户侧"可感知"(耗电、状态栏位置指示等),并触发"为何需要"的追问。
3. 代码层面说明:Android/iOS 到底是怎么"给你定位结果"的
3.1 Android:没有后台权限会怎样
直觉理解:
- 前台:只要用户授予定位权限(精确/粗略),你在 Activity 可见期间可以拿到定位更新。
- 后台 :Android 10+ 把后台定位能力显式拆成
ACCESS_BACKGROUND_LOCATION。没有它,你很难在用户离开 App 后继续稳定获取位置(具体还取决于系统版本、厂商策略、前台服务使用方式)。
工程上的结论:如果你"业务上必须后台定位",你必须把它当成一个需要审批与强叙事的能力,而不是一个"顺便开一下权限"的实现细节。
来源:Google Play(了解后台位置信息权限,节选)
只有当应用的核心功能需要时,您的应用才应请求在后台获取位置信息。
后台位置信息只有在能够让用户显著受益且与应用的核心功能相关的情况下才可使用。
......需要在后台获取位置信息的应用必须获得批准。若未获得批准,您的应用更新可能遭到屏蔽,并且您的应用可能会从 Google Play 下架。
3.1.1 示例:前台获取一次经纬度
kotlin
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import androidx.core.content.ContextCompat
import com.google.android.gms.location.LocationServices
import com.google.android.gms.tasks.CancellationTokenSource
suspend fun getOneShotLocationOrNull(activity: android.app.Activity): Location? {
val hasFine = ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
val hasCoarse = ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
if (!hasFine && !hasCoarse) return null
val client = LocationServices.getFusedLocationProviderClient(activity)
val tokenSource = CancellationTokenSource()
return kotlinx.coroutines.tasks.await(client.getCurrentLocation(com.google.android.gms.location.Priority.PRIORITY_BALANCED_POWER_ACCURACY, tokenSource.token))
}
3.1.2 示例:订阅位置更新(经纬度)+ 反向地理编码(地理位置)
kotlin
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Geocoder
import android.location.Location
import android.os.Looper
import androidx.core.content.ContextCompat
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import java.util.Locale
fun startLocationUpdates(
context: Context,
onLocation: (Location) -> Unit,
): LocationCallback? {
val hasFine = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
val hasCoarse = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
if (!hasFine && !hasCoarse) return null
val request = LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 3_000L)
.setMinUpdateIntervalMillis(1_000L)
.setMinUpdateDistanceMeters(10f)
.build()
val client = LocationServices.getFusedLocationProviderClient(context)
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
val location = result.lastLocation ?: return
onLocation(location)
}
}
client.requestLocationUpdates(request, callback, Looper.getMainLooper())
return callback
}
fun stopLocationUpdates(context: Context, callback: LocationCallback) {
LocationServices.getFusedLocationProviderClient(context).removeLocationUpdates(callback)
}
suspend fun reverseGeocodeOrNull(context: Context, location: Location): String? {
val geocoder = Geocoder(context, Locale.getDefault())
val results = kotlinx.coroutines.Dispatchers.IO.let { dispatcher ->
kotlinx.coroutines.withContext(dispatcher) {
geocoder.getFromLocation(location.latitude, location.longitude, 1)
}
}
val address = results?.firstOrNull() ?: return null
return listOfNotNull(
address.adminArea,
address.locality,
address.subLocality,
address.thoroughfare,
address.featureName,
).joinToString("")
}
补充两点容易误解的行为差异:
- "进入后台还能不能拿到位置"不是一句话能概括,工程上看你是否仍处于"前台态":如果你启动了带定位类型的前台服务(持续通知可见),通常仍可以用
ACCESS_COARSE_LOCATION/ACCESS_FINE_LOCATION持续收点;如果没有前台服务、界面也不可见,那就是典型后台场景,Android 10+ 往往需要ACCESS_BACKGROUND_LOCATION才能稳定持续更新。 - "我不注册,我去访问经纬度就拿不到吗":不一定。你不订阅更新时,仍可能通过
getLastLocation/getCurrentLocation拿到一次"缓存/当前"位置;但如果没有定位权限(粗略/精确都没拿到),要么直接拿不到数据(返回 null/抛出安全异常),要么只能得到受限信息。
3.2 iOS:不申请"始终授权"会怎样,会不会拿不到定位
不会。
iOS 的授权层级核心是 前台授权 vs 始终授权:
- 前台授权 :定位更新"主要在用户使用应用时可用"。在 iOS 上,"使用中"通常指前台,以及从前台切到后台的短暂时间;如果启用了后台定位更新且定位服务正在运行,也可能在后台继续一段可控的运行,但如果应用被终止或未运行,系统通常不会为了持续更新而自动拉起应用。 来源:Apple Core Location(定位授权要点,转述)
iOS 判断"正在使用"通常包含:前台,以及从前台切到后台的短暂时间窗口。
- 始终授权 :允许"在任何时间"接收定位更新,并且系统在某些位置更新类型(例如显著位置变化、访问记录、区域监控)下可以"静默拉起"被终止的应用来处理事件。 来源:Apple Core Location(定位授权要点,转述)
"始终授权"会让定位更新在任意时间可用,并允许系统在部分更新场景下静默拉起应用处理更新。
所以,"不申请始终授权"在工程上的真实含义是:
- 你依然能在前台正常拿到定位。
- 你不能把"持续后台定位/被杀后继续跟踪"当成稳定能力依赖。
3.3 iOS 授权必备配置:不配 key 会发生什么
Apple 明确要求把"用途说明"写入 Info.plist,且缺失时授权请求会失败:
NSLocationWhenInUseUsageDescription:请求前台授权或始终授权时必填。NSLocationAlwaysAndWhenInUseUsageDescription:请求始终授权时必填。
来源:Apple Core Location(定位授权要点,转述)
若 Info.plist 缺少所需 key,授权请求会立即失败。
4. 一个"合规但能满足高频需求"的解决方案
这里把"频繁访问 GPS"换成一个工程可落地的目标描述:
在确有必要的业务场景下,提供"高频定位能力",但把敏感数据采集控制在最小范围,并保证用户知情可控、可验证、可止损。
4.1 总体思路:把"高频"压缩为前台短会话,把后台改为事件驱动
- 能力拆解:前台短时高频会话 + 后台事件触发 + 合规披露/开关/留存
- 前台短时高频会话:
- 必须由用户显式触发
- 界面强可感知(提示定位中/可随时停止)
- 严格限时(例如 10~60s),用完即停
- 高频只在会话内,后台一律降级
- 后台事件触发:
- 用地理围栏/区域监控/显著位置变化等"系统事件"代替持续更新
- 只在事件发生时取一次点做校验(优先粗略定位/最近一次缓存位置)
- 合规配套:
- 明示目的、频率、保存期限、共享对象、关闭方式
- 单独同意(敏感信息)与撤回通道
- 留存最短、默认不上报或脱敏后上报
4.2 流程:把"频率、精度、前后台策略"写进代码
- 空闲
- 用户进入需要定位的功能 → 说明用途与频率
- 请求授权
- 用户确认开启定位 → 发起授权请求
- 用户拒绝/取消 → 回到空闲
- 授权成功 → 进入就绪
- 就绪
- 用户触发"开始记录/导航/测距" → 进入"前台短时高频会话"
- 业务确需后台能力 → 进入"后台事件触发"
- 用户关闭定位功能/撤回同意 → 回到空闲
- 前台短时高频会话
- 达到目标/超时/用户停止 → 回到就绪
- 后台事件触发
- 业务结束/用户关闭 → 回到就绪
4.3 "高频定位"的合规参数模板
- 前台短时高频会话:
持续时长 = 10~60s,采集间隔 = 1~5s,最小位移 = 5~20m(根据场景调)。 - 后台:只允许事件驱动(围栏/区域/显著变化),禁止定时器每秒取点。
- 上报:默认不上报原始轨迹;确需上报时做栅格化/抽样/批量,保存期限按最短必要。
这些参数的合规价值在于:你能解释"为什么需要、采多少、采多久、怎么停、怎么删"。
5. 落地要点(不贴代码)
5.1 iOS:以前台授权为主 + 前台短时高频会话 + 必要时升级始终授权
- 授权策略:默认以前台授权为主;只有在明确业务需要且用户知情的情况下才申请"始终授权",并提供关闭/撤回路径。
- 会话模型:把"高频定位"限制在前台短时高频会话(10~60s),退出即停;超时自动停止,避免忘停导致后台持续采集。
- 参数约束:
desiredAccuracy/distanceFilter只在会话内拉高,非会话状态降级。 - 失败与撤回:拒绝/受限时立即停止采集并给出可理解的提示,不要循环弹窗。
- 配套声明:Info.plist 至少要有
NSLocationWhenInUseUsageDescription;若要请求"始终授权",再加NSLocationAlwaysAndWhenInUseUsageDescription。 来源:Apple Core Location(定位授权要点,转述)若 Info.plist 缺少所需 key,授权请求会立即失败。
5.2 Android:前台短时高频会话 + 用完即停(要点)
- 权限策略:优先用粗略定位满足需求,确需高精度再申请精确定位;权限不足时不采集、不兜底"静默取点"。
- 会话模型:同样用"会话 + 超时停止"约束高频,只允许用户显式触发;页面退出/用户停止就立刻
removeUpdates。 - 频率与距离:用
minTime/minDistance控制频率,不要后台定时器每秒拉点;后台改为事件驱动(围栏/显著变化/最近一次缓存位置)。 - 线程与卡顿:定位回调里只做轻量处理,复杂逻辑异步化,避免在主线程堆重活。
6. 提交前自检:把"合规"做成清单
- 是否能用"以前台授权为主 + 前台短时高频会话"满足需求?是否真的需要后台持续定位/始终授权?
- 是否做到"用户触发才采集、用完即停"?是否存在启动即采集、页面退出仍采集?
- 是否存在"同意前采集/拒绝后仍采集/频繁弹窗骚扰"? 来源:《App违法违规收集使用个人信息行为认定方法》第三部分第 1 项、第 2 项(节选)
征得用户同意前就开始收集个人信息或打开可收集个人信息的权限。
用户明确表示不同意后,仍收集个人信息或打开可收集个人信息的权限,或频繁征求用户同意、干扰用户正常使用。
- 是否存在"频度超出业务需要"? 来源:《App违法违规收集使用个人信息行为认定方法》第四部分第 4 项(节选)
收集个人信息的频度等超出业务功能实际需要。
- 是否对行踪轨迹(敏感个人信息)做到"单独同意 + 必要性说明 + 严格保护措施"? 来源:《中华人民共和国个人信息保护法》第二十八条至第二十九条(节选)
敏感个人信息是一旦泄露或者非法使用,容易导致自然人的人格尊严受到侵害或者人身、财产安全受到危害的个人信息,包括......行踪轨迹......等信息。
只有在具有特定的目的和充分的必要性,并采取严格保护措施的情形下,个人信息处理者方可处理敏感个人信息。
处理敏感个人信息应当取得个人的单独同意;法律、行政法规规定处理敏感个人信息应当取得书面同意的,从其规定。
- 是否有撤回同意/关闭入口、删除能力、留存最短必要?