🗺️

FusedLocation - Androidで位置情報取得 -

2022/03/25に公開

概要

以前は LocationManager を使っていたが、最近は Google Play Serviceの FusedLocation を使うのが推奨されているらしい。
公式の説明を見ると、Providerどれ使うか?(GPS, wifi...)とバッテリー効率を考えて一番適した方法で位置情報を提供してくれる様子。

位置情報へのアクセスをリクエストする

アプリの権限をリクエストの基本 今一度確認

  • 権限を必要とする機能をユーザーが操作し始めたら、その状況に応じた権限をリクエストすること
  • ユーザーをブロックしないこと。権限に関連した説明を表示する UI フローは、常にキャンセルできるようにしてください
  • 機能に必要な権限をユーザーが拒否または取り消した場合は、グレースフル デグラデーションを行いアプリの使用を続けられるようにすること
  • システム動作を前提としないこと

権限の種類

  • ACCESS_FINE_LOCATION
    • GPSやWi-Fi、モバイルデータなど、利用可能な位置情報プロバイダを使用し、できる限り正確な位置情報の特定を行います
  • ACCESS_COARSE_LOCATION
    • Wi-Fiかモバイルルータ、あるいはその両方を使用し、都市の1区画程度の制度で位置情報の特定を行います

実装

まずは権限が付与されているかのチェック

    private fun getLocationPermission() {
        val permission = ContextCompat.checkSelfPermission(
            this.applicationContext,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
        if (permission == PackageManager.PERMISSION_GRANTED) {
            requestDeviceLocation()
        } else if (permission == PackageManager.PERMISSION_DENIED) {
            /* 以前ユーザーがリクエストを許可しなかった場合trueを返す
               また「今後表示しない」を選択していた場合はfalseを返す */
            if (ActivityCompat.shouldShowRequestPermissionRationale(
                    this,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            ) {
                // ここでユーザーに説明用のUIを表示する
            } else {
                val requestPermissionLauncher =
                    registerForActivityResult(
                        ActivityResultContracts.RequestPermission()
                    ) { isGranted: Boolean ->
                        if (isGranted) {
                            requestDeviceLocation()
                        } else {
                            Napier.w("Permission not granted")
                        }
                    }
                requestPermissionLauncher.launch(
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
            }
        }
    }

直近の位置情報を取得する


    @SuppressLint("MissingPermission")
    private fun requestDeviceLocation() {
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        try {
            val locationResult = fusedLocationClient.lastLocation
            locationResult.addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    val lastKnownLocation = task.result
                    if (lastKnownLocation != null) {
		        // lastKnownLocation.latitude と lastKnownLocation.longitude を使う
                    }
                } else {
                    Napier.i("Request location updates")
                    locationCallback = object : LocationCallback() {
                        override fun onLocationResult(locationResult: LocationResult) {
                            locationResult.lastLocation.also {
		                // it.latitude と it.longitude を使う
                            }
                        }
                    }
                    startLocationUpdates()
                    requestingLocationUpdates = true
                }
            }
        } catch (e: SecurityException) {
            Napier.e("SecurityException", e)
        }
    }

    @SuppressLint("MissingPermission")
    private fun startLocationUpdates() {
        locationCallback?.also {
            fusedLocationClient.requestLocationUpdates(
                LocationRequest.create().apply {
                    interval = 5000
                    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
                }, it, this.mainLooper
            )
        }
    }

    override fun onResume() {
        super.onResume()
        if (requestingLocationUpdates) {
            startLocationUpdates()
        }
    }

    override fun onPause() {
        super.onPause()
        locationCallback?.also {
            fusedLocationClient.removeLocationUpdates(it)
        }
    }

参考URL

Discussion