Android 定位結果的 `Location.getTime()` 不一定是衛星時間

Photo by SpaceX on Unsplash 前言 最近的專案需要取定位的時間,並用該時間判斷使用者是否有在指定時間完成任務,而業主就提出希望以定位所取得的時間做為判斷依據。 然後,就發現事情沒有想像中的那麼單純。 原來目前在 Android 的定位結果中所取得的時間,只有在定位來源為純 GPS 的情況下才會是衛星所回傳的時間。 來看看究竟是怎麼一回事吧… 先認識 Location 型別 不論是使用 Android 官方推薦的 Fused Location Provider 或是 LocationManager ,定位結果所回傳的型別都是 Location。這個型別除了基本的經緯度與海拔等資訊,其中也包含定位的時間。 通常開發上指的定位時間,我們會使用 Location.getTime() 取得 Unix epoch time,再將這串數字轉成人類可閱讀的時間格式。 Unix epoch time:從 UTC 1970 年 1 月 1 日 0 時 0 分 0 秒起至現在的總秒數,不考慮閏秒。 – Wikipedia Location.getTime() 會跟定位來源有關 從 Android Doc: Location.getTime() 的說明會發現,不同的定位結果所取得的時間來源不見得相同。 當定位結果是由 LocationManager.GPS_PROVIDER 提供的時候,時間會是由衛星所提供。如果是其他的 Provider,時間來源則不一定,不過通常會是使用裝置系統的 Unix epoch time。 There is no guarantee that different locations have times set from the same clock. Locations derived from the LocationManager#GPS_PROVIDER are guaranteed to have their time originate from the clock in use by the satellite constellation that provided the fix. Locations derived from other providers may use any clock to set their time, though it is most common to use the device’s Unix epoch time system clock (which may be incorrect). ...

Published on May 27, 2023 · 2 min · 257 words · Daniel Huang

Android 取得即時定位 LocationManager

📢 除非有特殊需求,官方建議使用 Google Fused Location Provider API。 權限請求 AndroidManifest.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- 宣告定位權限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application> <!-- 略 --> </application> </manifest> 請求動態權限 因為定位屬於危險權限需要動態向使用者請求。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import android.Manifest import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts class MainActivity : AppCompatActivity() { // -----------------------Request Location Permission------------------------------ private val resultLauncherPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { if (it) { initLocationManager() } else { Toast.makeText(this, "請允許權限以開啟定位", Toast.LENGTH_SHORT).show() finish() } } // -----------------------------LifeCycle Event------------------------------------- override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 啟動時請求權限 resultLauncherPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION) } // -------------------------------------------------------------------------------- private fun initLocationManager() { Toast.makeText(this, "定位權限請求成功,準備初始化 LocationManager", Toast.LENGTH_SHORT).show() } } LocationManager 實例化 1 2 3 import android.location.LocationManager val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager 請求定位 Android S 以上支援 FUSED_PROVIDER,不過建議直接用 Android Fused Location Provider API,支援的系統版本比較廣。 ...

Published on May 24, 2023 · 2 min · 271 words · Daniel Huang