引言:運行時權(quán)限是版本升級的一個更新點隘膘,學起來挺容易的额嘿,寫一篇筆記感覺真費勁。
時間:2017年04月18日23:45:50
作者:JustDo23
01. 前言
運行時權(quán)限是Android 6.0 變更中尤為突出的一點锰茉。6以下的手機在安裝時候提示權(quán)限列表嫂用,用戶全部同意后才能安裝程序沐寺;6以后的手機直接安裝书在,在運行過程中動態(tài)的向用戶申請所需權(quán)限缩多,另外用戶可以在設置界面對程序的各個權(quán)限進行管理友浸。
Android 中的權(quán)限可以分為三類:
- 普通權(quán)限(Normal Permissions)
- 危險權(quán)限(Dangerous Permissions)
- 特殊權(quán)限(Special Permissions)
普通權(quán)限不涉及用戶隱私峰尝,在AndroidManifest.xml
中聲明即獲取收恢;危險權(quán)限涉及用戶的隱私武学,在用戶授權(quán)之后方能使用。另外伦意,Google 對危險權(quán)限進行了分組火窒,當某一個組中的某一個權(quán)限被授權(quán)之后應用同時就獲取到了整個組的所有權(quán)限。而且驮肉,調(diào)用 API 申請權(quán)限時系統(tǒng)將向用戶顯示一個標準對話框熏矿,該對話框上的提示權(quán)限說明是針對整個組的說明,應用無法配置或更改此對話框离钝。
02. 聲明權(quán)限
在官方文檔中提到:為了保護系統(tǒng)的完整性和用戶隱私權(quán)票编,Android 在訪問受限的沙盒中運行每款應用。如果應用需要使用其沙盒以外的資源或信息卵渴,則必須明確請求權(quán)限慧域。根據(jù)應用請求的權(quán)限類型,系統(tǒng)可能會自動授予權(quán)限奖恰,也可能會要求用戶授予權(quán)限吊趾。可以在應用清單中列出相應的權(quán)限瑟啃,聲明應用需要此權(quán)限论泛。
聲明權(quán)限,將<uses-permission>
元素置于頂級<manifest>
元素的子項蛹屿。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.snazzyapp">
<uses-permission android:name="android.permission.SEND_SMS"/>
<application ...>
...
</application>
</manifest>
03. 檢查權(quán)限
/**
* Determine whether you have been granted a particular permission.
*
* @param permission The name of the permission being checked.
*/
ContextCompat.checkSelfPermission(@NonNull Context context, @NonNull String permission)
以上為核心 API 檢查是否擁有權(quán)限屁奏,簡單封裝如下:
/**
* 檢查是否具有某權(quán)限
*
* @return true, 有權(quán)限 false,無權(quán)限
*/
private boolean checkPermission(Context context, String permission) {
boolean checkPermission = false;
int permissionCheck = ContextCompat.checkSelfPermission(context, permission);// 檢查權(quán)限
switch (permissionCheck) {
case PackageManager.PERMISSION_GRANTED:// 有權(quán)限
checkPermission = true;
break;
case PackageManager.PERMISSION_DENIED:// 無權(quán)限
checkPermission = false;
break;
}
return checkPermission;
}
- 返回的結(jié)果是
int
類型 - 常量
PackageManager.PERMISSION_GRANTED
表示有權(quán)限 - 常量
PackageManager.PERMISSION_DENIED
表示無權(quán)限
// 檢查日歷權(quán)限
ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
04. 請求權(quán)限
/**
* 請求指定的權(quán)限集合
*
* @param activity The target activity.
* @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code.
*/
ActivityCompat.requestPermissions(
final @NonNull Activity activity,
final @NonNull String[] permissions,
final @IntRange(from = 0) int requestCode);
- 此方法為異步方法
- 第二參數(shù)指定一個權(quán)限的字符數(shù)組
// 請求一個相機權(quán)限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 23);
// 同時請求三個權(quán)限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_CALENDAR, Manifest.permission.READ_SMS}, 32);
05. 請求響應
/**
* Callback for the result from requesting permissions.
*
* @param requestCode The request code.
* @param permissions The requested permissions. Never null.
* @param grantResults The grant results.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
case 23:
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ToastUtil.showShortToast(MainActivity.this, "授權(quán)");
} else {
ToastUtil.showShortToast(MainActivity.this, "拒絕");
}
}
break;
case 32:
break;
}
}
- 第二個參數(shù)是請求的權(quán)限數(shù)組
- 第三個參數(shù)是與請求數(shù)組對應的授權(quán)結(jié)果數(shù)組
06. 提供解釋
/**
* Gets whether you should show UI with rationale for requesting a permission.
*
* @param activity The target activity.
* @param permission A permission your app wants to request.
* @return Whether you can show permission rationale UI.
*/
public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
@NonNull String permission) {
if (Build.VERSION.SDK_INT >= 23) {
return ActivityCompatApi23.shouldShowRequestPermissionRationale(activity, permission);
}
return false;// 低版本直接返回 false
}
- 如果應用之前請求過此權(quán)限但用戶拒絕了請求,此方法將返回
true
错负。 - 如果用戶在過去拒絕了權(quán)限請求坟瓢,并在權(quán)限請求系統(tǒng)對話框中選擇了 Don't ask again 選項,此方法將返回
false
犹撒。 - 如果設備規(guī)范禁止應用具有該權(quán)限折联,此方法也會返回
false
。
這部分的內(nèi)容Android M 權(quán)限最佳實踐這篇文章寫得很好识颊。
07. 官方例子
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);
}
}
08. 兼容問題
首先明確一下在什么情況下需要使用運行時權(quán)限動態(tài)申請:
- 危險權(quán)限
- Android 版本 >= 6.0
- targetSdkVersion >= 23
在這三個條件同時具備的情況下必須使用運行時權(quán)限機制诚镰。當targetSdkVersion < 23
的時候不用
調(diào)用運行時權(quán)限機制奕坟,當targetSdkVersion >= 23
的時候必須
調(diào)用運行時權(quán)限機制以確保程序不會出現(xiàn)崩潰。另外清笨,運行時權(quán)限機制的相關 API 都是在support.v4
包下月杉,說明做了低版本兼容,相關 API 運行在低版本時候均有默認的返回值抠艾。在此基礎上兼容適配問題可以考慮從兩個因素Android 版本
和targetSdkVersion
入手苛萎,用一張表來簡單分析兼容適配問題:
targetSdkVersion | Android 版本 | 兼容適配 |
---|---|---|
targetSdkVersion < 23 | SDK < 23 | 安裝時授權(quán),正常使用 |
targetSdkVersion < 23 | SDK >= 23 | 直接安裝并授權(quán)检号,用戶管理權(quán)限腌歉,可能崩潰 |
targetSdkVersion >= 23 | SDK < 23 | 安裝時授權(quán),運行時權(quán)限 API 有默認返回值谨敛,正常使用 |
targetSdkVersion >= 23 | SDK >= 23 | 直接安裝究履,運行時授權(quán),用戶管理權(quán)限脸狸,正常使用 |
從表格中看出如果應用targetSdkVersion < 23
運行在Android 6.0
的手機上最仑,由于用戶可以自主管理權(quán)限,取消某些授權(quán)炊甲,便會引起程序崩潰泥彤。因此,盡快提升目標版本同時添加運行時權(quán)限判斷申請 API 是很有必要的卿啡。
注意:對于以 Android 6.0 或更高版本為目標平臺的應用吟吝,請務必在運行時檢查和請求權(quán)限。即使不以 Android 6.0 為目標平臺颈娜,也應該在新權(quán)限模式下測試應用剑逃。
09. 其他小點
- 如果您的應用需要危險權(quán)限,則每次執(zhí)行需要這一權(quán)限的操作時您都必須檢查自己是否具有該權(quán)限官辽。用戶始終可以自由調(diào)用此權(quán)限蛹磺,因此,即使應用昨天使用了相機同仆,它不能假設自己今天仍具有該權(quán)限萤捆。
- 用戶只需要為每個權(quán)限組授予一次權(quán)限。當請求已經(jīng)被授予的權(quán)限時俗批,系統(tǒng)會調(diào)用您的
onRequestPermissionsResult()
回調(diào)方法俗或,并傳遞PERMISSION_GRANTED
。 - 當系統(tǒng)要求用戶授予權(quán)限時岁忘,用戶可以選擇指示系統(tǒng)不再要求提供該權(quán)限辛慰。這種情況下,無論應用在什么時候使用
requestPermissions()
再次要求該權(quán)限干像,系統(tǒng)都會立即拒絕此請求昆雀。系統(tǒng)會調(diào)用您的onRequestPermissionsResult()
回調(diào)方法辱志,并傳遞PERMISSION_DENIED
。
10. 奇思怪想
- 同時申請多條相同權(quán)限時狞膘,只有一個權(quán)限提示。
- 同時申請同組的多條權(quán)限時什乙,只有一個權(quán)限提示挽封。
- 在
onRequestPermissionsResult
方法中的權(quán)限字符數(shù)組與requestPermissions
方法中的相同。 - 先檢查權(quán)限再申請權(quán)限臣镣。原因是第一次申請權(quán)限勾選允許辅愿,再次申請權(quán)限勾選拒絕,程序崩潰忆某。同時申請多個權(quán)限点待,有的拒絕有的允許,再次申請時應該先檢查并剔除已經(jīng)允許的權(quán)限弃舒。注意:崩潰出現(xiàn)在6.0的手機上癞埠,在7.0上回自動返回授權(quán)或者自動剔除。
11. 推薦文章
有幾篇非常不錯的文章值得閱讀學習: