ANDROID CORE · 111
Manifest / Runtime Permission / Location:不是「有寫 permission 就有 GPS」
Location 是多層問題:Manifest 宣告、runtime grant、provider 狀態、device sensor/network、accuracy、timestamp、lifecycle。正確設計要把每一層的 state 與 evidence 分開。
Learning outcomes
- 能區分 manifest declaration 與 runtime permission state。
- 能把 permission flow 當 state machine,而不是一次性 popup。
- 能保存 location accuracy / timestamp 等 evidence。
- 能區分 permission failure、provider failure、poor-quality location。
1. Manifest 是 capability declaration,不是 runtime grant
<uses-permission
android:name=
"android.permission.ACCESS_FINE_LOCATION"
/>這表示 app 宣告可能使用該 capability;是否在 runtime 被允許,仍要依 permission model 與使用者決定。
2. Permission 是 state
sealed interface
LocationPermissionState {
data object Unknown :
LocationPermissionState
data object Granted :
LocationPermissionState
data object Denied :
LocationPermissionState
data object
NeedsRationale :
LocationPermissionState
}
實際 Android API / UI flow 依平台版本與 app target 而不同,但設計上不要只保留一個 hasPermission: Boolean 就假裝所有情境相同。
3. 請求 permission 必須由明確 user action/context 驅動
不要在 app 啟動時無脈絡地一次要求所有 permissions。
4. Location update 不只有 lat/lng
data class
LocationSample(
val latitude: Double,
val longitude: Double,
val accuracyMeters: Float?,
val speedMps: Float?,
val timestampMs: Long
)
室內、多路徑反射、省電策略、provider 狀態,都可能讓座標或速度品質不同。至少保留 accuracy / timestamp 才有 debugging evidence。
5. Data flow
Permission state
↓
Location provider
↓
LocationSample
↓ validate quality
TripRepository / Domain
↓
TripState
↓
ViewModel
↓
UI
fare / distance business rule 不應直接綁死在 Android location callback 裡,否則難測也難重播。
6. Poor location ≠ Permission denied
| 現象 | 可能 evidence |
|---|---|
| Permission denied | runtime permission result |
| Provider off/unavailable | provider/settings state |
| 有座標但飄移 | accuracy、timestamp、速度跳動 |
| 更新太慢 | request interval / device power / provider behavior |
| 背景停止 | lifecycle / background execution policy |
7. Project checkpoint:Trip Meter Android Shell v2
fun onStartTrip() {
when (
permissionState
) {
Granted ->
startLocation()
NeedsRationale ->
showExplanation()
Denied,
Unknown ->
requestPermission()
}
}
真正 location callback 再轉成 domain LocationSample,讓計程邏輯可以脫離裝置重播測試。
8. Background location / execution
這一塊受 Android 版本、target SDK、foreground service 與平台政策持續影響。教材只建立 architecture mental model;實作時必須再查當前 Android 官方文件,不能把舊規則硬編成永遠有效。
9. Android 12+:Approximate / Precise 是使用者選擇
在 Android 12(API 31)以上,app 即使要求 precise location,使用者仍可以只授予 approximate location。若功能確實需要 precise access,runtime request 應同時包含 ACCESS_COARSE_LOCATION 與 ACCESS_FINE_LOCATION,並且 UI/logic 必須能接受只拿到 coarse 的結果。
Precise choice
→ FINE + COARSE granted
Approximate choice
→ COARSE granted only
因此「Manifest 有 FINE」或「程式 request FINE」都不等於 runtime 一定得到 precise location。
10. Foreground / Background Location 要分階段
Foreground location 與 background location 不是一次全部要求的 permission bundle。對 Android 11+ target,應先建立 foreground access,再在真正需要背景功能時個別導引 background permission;同時要求 foreground + background 的 flow 會被系統拒絕。
User uses foreground feature
↓
request COARSE / FINE
↓ foreground granted
Later, user enables background feature
↓
request background access separately
背景定位還牽涉 foreground service、target SDK 與平台政策;不要把「有 background permission」簡化成「任何時候都能任意啟動定位」。
11. Last known location ≠ Current location
getLastLocation() 很快、耗電低,但結果可能很舊;需要「現在」的位置時,應把 timestamp/accuracy 納入判斷,必要時使用 getCurrentLocation() 取得較新的估計。
LocationSample
latitude
longitude
accuracy
timestamp / elapsed realtime
provider/source context
所以 Debug 流程應先問「sample 多舊?accuracy 多差?」而不是看到有 lat/lon 就直接接受。
12. Android 14+ 的 location foreground service boundary
長時間 navigation / location sharing 若使用 foreground service,現代 Android 還要求正確的 foreground service type 與對應 permission。以 Android 14 target 為例,location foreground service 要宣告 android:foregroundServiceType="location" 與對應的 foreground-service permission,而且 while-in-use location restrictions 仍然存在。
因此「Manifest location permission + startForeground()」不是完整條件;實作時必須一起檢查 target SDK、FGS type、runtime location grant、app 是否在允許啟動的位置與背景狀態。
Knowledge check
- Manifest 宣告與 runtime grant 差在哪?
- 為什麼 location sample 要保留 accuracy/timestamp?
- 設計一個 permission denied 但 app 仍可使用其他功能的 UI state。
- 收到「室內定位跳動」時,你會蒐集哪四種 evidence?