關於動態權限

首發於個人公衆號html

關於動態權限java

一、在給app升級動態權限以前須要注意搞清楚一下幾個概念

1.一、版本號對應的api等級

查閱官網能夠看出android

1.二、minSdkVersion、targetSdkVersion和 compileSdkVersion

這幾個屬性一般在gradle defaultConfig中去配置,做用以下shell

(1)minSdkVersion 指明應用程序運行所需的最小API level,若是系統的API level低於minSdkVersion設定的值,那麼android系統會阻止用戶安裝這個應用,若是不指明的話,默認是1,若是指明這個屬性,並在項目中使用了改與這個API level的API的話,那麼將會在編譯時報錯。 可見該屬性不只在程序安裝時起做用,並且會在項目構建時起做用apache

(2)targetSdkVersionapi

指明應用程序目標API level的一個整數,若是不設置就默認和minSdkVersion相同。這個屬性通知系統,已經針對這個目標版本測試過程序,系統沒必要使用兼容模式來讓你的應用程序向前兼容這個目標版本。 若是targetSdkVersion爲19(對應爲Android4.4),應用運行時,最高只能使用API 19的新特性。即便代碼中使用了API 23的新特性,實際運行時,也不會使用該新特性; 可見targetSdkVersion這個屬性是在程序運行時期起做用的,系統根據這個屬性決定要不要以兼容模式運行這個程序 例如,Android6.0系統增長了動態權限機制,若是爲了追時髦,盲目把你的targetSDKVersion設置爲23(6.0),那麼在須要使用權限的地方將會出現異常。爲此,在你作好動態權限申請以前,爲保障APP正常運行,你須要將目標版本設置低於23。緩存

(3)complieSdkVersionbash

compileSdkVersion僅僅是告訴Gradle使用哪一個版本的SDK編譯應用,不會被包含到apk中,徹底不影響應用的運行結果;雖然沒有影響可是網絡

即 :compileSDKVersion是和編譯器打交道的,而minSDKVersion和targetSDKVersion是和系統打交道的。app

二、如何升級app的動態權限

首先須要瞭解動態權限這個概念

2.1 動態權限

這個是在android 6.0提出的,從該版本開始,用戶實在運行時而不是應用安裝時授予或者撤銷應用權限,對應API23,這個版本最重要的變化就是權限動態管理,任何未被授予權限的邏輯均可能引發後續運行的崩潰,能夠經過adb 工具從命令行獲取權限

按組列出權限和狀態:

$ adb shell pm list permissions -d -g

授予或撤銷一項或多項權限:

$ adb shell pm [grant|revoke] ...

6.0以前的權限在AndroidMenifest聲明以後便可獲取全部權限,這樣會形成用戶會默默忍受一些沒必要要的權限,特別是通信錄,位置短信之類的比較敏感的權限,在6.0以後咱們只有在須要權限的時候纔會向用戶請求,用戶能夠選擇拒絕,新的機制較好的保護的用戶的隱私。 谷歌將權限分爲兩大類 Normal Permissions 這類權限通常不涉及用戶隱私是不須要用戶進行受權的,好比網絡訪問、藍牙(詳細權限見附錄) Dangenerous Permission 這類涉及到用戶隱私,須要用戶進行受權,好比讀取sdcard、開啓照相機、訪問通信錄等,其中危險權限是分組的,用戶以前若是已經選擇經過該組某個危險權限,主要有如下幾組(詳細權限見附錄)

  1. 身體傳感器
  2. 日曆 攝像頭
  3. 通信錄
  4. 地理位置
  5. 麥克風
  6. 電話
  7. 短信
  8. 存儲空間

2.2 權限相關API

爲了方便開發者實現權限管理,谷歌給出下面4個API

通常權限檢查須要如下三個步驟配合

一、檢查權限是否授予

//Activity.java
> public int checkSelfPermission(permission) 
複製代碼

這個是在ContextCompat類中用來判斷是否app已經獲取到某一個權限的使用權。若是返回android.content.pm.PackageManager#PERMISSION_GRANTED,則說明app被授予權限,若是返回android.content.pm.PackageManager#PERMISSION_DENIED 則說明權限被禁止授予

二、申請權限

//Activity.java
public final void requestPermissions( new String[permission1,permission2,...], requestCode)
複製代碼

這個是在ActivityCompat類以及FragmentCompat類中用來申請權限的方法

三、權限回調 用戶在系統彈窗裏面選擇之後結果會經過Activity的onRequestPermissionsResult 方法回調

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
    //繼續執行邏輯或者提示權限獲取失敗
}
複製代碼

這些方法能夠封裝在BaseActvity中

四、是否顯示權限對話框 這個是做爲輔助類

public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity, @NonNull String permission) 這個是在ActivityCompat類以及FragmentCompat類中用來判斷是否顯示權限詢問對話框。在權限申請的過程當中,若是用戶選擇容許權限使用或者在拒絕的同時又勾選了再也不詢問對話框,這2種狀況下該api就會返回false,表示再也不彈出權限詢問對話框,其中受權彈窗是不支持自定義的

這個輔助函數十分重要,當動態權限申請時候若是用戶若是用戶勾選了「再也不詢問」,那麼在執行requestPermissions( )後,onRequestPermissionsResult( )會永遠返回PERMISSION_DENIED,這樣應用本來的操做將永遠沒法執行,這是咱們不但願看到的

谷歌仍是給咱們留了一手,就是 shouldShowRequestPermissionRationale,若是返回true,應用應該彈出dialog說明申請權限的原因好比下面這種

其中第一次申請權限時候該函數默認返回false,無需告知用戶申請該權限的理由;當第一次申請被拒絕,再次申請時該函數會返回true,而且彈出的系統dialog上會有一個選擇「再也不詢問」,要是用戶勾選了該選項,則之後該函數一直會返回false。

2.3 如何適配

若是項目的targetSdkVersion < 23 運行在android 6.0及以上的系統上,會默認給與AndroidManifest.xml中申請的權限,是否是這樣就萬事大吉了呢?顯然是想多了,若是用戶在應用的權限頁面手動回收權限,將會致使應用crash

雖然系統提醒了用戶,可是仍是要取決用戶心情,所以穩妥的適配動態仍是有必要的事情。

首先targetSdkVersion小於23的應用默認授予了所申請的全部權限,因此若是你之前的APP設置的targetSdkVersion低於23,也能正常使用。等於或者大於23,則必須 request permission,不然會崩潰閃退。 下面將大體闡述一下升級動態權限步驟

(1)聲明目標版本sdk 修改build.gradle中targetSdkVersion爲23以上

(2)檢查權限申請地方並request權限 在咱們須要使用到權限的地方,檢查是否已經擁有權限,好比讀寫外置SD卡權限,咱們在寫入以前檢車是否有權限,沒有權限則申請權限

private void requestContactPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            //申請 WRITE_CONTACTS 權限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS},
                    REQUEST_CODE_WRITE_CONTACTS);
        }
    } 
複製代碼

(3)響應用戶權限回調

用戶能夠選擇allow或者deny,可能deny。回調onRequestPermissionsResult方法, 該方法相似於onActivityResult。若是是fragment,最好是使用父fragment,但不是使用ActivityCompat。建議使用getParentFragment().requestPermissions方法。

(4)根據requestCode和grandResult(受權結果)作相應處理

private void handleGrantResults(int requestCode, int[] grantResults) {
      if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
          if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              // Permission Granted 得到權限後執行xxx
          } else {
              // Permission Denied 拒絕後xx的操做。
          }
      }
  }
複製代碼

三、後話

3.一、權限申請若是用戶拒絕怎麼處理

若是用戶拒絕了核心權限一次,下次再次申請會出現再也不提醒的選項,要是選擇再也不提醒,核心權限不給獲取一些功能就沒法使用,你能夠選擇直接退出應用,或者能夠優雅點,咱們本身檢測一下是否拒絕了兩次或者以上,本身給個提示向用戶作一個交互

private void handleContactPermission() {
        if (Integer.parseInt(Build.VERSION.SDK)>=23) {
            int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
            if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
                if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                    showMessageOKCancel("You need to allow access to Contacts",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    requestContactPermission();//肯定後申請權限。
                                }
                            });
                    return;
                }
                requestContactPermission();//沒有權限的話,申請。
            }
        }
複製代碼

或者記錄用戶勾選了再也不詢問 Google提供了一個很是好的思路,詳見EasyPermissions . EasyPermissions並無存儲上一次shouldShowRequestPermissionRationale( )的返回值,而是在申請權限被拒後調用shouldShowRequestPermissionRationale( )方法,若是此時返回false則說明用戶勾選了「再也不詢問」。

兩種方式均可以做爲參考方式。

3.2 取消支持Apache http 客戶端

Android 6.0 版移除了對 Apache HTTP 客戶端的支持。若是您的應用使用該客戶端,並以 Android 2.3(API 級別 9)或更高版本爲目標平臺,請改用HttpURLConnection 類。此 API 效率更高,由於它能夠經過透明壓縮和響應緩存減小網絡使用,並可最大限度下降耗電量。要繼續使用 Apache HTTP API,您必須先在 build.gradle 文件中聲明如下編譯時依賴項: android { useLibrary 'org.apache.http.legacy' }

3.3 升級到7.0 api 24及以上

對於面向 Android 7.0 的應用,Android 框架執行的 StrictMode API 政策禁止在您的應用外部公開 file:// URI。若是一項包含文件 URI 的 intent 離開您的應用,則應用出現故障,並出現 FileUriExposedException 異常,常見的是訪問升級下載到內部sd卡,訪問手機相冊等。 網上有不少解決方案

附錄

Normal Permissions

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

Dangenerous Permission

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

###參考連接

公衆號小.jpg
相關文章
相關標籤/搜索