1. 程式人生 > >Android開發——Android 6.0許可權管理機制詳解

Android開發——Android 6.0許可權管理機制詳解

0.前言

最近在研究所實習,我負責維護Android手機取證專案的Android客戶端,有客戶反映我們的APPAndroid6.0無響應,經過除錯發現SD卡讀寫許可權許可權被拒絕。但明明是在AndroidManifest.xml檔案中宣告過的。查了很多資料才知道Android6.0的很多許可權申請機制發生了改變,可以說是Android6.0在安全機制上更進了一步吧,因此寫下這篇文章以記錄。

PS:在我們的產品中,因為我們確信客戶在使用時不會在許可權申請時點“拒絕”,因此我對此功能的實現也僅限於文章中的前部分,也就是直接做死迴圈直到使用者同意授權,因為當然是用最低的成本滿足客戶的需求最好啦,但是真正開發中,需要處理更多的事情,我也並沒有淺嘗輒止,後面會

用到onRequestPermissionsResult回撥方法,shouldShowRequestPermissionRationale方法等,才能避免很多令使用者困擾的情況。後面會詳細地進行介紹。

1Android 6.0新的許可權管理機制

Android 6.0 Marshmallow版本之後,對於一些危險級別的許可權,執行在targetSdkVersion設定為2323以上的應用、並且程式碼邏輯需要這些許可權時,需要我們在程式碼中實現實時的詢問使用者是否授予許可權若不詢問直接進行有關這些許可權的程式碼邏輯,會出現類似java.lang.SecurityException: Permission Denial

的異常日誌。

targetSdkVersion如果設定為23以下,系統還是會使用舊的許可權管理規則但是6.0以後,使用者可以在<設定-許可權>裡將該APP的某些許可權手動關閉,此時被使用者禁止許可權的API介面返回值都為null或者0,我們判空即可防止App Crash

若APP在執行時,將設定裡的許可權手動關閉,那就會直接Crash。

2.危險許可權列表

前面提到的危險級別的許可權是我們需要格外關注的,因為這些許可權在使用前需要進行特殊處理。

 

上圖中有一個許可權群的概念,同一組的任何一個許可權被授權了,其他許可權也自動被授權。

例如,一旦WRITE_EXTERNAL_STORAGE被授權了,

APP同時也就有了READ_EXTERNAL_STORAGE許可權。

3Android 6.0執行時主動請求許可權

3.1  檢測和申請許可權

下面的例子介紹上面列出的讀寫SD卡的使用例子,可以使用以下的方式解決:

public boolean isGrantExternalRW(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

        activity.requestPermissions(new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, 1);
        return false;//第一次開啟應用並執行許可權檢查,雖然返回了false,但是已經呼叫過了申請許可權的方法
    }
    return true;//非第一次開啟應用並執行許可權檢查,或者6.0以下的Android版本
}

檢查和申請許可權的方法分別是Activity.checkSelfPermission()和Activity.requestPermissions,這兩個方法是在 API 23中新增的。

Activity.checkSelfPermission()主要用於檢測某個許可權是否已經被授予,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。當返回DENIED就需要進行申請授權了。

Activity.requestPermissions該方法是非同步的,第一個引數需要申請的許可權的字串陣列,第二個引數為requestCode,主要用於回撥的時候檢測。最前面的引數可以傳入mActivity。好像不傳也可以。

可以從方法名requestPermissions以及第二個引數看出,是支援一次性申請多個許可權的,系統會通過對話方塊逐一詢問使用者是否授權。

然後在需要使用這個許可權的時機,進行如下呼叫即可。

 boolean isGrant= isGrantExternalRW(mActivity);
 if (isGrant) {
      //業務邏輯
 }
 while (!isGrant) {
      try {
         Thread.sleep(1000);
} catch (InterruptedException e) {
        e.printStackTrace();
}
    isGrant = isGrantExternalRW(mActivity);
    if (isGrant) {
       //業務邏輯
   }
}

這裡因為我們寫的isGrantExternalRW方法的返回值只是判斷的一開始檢查許可權時的狀態,因此如果是第一次開啟應用,返回的是false,並且申請了許可權(如果使用者同意的話),再呼叫一次該方法返回true,進入邏輯程式碼,並最後跳出while迴圈。如果使用者已經授權過了,那麼直接會走邏輯程式碼。這裡比較流氓的是,如果使用者一直不同意,會一直返回false,我們就阻塞在while迴圈裡,一秒後繼續申請,直到使用者同意為止。顯然這是不夠友好的。

因此Google為了防止這種情況的發生,在使用者拒絕授權時,下一次彈窗可以勾選“不再提醒”如果這個選項被使用者勾選了。下次為這個許可權請求requestPermissions時,對話方塊就不彈出來了,系統會直接回調處理申請返回結果的回撥方法onRequestPermissionsResult,回撥結果為最後一次使用者的選擇。

3.2 處理許可權申請回調

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: {
            // 使用者取消授權這個陣列為空,如果你同時申請兩個許可權,那麼grantResults的length就為2,分別記錄你兩個許可權的申請結果
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //業務邏輯
            } else {
                //授權被拒絕,不再進行基於該許可權的功能
            }
            return;
        }
        // 其他case處理其他許可權的申請回調
    }
}

上面處理申請回調的方法已經寫的很明白了。

還有就是不管使用者點選拒絕還是同意,都會回撥該方法(別忘記使用者拒絕並勾選“不再提醒”時也會回撥)。

3.3  使用shouldShowRequestPermissionRationale方法

問題來了,如果第二次向用戶申請許可權被拒絕,並且使用者勾選了“不再提醒”,那我們以後每次需要使用這個許可權都會直接被拒絕,並不會彈出對話方塊。APP什麼也不做會產生很差的使用者體驗。所以這種情況需要我們進行處理。這時候我們可以藉助shouldShowRequestPermissionRationale方法。首先看一下該方法的返回值。


因此,我們在回撥函式中做許可權檢測,如果返回DENIED,就呼叫上述方法,返回false,就彈出對話方塊引導使用者手動開啟許可權,避免了使用者的操作觸發了許可權申請機制(已被拒絕並勾選不再提醒或手動關閉許可權),但是沒有任何響應的尷尬。又因為我們事先向使用者詢問授權過了,因此不存在表格中的第一種情況。

因此只需要在上面回撥程式碼的else程式碼段加入如下程式碼即可。

                if (!mActivity.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    //使用者已經完全拒絕,或手動關閉了許可權
                    //開啟此對話方塊緩解一下尷尬...
                    AlertDialog dialog = new AlertDialog.Builder(this)
                            .setMessage("不開啟該許可權將無法正常工作,請在設定中手動開啟!")
                            .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    finish();
                                }
                            })
                            .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    finish();
                                }
                            }).create();
                    dialog.show();
                    return;
                }else{
                    //使用者一直拒絕並一直不勾選“不再提醒”
                    //不執行該許可權對應功能模組,也不用提示,因為下次需要許可權還會彈出對話方塊
                }

在需要許可權的時候,只要執行類似於下面的檢查和申請許可權的程式碼即可(注意自己替換ContentCompat):

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 
&& ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) 
!= PackageManager.PERMISSION_GRANTED) {     
ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); } 
else {     //Do the stuff that requires permission... 
}


相關推薦

Android開發——Android 6.0許可權管理機制

0.前言最近在研究所實習,我負責維護Android手機取證專案的Android客戶端,有客戶反映我們的APP在Android6.0無響應,經過除錯發現SD卡讀寫許可權許可權被拒絕。但明明是在AndroidManifest.xml檔案中宣告過的。查了很多資料才知道Android

android 6.0許可權管理

轉載 https://blog.csdn.net/android2me/article/details/69525975 private void checkPermission() { //檢查許可權(NEED_PERMISSION)是否被授權 PackageManager.

Android 6.0許可權管理以及動態申請,以定位許可權為例

前言: 我們都知道現在手機系統已經到了很高的版本,在我們的Android6.0以後很多許可權都被列入危險許可權,都需要使用者手動去確認 1.我們先來看一下6.0以後被列為危險級別的一些許可權

Android——Android 6.0 許可權申請機制處理

Android 6.0帶來了新的許可權管理方式,預設情況下沒有任何應用有許可權去執行對其他應用、作業系統、使用者有不利影響的操作,這涉及到android 6.0的 Security Architecture(安全體系結構),也是Android安全體系結構的核心,

Android 啟動系統相機,相簿,裁剪圖片及6.0許可權管理

在日常開發中,我們經常需要用到上傳圖片的 功能,這個時候通常有兩種做法,第一種,從相機獲取,第二種,從相簿獲取。今天這篇部落格主要講解利用系統的Intent怎樣獲取? 主要內容如下 - 怎樣通過相機獲取我們的圖片 - 怎樣啟動相簿獲取我們想要的圖片 -

專案中處理 android 6.0 許可權管理問題

android 6.0對於許可權管理比較收緊,因此在適配android 6.0的時候就很有必要考慮一些許可權管理的問題。 如果你沒適配6.0的裝置並且許可權沒給的話,就會出現類似如下的問題: java.lang.SecurityException: Permission Denial: starting I

專案中處理android 6.0許可權管理問題

android 6.0對於許可權管理比較收緊,因此在適配android 6.0的時候就很有必要考慮一些許可權管理的問題。 如果你沒適配6.0的裝置並且許可權沒給的話,就會出現類似如下的問題: java.lang.SecurityException: Permission Denial: startin

Android 6.0許可權管理及其封裝

前言 Android M出來很久了,N都快釋出了,儘管如此還是要整理一下這塊。6.0的許可權機制變更為Runtime Permissions,執行時要請求許可權,如果使用者不授權的話,可能會導致崩潰。 本篇文章分三部分,一是許可權的分類,二是執行時請求的基本

Android超清晰6.0許可權申請AndPermission

前言 這是我經常使用的框架,原因: 1.思路清晰 2.實現方便 開始 準備工作 導包 compile 'com.yanzhenjie:permission:1.0.7' 然後就可以使

Android記憶體管理機制

無意中在MIUI看到的文章,感覺不錯,轉了過來。 原文如下: 最近看到很多機油發帖抱怨記憶體太小程序殺不掉。首先要表示,這個帖子是從百度貼吧轉來的,主要針對正常的安卓機,像里程碑這種悲劇的小記憶體機器

Android開發的之基本控制元件和四種佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有Frame絕對佈局和AutoL

Android開發基礎 -- 實體類 和 抽象類

1. 實體類        在日常的Java專案開發中,entity(實體類)是必不可少的,它們一般都有很多的屬性,並有相應的setter和getter方法。entity(實體類)的作用一般是和資

Android開發重點難點:RelativeLayout(相對佈局)

重點知識 和線性佈局(LinearLayout)一樣,RelaiveLayout相對佈局也是我們用的比較多的一個佈局之一。相對,顧名思義是有參照的,就是以某個兄弟元件,或者父容器來決定的(兄弟元件是在

Android 開發之多執行緒處理——Handler

    Android開發過程中為什麼要多執行緒     我們建立的Service、Activity以及Broadcast均是一個主執行緒處理,這裡我們可以理解為UI執行緒。但是在操作一 些耗時操作時,比如I/O讀寫的大檔案讀寫,資料庫操作以及網路下載需要很長時間,為了不

android 開發 View _14 MotionEvent和事件處理,與實踐自定義滑動條View

MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION

Android 開發中的 Manifest.xml 配置檔案

    AndroidManifest.xml 是一個非常重要的功能清單檔案。每一個應用程式的根目錄裡都有這個功能清單檔案,這個清單檔案給Android系統提供了關於這個應用程式的基本資訊,系統在執行任何程式程式碼之前必須知道這些資訊。 <?xml version=

mybatis事務管理機制

attribute log builder tween gen 事務管理 getc there spro 1.mybatis事務的配置和使用 mybatis事務有兩種使用方式: (a):使用JDBC的事務管理機制:即使用java.Sql.Connection對象完成對事務的

CentOS 7下Cloudera Manager及CDH 6.0.1安裝過程

一、概念介紹 1、CDH 概覽 CDH是Apache Hadoop和相關專案的最完整、最受測試和最流行的發行版。CDH提供Hadoop的核心元素-可伸縮儲存和分散式計算-以及基於web的使用者介面和重要的企業功能。CDH是Apache許可的開放原始碼,是唯一提供統一批處理、互動式SQL和互動式搜尋以及基於

activiti 6.0 editor漢化

新增漢化檔案到如下:   原始碼:  漢化檔案 stencilset_bpmn.json { "title" : "BPMN 2.0標準工具", "namespace" : "http://b3mn.org/stencilset/bp

Java記憶體管理機制

Java記憶體管理機制 本文將介紹Java虛擬機器所管理的記憶體區域以及記憶體回收問題: 1、Java虛擬機器所管理的記憶體區域 2、記憶體回收問題 <1>:常用垃圾收集演算法 <2>:JVM如何判斷一個物件已經消亡可以被回收