Android 6.0 Permission許可權與安全機制

来源:http://www.cnblogs.com/284628487a/archive/2016/03/14/5274767.html
-Advertisement-
Play Games

Android 6.0 許可權與安全,請求許可權


Marshmallow版本許可權修改

  android的許可權系統一直是首要的安全概念,因為這些許可權只在安裝的時候被詢問一次。一旦安裝了,app可以在用戶毫不知曉的情況下訪問許可權內的所有東西,而且一般用戶安裝的時候很少會去仔細看許可權列表,更不會去深入瞭解這些許可權可能帶來的相關危害。但是在android 6.0 Marshmallow版本之後,系統不會在軟體安裝的時候就賦予該app所有其申請的許可權,對於一些危險級別的許可權,app需要在運行時一個一個詢問用戶授予許可權。

   

舊版本app相容問題

  那麼問題來了,是不是所有以前發佈的app都會出現問題呢?答案是不會,只有那些targetSdkVersion 設置為23及以上的應用才會出現異常,在使用危險許可權的時候系統必須要獲得用戶的同意才能使用,要不然應用就會崩潰,出現類似下麵的錯誤。

java.lang.SecurityException: Permission Denial...

所以targetSdkVersion如果沒有設置為23版本或者以上,系統還是會使用舊規則:在安裝的時候賦予該app所申請的所有許可權。所以app當然可以和以前一樣正常使用了,但是還有一點需要註意的是6.0的系統裡面,用戶可以手動將該app的許可權關閉,在 App info裡面Permissions下邊,可以關閉某個許可權。如果以前的老應用申請的許可權被用戶手動關閉了,不會拋出異常,不會崩潰,只不過調用那些被用戶禁止許可權的api介面返回值都為null或者0,所以我們只需要做一下判空操作就可以了,這是需要註意的。

普通許可權和危險許可權列表

  現在對於新版本的許可權變更應該有了基本的認識,那麼,是不是所有許可權都需要去進行特殊處理呢?當然不是,只有那些危險級別的許可權才需要,可參考官網。

  http://developer.android.com/training/permissions/requesting.html 
  http://developer.android.com/guide/topics/security/permissions.html#normal-dangerous 
  所以仔細去看看自己的app,對照列表,如果有需要申請其中的一個許可權,就需要進行特殊操作。還有一個比較人性的地方就是如果同一組的任何一個許可權被授權了,其他許可權也自動被授權。例如,一旦WRITE_EXTERNAL_STORAGE被授權了,app也有READ_EXTERNAL_STORAGE許可權了。

支持Marshmallow新版本許可權機制

  在Android M的api中,我們可以通過checkSelfPermission檢測軟體是否有某一項許可權,以及使用requestPermissions去請求一組許可權。

int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                CODE_FOR_WRITE_PERMISSION);
    return;
}

  以上的代碼塊展示了檢測軟體是否有寫文件的許可權,如果沒有寫文件的許可權,則通過requestPermissions去向用戶發起請求許可權的流程。向用戶發起請求之後,請求完成,會有相對應的回調方法,通知軟體用戶是否授予了許可權。通過在Activity或者Fragment中重寫onRequestPermissionsResult方法。  

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == CODE_FOR_WRITE_PERMISSION){
        if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            // 用戶同意寫文件
        } else {
            // 用戶不同意,自行處理即可
        }
    }
}

處理不再提醒

  如果用戶一旦拒絕過某許可權的授權。下一次彈框時,用戶會有一個“不再提醒(Never ask again)”的選項的來防止app以後繼續請求授權。

  

  如果這個選項在拒絕授權前被用戶勾選了。下次為這個許可權請求requestPermissions時,對話框就不彈出來了,系統會直接回調onRequestPermissionsResult函數,回調結果為最後一次用戶的選擇。所以為了應對這種情況,系統提供了一個shouldShowRequestPermissionRationale()函數,這個函數的作用是幫助開發者找到需要向用戶額外解釋許可權的情況。

  1. 應用安裝後第一次訪問,直接返回false;
  2. 第一次請求許可權時,用戶拒絕了,下一次shouldShowRequestPermissionRationale()返回 true,這時候可以顯示一些為什麼需要這個許可權的說明;
  3. 第二次請求許可權時,用戶拒絕了,並選擇了“不再提醒”的選項時:shouldShowRequestPermissionRationale()返回 false;
  4. 設備的系統設置中禁止當前應用獲取這個許可權的授權,shouldShowRequestPermissionRationale()返回false;

註意:第二次請求許可權時,才會有“不再提醒”的選項,如果用戶一直拒絕,並沒有選擇“不再提醒”的選項,下次請求許可權時,會繼續有“不再提醒”的選項,並且shouldShowRequestPermissionRationale()也會一直返回true。

所以利用這個函數我們可以進行相應的優化,針對shouldShowRequestPermissionRationale函數返回false的處理有兩種方法:

  處理方法已經有了,修改一下代碼,這裡以第二種方案來處理:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == CODE_FOR_WRITE_PERMISSION){
        if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            &&grantResults[0] == PackageManager.PERMISSION_GRANTED){
            // 用戶同意
        } else {
            // 用戶不同意,向用戶展示該許可權作用
            if (!shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                showPermissionDialog();return;
            }
        }
    }
}

當勾選不再提醒,並且拒絕之後,彈出dialog,提醒用戶該許可權的重要性

使用相容庫

  以上的代碼在6.0版本上使用沒有問題,但是在之前就有問題了,最簡單粗暴的解決方法可能就是利用Build.VERSION.SDK_INT >= 23這個判斷語句來判斷了,方便的是SDK 23的v4包加入了專門類進行相關的處理:

  • ContextCompat.checkSelfPermission()被授權函數返回PERMISSION_GRANTED,否則返回PERMISSION_DENIED ,在所有版本都是如此。
  • ActivityCompat.requestPermissions()這個方法在6.0之前版本調用,OnRequestPermissionsResultCallback 直接被調用,帶著正確的 PERMISSION_GRANTED或者PERMISSION_DENIED。
  • ActivityCompat.shouldShowRequestPermissionRationale()在6.0之前版本調用,永遠返回false。
// 使用相容庫就無需判斷系統版本
int hasWriteContactsPermission = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteContactsPermission == PackageManager.PERMISSION_GRANTED) {
 
} // 需要彈出dialog讓用戶手動賦予許可權
else {
    ActivityCompat.requestPermissions(Acivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_FOR_WRITE_PERMISSION);
}

onRequestPermissionsResult函數不變。後兩個方法,我們也可以在Fragment中使用,用v13相容包:FragmentCompat.requestPermissions() 和 FragmentCompat.shouldShowRequestPermissionRationale()和activity效果一樣。

一次請求多個許可權

  當然了有時候需要多個許可權,可以用上面方法一次請求多個許可權。當然最重要的是不要忘了為每個許可權檢查“不再提醒”的設置。

List<String> permissionsNeeded = new ArrayList<String>();
permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissionsNeeded.add(Manifest.permission.READ_CONTACTS);
permissionsNeeded.add(Manifest.permission.WRITE_CONTACTS);
requestPermissions(permissionsNeeded.toArray(new String[permissionsList.size()]), CODE_FOR_MULTIPLE_PERMISSION);

最後在onRequestPermissionsResult函數中一個個處理返回結果即可。

第三方庫簡化代碼

  當然早就有第三方庫來幫忙做這些事情了: 
  Github上的開源項目 PermissionHelperPermissionsDispatcherEasyPermissions

APP處於運行狀態下,被撤銷許可權

  如果APP正在運行中,用戶進入設置-應用程式頁面去手動撤銷該APP許可權,會出現什麼情況呢?系統又會接著彈出許可權請求對話框。

Over

  新運行時許可權已經在棉花糖中被使用了。我們沒有退路。我們現在唯一能做的就是保證app適配新許可權模型。欣慰的是只有少數許可權需要運行時許可權模型。大多數常用的許可權,例如,網路訪問,屬於Normal Permission 在安裝時自動會授權,當然你要聲明,以後無需檢查。因此,只有少部分代碼你需要修改。 
兩個建議: 
  1.嚴肅對待新許可權模型。 
  2.如果你代碼沒支持新許可權,不要設置targetSdkVersion 23 。尤其是當你在Studio新建工程時,不要忘了修改! 
  說一下代碼修改。這是大事,如果代碼結構被設計的不夠好,你需要一些很蛋疼的重構。每個app都要被修正。如上所說,我們沒的選擇。列出所有你需要請求許可權的全部情形,如果A被授權,B被拒絕,會發生什麼,針對每一個情況認真處理。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 游戲項目尾聲,做下總結: 1.sharesdk微信微博分享(1) 如果接入眾多渠道,選用服務端獲取代碼配置參數的方式(微信:app_id 微博: app_key, app_secret)代碼配置2.x版本需註意setPlatformConfig設置參數時Android和ios設置key不同(Andr
  • 今天發現之前自己一直有個誤區,new Runnable(run()方法){}原來它不是一定創建一個線程 如果用主線程的handler去post(Runnable),他就不會創建子線程,而是在主線程上執行的Runnable方法 如果用new Thread(Runnable).start();那他就是在
  • 在網上找到了一篇總結的非常好的文章,我這裡就貼出他的博文地址。自己就不再寫這個方面的總結了。 "Activity與Fragment通信(99%)完美解決方案"
  • Android Material Design DrawerLayout和NavigationView及Palette
  • 本文詳細整理了 Cocoa 的 Runtime 系統的知識,它使得 Objective-C 如虎添翼,具備了靈活的動態特性,使這門古老的語言煥發生機。主要內容如下: 曾經覺得Objc特別方便上手,面對著 Cocoa 中大量 API,只知道簡單的查文檔和調用。還記得初學 Objective-C 時把[
  • iOS9系統下 為了我司APP的相容性問題 特意把手上的iOS Mac XCode都升級到了最新的beta版 然後發現iOS9的多任務管理器風格大變 變成了下麵這種樣子 我忽然想起來之前的文章提到我最愛的UI控制項iCarousel要實現類似這種效果其實是很簡單的 一時興起就花時間試驗了一下 效果還不
  • 本節先說網路請求的重構 舊代碼結構圖: 之前的代碼控制器中都是一個個需要連接網路的方法中直接調用service的請求方法並獲取回調,屬於常規做法。 重構後結構圖:  使用RAC改寫後,controller不會直接調用service,controller通過控制一個個command的執行與否來達到發請
  • 1.撥打電話:am start -a android.intent.action.CALL -d tel:10086             這裡-a表示動作,-d表述傳入的數據,還有-t表示傳入的類型。 2. 打開一個網頁:am start -a android.intent.action.VIE
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...