1. 程式人生 > >Android6.0及以上版本申請許可權講解

Android6.0及以上版本申請許可權講解

我們先來了解一個概念

在執行時請求許可權

從 Android 6.0(API 級別 23)開始,使用者開始在應用執行時向其授予許可權,而不是在應用安裝時授予。此方法可以簡化應用安裝過程,因為使用者在安裝或更新應用時不需要授予許可權。它還讓使用者可以對應用的功能進行更多控制;例如,使用者可以選擇為相機應用提供相機訪問許可權,而不提供裝置位置的訪問許可權。使用者可以隨時進入應用的“Settings”螢幕呼叫許可權。

系統許可權分為兩類:正常許可權危險許可權

  • 正常許可權不會直接給使用者隱私權帶來風險。如果您的應用在其清單中列出了正常許可權,系統將自動授予該許可權。
  • 危險許可權會授予應用訪問使用者機密資料的許可權。如果您的應用在其清單中列出了正常許可權,系統將自動授予該許可權。如果您列出了危險許可權,則使用者必須明確批准您的應用使用這些許可權。
:從 Android 6.0(API 級別 23)開始,使用者可以隨時從任意應用呼叫許可權,即使應用面向較低的 API 級別也可以呼叫。無論您的應用面向哪個 API 級別,您都應對應用進行測試,以驗證它在缺少需要的許可權時行為是否正常。
  • 正常許可權:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
  • 危險許可權:

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS


因此,如果API 23及以上時,我們申請危險許可權時,除了在清單檔案配置,還要在程式碼中進行動態申請:

要檢查您是否具有某項許可權,請呼叫 方法。例如,以下程式碼段顯示瞭如何檢查 Activity 是否具有在日曆中進行寫入的許可權:

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);



請求許可權

如果您的應用需要應用清單中列出的危險許可權,那麼,它必須要求使用者授予該許可權。Android 為您提供了多種許可權請求方式。呼叫這些方法將顯示一個標準的 Android 對話方塊,不過,您不能對它們進行自定義。


如果應用尚無所需的許可權,則應用必須呼叫一個 方法,以請求適當的許可權。應用將傳遞其所需的許可權,以及您指定用於識別此許可權請求的整型請求程式碼。此方法非同步執行:它會立即返回,並且在使用者響應對話方塊之後,系統會使用結果呼叫應用的回撥方法,將應用傳遞的相同請求程式碼傳遞到。

接下來我們看一個例子:

以下程式碼可以檢查應用是否具備讀取使用者聯絡人的許可權,並根據需要請求該許可權:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}


處理許可權請求響應

當應用請求許可權時,系統將向用戶顯示一個對話方塊。當用戶響應時,系統將呼叫應用的 方法,向其傳遞使用者響應。您的應用必須重寫該方法,以瞭解是否已獲得相應許可權。回撥會將您傳遞的相同請求程式碼傳遞給 。例如,如果應用請求 訪問許可權,則它可能採用以下回調方法:

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}




一個請求撥打電話的小Demo

只有一個MainActivity.java,沒佈局檔案,直接上程式碼

package com.example.allan.encryption;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {
    //定義一個撥打電話許可權的請求碼
    private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        testCall();
    }

    public void testCall() {
        //檢查是否已經授予撥打電話許可權
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED) {
            //如果沒有,則顯示請求撥打電話許可權對話方塊
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.CALL_PHONE},
                    MY_PERMISSIONS_REQUEST_CALL_PHONE);
        } else {
            //否則,撥號
            callPhone();
        }
    }

    public void callPhone() {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + "10086");
        intent.setData(data);
        startActivity(intent);
    }
    //判斷許可權的結果碼
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //如果是當前申請的撥打電話許可權
        if(requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {
            //如果已經允許該許可權
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                callPhone();
            }else {
                //否則,提示該許可權已經被禁止
                Toast.makeText(this, "請授予撥打電話許可權!", Toast.LENGTH_SHORT).show();
            }
            return;
        }
    }
}

最後別忘了配置清單檔案