自 Android 6.0 Marshmallow 起,Android 採用權限模型,可簡化應用程式安裝和自動更新程序。系統會在執行階段要求權限,而非在安裝應用程式前。此外,使用者可以選擇拒絕授予特定權限。 如要提供這項彈性,您必須確保使用者啟用或停用特定權限時,應用程式的行為符合預期。
Google Play 服務本身具有執行階段權限,使用者可以選擇拒絕這些權限,與應用程式要求的權限分開處理。Google Play 服務會自動取得支援 API 所需的所有權限。不過,應用程式仍應視需要檢查及要求執行階段權限,並在使用者拒絕 Google Play 服務存取應用程式所用 API 的必要權限時,適當處理錯誤。
建議您在設定執行階段可能需要的權限時,管理使用者的期望。下列最佳做法有助於避免潛在問題。
必要條件
您需要在 AndroidManifest.xml
檔案中宣告權限。
例如:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
指南規範
呼叫 API 前先驗證權限
在 AndroidManifest.xml
檔案中宣告要使用的 API 後,請先確認您擁有必要權限,再呼叫 API。您可以使用 ActivityCompat
或 ContextCompat
的 checkSelfPermission
方法完成這項操作。
如果呼叫傳回 false,表示權限未獲授予,您應使用 requestPermissions
要求權限。這個問題的回覆會透過回呼傳回,您會在下一個步驟中看到。
例如:
Kotlin
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Request Permissions Now ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION_CODE) } else { // permission has been granted, continue as usual val locationResult = LocationServices .getFusedLocationProviderClient(this /* Context */) .lastLocation }
Java
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Request Permissions Now ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION_CODE); } else { // permission has been granted, continue as usual TasklocationResult = LocationServices .getFusedLocationProviderClient(this /** Context */) .getLastLocation(); }
導入要求權限回呼
如果使用者尚未授予應用程式所需的權限,請呼叫 requestPermissions
方法,要求使用者授予權限。使用者回覆會擷取到 onRequestPermissionsResult
回呼中。應用程式應實作這項功能,並一律檢查傳回值,因為要求可能會遭到拒絕或取消。您也可以一次要求及檢查多項權限,但下列範例只檢查單一權限。
Kotlin
fun onRequestPermissionsResult( requestCode: Int, permissions: Array, grantResults: IntArray ) { if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) { if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) { // We can now safely use the API we requested access to val locationResult: Task = LocationServices .getFusedLocationProviderClient(this /* Context */) .lastLocation // Request the last known location. } else { // Permission was denied or request was cancelled } } }
Java
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) { if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // We can now safely use the API we requested access to TasklocationResult = LocationServices .getFusedLocationProviderClient(this /** Context */) .getLastLocation(); // Request the last known location. } else { // Permission was denied or request was cancelled } } }
顯示權限說明
如果應用程式要求的權限是核心功能所必需,且使用者先前已拒絕權限要求,應用程式應先顯示額外說明,再重新要求權限。如果使用者瞭解應用程式需要權限的原因,以及授予權限後可立即獲得的好處,就更可能授予權限。
在這種情況下,您應先呼叫 shouldShowRequestPermissionRationale
,再呼叫 requestPermissions
。如果傳回 true,您應建立一些 UI,顯示權限的其他背景資訊。
舉例來說,您的程式碼可能如下所示:
Kotlin
private const val REQUEST_LOCATION_PERMISSION_CODE = 2 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Check Permissions Now if ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) { // Display UI and wait for user interaction } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION_CODE) } } else { // Permission has already been granted, continue as usual val locationResult: Task= LocationServices .getFusedLocationProviderClient(this /* Context */) .lastLocation }
Java
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Check Permissions Now private static final int REQUEST_LOCATION_PERMISSION_CODE = 2; if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Display UI and wait for user interaction } else { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.LOCATION_FINE}, REQUEST_LOCATION_PERMISSION_CODE); } } else { // permission has been granted, continue as usual TasklocationResult = LocationServices .getFusedLocationProviderClient(this /** Context */) .getLastLocation(); }
Google Play 服務 API 呼叫會自動顯示對話方塊 (如果用戶端是使用 Activity
例項化),或是系統匣通知 (如果用戶端是使用 Context
例項化),使用者可以輕觸這些項目來啟動權限解決意圖。通話會排入佇列,並在授予權限後重試。