編輯:關於Android編程
Android6.0帶來了新的權限管理方式,本文主要來源於官方文檔,加入了自己的理解,目的是想總結Android6.0權限管理的新方式,其他部分可能主要是總結式的帶過,後續再詳細分析。
Android安全體系結構的核心是:
默認情況下沒有任何應用有權限去執行對其他應用、操作系統、用戶有不利影響的操作。這是一個核心的設計理念。記住這句話對後面的權限管理可以很好的理解。
正式由於這樣的設計理念,默認情況下應用不能去讀寫用戶的私有數據(比如Email和Contacts),不能去讀寫其他App的文件,不能執行網絡訪問,不能保持設備始終喚醒等等。
因為每一個Android 應用都是在一個進程沙盒中運行的,應用必須明確分享的資源和數據,通過申明需要的額外權限這種方式(這些額外權限不由基本沙河提供)。應用靜態的聲明這些權限(在Manifest裡面),然後Android系統會請求用戶同意這些權限。
Android應用沙盒不依賴於創建應用的技術(這句話不是很懂,懂的大神可以指 一下),特別的是Dalvik虛擬機並不是安全邊界的,所有的應用都可以運行native code(比如參見NDK),所有類型的應用-Java,native,hybird,都是以同樣的方式封裝在沙盒內並且相互之間是同樣的安全等級。
所有的Apk文件都必須由他的開發者使用私有的簽名證書簽名,這個證書是開發者身份的唯一標識,這個證書是由開發者自己生成的開放式的證書,用於自己簽名應用。證書的目的是標識應用的身份,這樣可以讓系統知道是該允許還是拒絕應用訪問簽名級別的權限(signature-level permissions),以及允許還是拒絕應用所請求的給予相同Linux身份來作為不同的應用。
在安裝一個app package的時候,android系統會給每一個package一個獨立的Linux user ID。這個User ID在這個應用在當前設備的生命周期內都是固定不變的,在不同的設備,相同的package的用戶ID可能各不相同,但可以確定的是在一台設備上一個 package的用戶ID是固定不變的。
因為安全執行是發生在進程層面的,兩個不同的package不能運行在相同的進程中,他們會被作為不同的Linux用戶來運行。
但是你可以在manifest中使用sharedUserId屬性來指定不同的package有相同的User ID,這樣這兩個不同的package將會被視為相同的APP,會有相同的User ID和文件權限。
當然為了保證安全,只有兩個APP簽名一致且申明了相同的sharedUserId才會被給予相同的User ID。
一個新建的Android應用默認是沒有權限的,這意味著它不能執行任何可能對用戶體驗有不利影響的操作或者訪問設備數據。為了使用受保護的功能,你必須包含一個或者多個
Android 6.0中權限分為兩種,普通權限和危險權限(即運行時權限,下面統稱運行時權限)。
如果你的應用manifest中只申明了普通權限(也就是說,這些權限對於用戶隱私和設備操作不會造成太多危險),系統會自動授予這些權限。
如果你的應用manifest中聲明了運行時權限(也就是說,這些權限可能會影響用戶隱私和設備的普通操作),系統會明確的讓用戶決定是否授予這些權限。系統請求用戶授予這些權限的方式是由當前應用運行的系統版本來決定的。
如果你的設備運行的是Android6.0(API level 23)及以上的系統,並且你的應用的targetSdkVersion也是23或者更高,那麼應用向用戶請求這些權限是實時的。這意味著用戶可以隨時取消 這些運行時權限的授權。所以應用在每次需要用到這些運行時權限的時候都需要去檢查是否還有這些權限的授權。具體請求方式後面會講到。
如果你的設備運行在Android5.1(API level 22)及以下的系統中,或者你的app的targetSdkVersion是22或者更低。系統會請求用戶在apk安裝的時候授予這些權限。
如果你的應用更新的時候添加了一個權限,系統會在用戶更新應用的時候請求用戶授予這個權限,一旦用戶安裝了這個應用,唯一可以取消授權的方式就是卸載掉這個應用。注意這句話的意思,想一下如果app的targetSdkVersion是22或者以下,但是運行在Android6.0及以上的設備中會有什麼問題?後面會分析這個問題。
常常來說一個授權失敗會拋出SecurityException,然而這並不是在 所有情況下都會發生。比如,發送一個廣播去檢查授權(SendBroadcast(Intent)),數據會被發送給所有接收者,但是當這個方法的請求返 回的時候,你不會收到任何一個因為授權失敗拋出的異常,其實在大多數情況下,授權失敗只會打印系統日志。
任何應用也可以定義和執行他們自己的權限。
簡單的說,如果你的app targetSdkVersion是3,而你當前運行的系統版本是4,那麼在android version 4 中新添加的權限會自動添加到你的app中。
比如WRITE_EXTERNAL_STORAGE權限是在api 4的時候添加的,而你的應用的targetSdkVersion是3,那麼這個權限會自動添加到你的應用中。而且在官方商店上這個權限也會列出來(盡管可能你並不需要這個權限)。
所以建議經常更新你的targetSdkVersion到最新版本。
下面來回答上面的那個問題,如果app的targetSdkVersion是22或者以下,但是運行在android 6.0或以上版本的手機中,會發生什麼?
安裝過程中,會一起請求用戶授予所有 權限,如果用戶拒絕,將不能安裝這個app,只有用戶全部同意這些授權,才能安裝這個應用,但是問題來了,安裝好了這個應用之後,android6.0以 上的系統中,用戶是可以去設置中取消授權的,而且是隨時都可以取消,所以很多運行時權限可能也得不到,目前官方的做法是,如果用戶取消該項授權,那麼依賴 該項授權的方法的返回值為null,所以你的app可能會報空指針異常。以後是否會針對22以下的app做改變還不得而知,畢竟crash是很難讓人接受 的,但是crash是由用戶造成的,用戶應該也可以理解。
系統權限會被傳遞給兩種不同的保護級別,我們所知道這兩種最重要的保護級別就是普通權限和運行時權限。
普通權限的覆蓋區域是在你的app需要訪問沙盒以外的數據和資源的時候,但是對用戶隱私和其他app的操作只有很少的影響,比如開啟手電筒的權限。這個時候,系統會自動授權這些普通權限。
運行時權限的覆蓋區域是你的app想要的數據和資源涉及用戶的隱私信息,或者是可能潛在的影響用戶的存儲數據或者其他app的操作。比如,請求獲取用戶聯系人信息的權限。如果一個app申明了運行時權限,用戶必須明確的授權這些權限給app。
如果一個app在manifest中請求了一個運行時權限,而且app還沒有得到這個運行時權限所在的權限組中的任何一個運行時權限授權,那麼系統會彈出一個對話框,描述app想要訪問的運行時權限的權限組,這個對話框不會描述這個權限組中某一個特定的權限。
比如,你的app想要請求READ_CONTACT權限,對話框只會描述app想要請求設備的聯系人,如果用戶授權通過,系統會授予app所請求的該項權限。
如果一個app在manifest中請求一個運行時權限,並且這個app已經在相同的權限組中有了另一個運行時權限的授權,那麼系統不會彈出對話框,而是會立即授予app該項運行時權限的授權。
比如,一個app之前請求過一個READ_CONTACT的權限並且被授權通過,之後又請求一個WRITE_CONTACT(在同一個權限組)權限,那麼系統會自動授予該權限。
其實所有權限(普通權限、運行時權限、用戶自定義權限)都屬於特定的權限組,但是只有運行時權限的權限組才會影響用戶體驗。
READ_CALENDAR
WRITE_CALENDAR
CAMERA
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
RECORD_AUDIO
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
BODY_SENSORS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
有兩個權限比較特殊,分別是SYSTEM_ALERT_WINDOW和WRITE_SETTINGS
都屬於比較敏感的權限,很多時候都永不到,如果需要這個權限,應該首先聲明,然後發送Intent去請求用戶授權,然後系統會顯示詳細的管理界面。
第一.判斷
Build.VERSION.SDK_INT>=Build.VERSION_CODES.M
第二.如果是android6.0以上的系統,則檢查是否獲取授權
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
如果返回值為PackageManager.PERMISSION_GRANTED,則可以繼續之後的操作,如果返回值為PERMISSION_DENIED,則代表沒有授權該權限。
第三.shouldShowRequestPermissionRationale()可以得到是否需要彈出一個解釋申請該權限的提示給用戶,如果為true,則可以彈。
第四.請求該權限
示例如下:
// 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. } } else { 執行獲取權限後的操作 }
第五.請求權限之後,在onRequestPermissionsResult()返回值中可以得到用戶是否授權,如果授權,就可以操作該運行時權限對應的方法
@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 } }
運行時權限的特點是,實時性,用戶可以隨時取消授權,所以每次調用運行時權限的方法都需要判斷或者請求一次運行時權限。
在執行運行時權限申請的同時想一下是否真的有必要,想一下使用Intent的方式啟動其他應用是否可以達到需求,比如ACTION_IMAGE_CAPTURE,是直接申明CAMERA的權限自己做一個照相機還是發送ACTION_IMAGE_CAPTURE請求讓別的應用處理並在onActivityResult()返回值更方便
如果設備運行在5.1或者以下的設備,或者targetSdkVersion在22或以下,系統會在安裝app的時候讓用戶授權權限。再說一遍,系統只會提示用戶app需要的權限組,而不會提示某一個特定的權限。
為了執行自定義權限,你必須在你的manifest中聲明一個或多個
比如:
相當於權限組的提示,要簡短
是某一個特定權限的描述,規則是兩句話,第一句描述,第二句警告用戶如果授權會發生什麼後果。
比如,CALL_PHONE權限
directlycallphonenumbers Allowstheapplicationtocall phonenumberswithoutyourintervention.Maliciousapplicationsmay causeunexpectedcallsonyourphonebill.Notethatthisdoesnot allowtheapplicationtocallemergencynumbers.
之後,你會在setting—>Application中看到該自定義權限。
概述 移動互聯網安全無疑已成為當今主流安全威脅之一。統計 2011 年至今的移動惡意代碼病毒庫,可以看到 Android 平台下的惡意軟件數量增長可謂
自定義控件是一些android程序員感覺很難攻破的難點,起碼對我來說是這樣的,但是我們可以在網上找一些好的博客關於自定義控件好好拿過來學習研究下,多練,多寫點也能找到感覺
前面照著android系統的裁剪圖片的功能自己寫了一個相似的工具。功能是大體上實現了,但留下了一個調用的問題:如何從我的程序調用這個裁剪工具,並且獲得裁剪後的圖片呢?其實
這裡,我將用一個小例子的形式來幫助大家初探JNI的用法,首先,大家要先搭建好NDK環境,請大家先閱讀《Android之——NDK環境搭建》一文。一