【Android 入門開發實戰:口罩地圖】獲取位置權限

 

【Android 入門開發實戰:口罩地圖】線上免費講義課程目錄

獲取使用者位置權限,除了要在 AndroidManifest.xml 宣告外,因為被列屬為危險權限,從 Android 6 (SDK 23)以上,需要特別額外跟使用詢問獲取,否則會因權限不足,而造成 APP 閃退。詳細權限級別,可以查閱官網文件: Manifest.permission

獲取 APP 權限方法

獲取 APP 權限,主要分成這四個部分。

checkSelfPermission

檢查我們的APP,是否獲得權限

shouldShowRequestPermissionRationale

是否要顯示更多說明解釋為何此權限對話視窗。收到 true,代表需要跟使用者顯示更多說明解釋為何此權限對話視窗,收到 false,代表不需額外顯示給使用者說明。

使用情境:

  • 第一次詢問權限,這個值會收到 false。
  • 第一次詢問,用戶選擇「拒絕」,這個值會收到 true。則需要顯示客制對話視窗,在視窗中解釋為何需要此權限。
  • 用戶允許權限後或是選擇「拒絕且不在詢問」後,這個值會收到 false。

requestPermissions

要求用戶給我們APP使用權限

onRequestPermissionsResult

覆寫此方法,要求權限後,會收到用戶決定是否給權限的結果 CallBack

AndroidManifest.xml

獲取位置權限,需要先在 AndroidManifest.xml 裡,加入此宣告。位置權限有兩種,一個是概略位置存取權(ACCESS_COARSE_LOCATION)和另一個精確位置存取(ACCESS_FINE_LOCATION),擇一即可,我們選擇精確定位權限。

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

MapActivity.kt

我們先新開一個空白的 Activity 頁面,檔名為 MapActivity,並在 AndroidManifest.xml 裡將啟動載入Activity,更改為此 Activity。

<activity android:name=".MapActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

檢查有無權限

透過 checkSelfPermission 方法,檢查有無精準位置(ACCESS_FINE_LOCATION)權限,若沒有則詢問使用者要求獲取權限,若獲得 locationPermissionGranted 設定為 true。

private var locationPermissionGranted = false

...
...
...

private fun getLocationPermission() {
    //檢查權限
    if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED
    ) {
        //已獲取到權限
        Toast.makeText(this, "已獲取到位置權限,可以準備開始獲取經緯度", Toast.LENGTH_SHORT).show()
        locationPermissionGranted = true
        //todo checkGPSState()
    } else {
        //詢問要求獲取權限
        requestLocationPermission()
    }
}

詢問要求獲取權限

private fun requestLocationPermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(
            this, Manifest.permission.ACCESS_FINE_LOCATION
        )
    ) {
        AlertDialog.Builder(this)
            .setMessage("此應用程式,需要位置權限才能正常使用")
            .setPositiveButton("確定") { _, _ ->
                ActivityCompat.requestPermissions(
                    this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                    REQUEST_LOCATION_PERMISSION
                )
            }
            .setNegativeButton("取消") { _, _ -> requestLocationPermission() }
            .show()
    } else {
        ActivityCompat.requestPermissions(
            this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION
        )
    }
}

處理權限 CallBack

override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<out String>, grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)

    when (requestCode) {
        REQUEST_LOCATION_PERMISSION -> {
            if (grantResults.isNotEmpty()) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //已獲取到權限
                    locationPermissionGranted = true
                    //todo checkGPSState()
                } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    if (!ActivityCompat.shouldShowRequestPermissionRationale(
                            this,
                            Manifest.permission.ACCESS_FINE_LOCATION
                        )
                    ) {
                        //權限被永久拒絕
                        Toast.makeText(this, "位置權限已被關閉,功能將會無法正常使用", Toast.LENGTH_SHORT).show()

                        AlertDialog.Builder(this)
                            .setTitle("開啟位置權限")
                            .setMessage("此應用程式,位置權限已被關閉,需開啟才能正常使用")
                            .setPositiveButton("確定") { _, _ ->
                                val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                                startActivityForResult(intent, REQUEST_LOCATION_PERMISSION)
                            }
                            .setNegativeButton("取消") { _, _ -> requestLocationPermission() }
                            .show()
                    } else {
                        //權限被拒絕
                        Toast.makeText(this, "位置權限被拒絕,功能將會無法正常使用", Toast.LENGTH_SHORT).show()
                        requestLocationPermission()
                    }
                }
            }
        }
    }
}

處理設定回來 CallBack

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        REQUEST_LOCATION_PERMISSION -> {
            getLocationPermission()
        }
    }
}

輸出結果

第一次呈現詢問畫面

若在第一次詢問,選擇「拒絕」,則會出現,我們自定義的對話視窗,可以在這個視窗跟用戶說明為何需要權限。

若是選擇「拒絕且不在詢問」,將不會在出現詢問視窗

參考資料

Build location-aware apps
https://developer.android.com/training/location

Request App Permissions
https://developer.android.com/training/permissions/requesting

permissions API reference page
https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION

Location Data
https://developers.google.com/maps/documentation/android-sdk/location

Select Current Place and Show Details on a Map
https://developers.google.com/maps/documentation/android-sdk/current-place-tutorial

程式碼範例

範例名稱:獲取位置權限
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載

這個網誌中的熱門文章

16天記下7000單字

2023 最新入門零基礎 Kotlin教學【從零開始學 Kotlin 程式設計】Kotlin 教學課程目錄 (Android Kotlin, IntelliJ IDEA, Android Studio, Android APP 開發教學)

2022 最新入門零基礎 Flutter教學 【Flutter 程式設計入門實戰 30 天】Flutter 教學課程目錄 (IntelliJ IDEA 開發教學)

nano 文字編輯器

【從零開始學 Flutter 程式設計】SharedPreferences 設定檔資料存取