詳解Android權(quán)限管理之Android 6.0運(yùn)行時權(quán)限及解決辦法
前言:
今天還是圍繞著最近面試的一個熱門話題Android 6.0權(quán)限適配來總結(jié)學(xué)習(xí),其實Android 6.0權(quán)限適配我們公司是在今年5月份才開始做,算是比較晚的吧,不過現(xiàn)在Android 6.0以上設(shè)備越來越多了,所以Android 6.0 權(quán)限適配是必不可少的工作,這里主要介紹一下我們公司是如何做Android 6.0權(quán)限適配的。
Android 6.0以下非運(yùn)行時權(quán)限:
根據(jù)上面博客我們很清楚的知道,Android的權(quán)限其實就是為了程序之間更加的安全的訪問,所以權(quán)限有等級之分,比如:Normal 低風(fēng)險權(quán)限 、Dangerous 高風(fēng)險權(quán)限等,雖然有這種安全意識,但是這些權(quán)限只會在安裝的時候被詢問一次,一旦安裝之后,如果app申請了高風(fēng)險權(quán)限的話,而且大部分用戶在安裝的時候很少去關(guān)注這些權(quán)限列表,再加上很多Android市場都有靜默安裝的功能用戶更加感知不到任何權(quán)限提示,就這樣app就有可能會在后臺做一些對用戶帶來傷害的事情。如下圖所示:
Android6.0運(yùn)行時權(quán)限:
鑒于6.0之前的版本權(quán)限管理相對不那么安全,所以Android 6.0 采用新的權(quán)限模型,只有在需要權(quán)限的時候,才告知用戶是否授權(quán),是在runtime時候授權(quán),而不是在原來安裝的時候 ,同時默認(rèn)情況下每次在運(yùn)行時打開頁面時候,需要先檢查是否有所需要的權(quán)限申請。這樣的用戶的自主性提高很多,比如用戶可以給APP賦予攝像的權(quán)限,也可以使用權(quán)限。
Android 6.0權(quán)限適配:
1.)不進(jìn)行適配造成的現(xiàn)象
先看下app module的build.gradle配置
compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.whoislcj.rxpermissions" minSdkVersion 15 targetSdkVersion 24 versionCode 1 versionName "1.0" }
由于Android 6.0 以上的權(quán)限變成了運(yùn)行時權(quán)限,也就是說在需要使用某個權(quán)限的時候必須動態(tài)去申請使用,直接訪問直接導(dǎo)致app崩潰。
2.)早期的解決辦法
其實判斷是否是需要運(yùn)行時權(quán)限的標(biāo)記就是targetSDKVersion,當(dāng)targetSDKVersion<23的時候,僅在安裝時賦予權(quán)限,使用時將不被提醒,當(dāng)targetSDKVersion≥23的時候才會使用新的運(yùn)行時權(quán)限規(guī)則。所有在最早遇見因權(quán)限未適配的導(dǎo)致的崩潰的時候,我們團(tuán)隊采用的解決辦法是將targetSDKVersion人為的降到小于23,這樣就變成了還是默認(rèn)使用權(quán)限,但是這種并不是Google所推薦使用的。
compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.whoislcj.rxpermissions" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" }
3.)判斷是否擁有該權(quán)限的使用權(quán)限
檢查是否擁有使用權(quán)
public boolean isGranted(String permission) { return !isMarshmallow() || isGranted_(permission); }
判斷是否是Android 6.0以上
private boolean isMarshmallow() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; }
是否申請了該使用權(quán)限
private boolean isGranted_(String permission) { int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission); return checkSelfPermission == PackageManager.PERMISSION_GRANTED; }
ContextCompat.checkSelfPermission,主要用于檢測某個權(quán)限是否已經(jīng)被授予,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。當(dāng)返回DENIED就需要進(jìn)行申請授權(quán)了。
4.)申請使用權(quán)限
private void requestPermission(String permission, int requestCode) { if (!isGranted(permission)) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { } else { ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode); } } else { //直接執(zhí)行相應(yīng)操作了 } }
shouldShowRequestPermissionRationale主要用于給用戶一個申請權(quán)限的解釋,該方法只有在用戶在上一次已經(jīng)拒絕過你的這個權(quán)限申請。也就是說,用戶已經(jīng)拒絕一次了,你又彈個授權(quán)框,你需要給用戶一個解釋,為什么要授權(quán),則使用該方法。requestCode這個需要在處理的回調(diào)的時候 一一對應(yīng)的。
5.)處理授權(quán)回調(diào)
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == CAMERA) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { String jpgPath = getCacheDir() + "test.jpg"; takePhotoByPath(jpgPath, 2); } else { // Permission Denied Toast.makeText(MainActivity.this, "您沒有授權(quán)該權(quán)限,請在設(shè)置中打開授權(quán)", Toast.LENGTH_SHORT).show(); } return; } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
6.)完整的Activity示例
public class MainActivity extends AppCompatActivity { private static final int CAMERA = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.request_permission).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { requestPermission(Manifest.permission.CAMERA, CAMERA); } }); } /** * 拍照,返回拍照文件的絕對路徑 */ private String takePhotoByPath(String filePath, int requestCode) { File file = new File(filePath); startActivityForResult(getTakePhotoIntent(file), requestCode); return file.getPath(); } private Intent getTakePhotoIntent(File file) { if (file.exists()) { file.delete(); } try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } Uri uri = Uri.fromFile(file); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); return intent; } public boolean isGranted(String permission) { return !isMarshmallow() || isGranted_(permission); } private boolean isGranted_(String permission) { int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission); return checkSelfPermission == PackageManager.PERMISSION_GRANTED; } private boolean isMarshmallow() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } //shouldShowRequestPermissionRationale主要用于給用戶一個申請權(quán)限的解釋,該方法只有在用戶在上一次已經(jīng)拒絕過你的這個權(quán)限申請。也就是說,用戶已經(jīng)拒絕一次了,你又彈個授權(quán)框,你需要給用戶一個解釋,為什么要授權(quán),則使用該方法。 private void requestPermission(String permission, int requestCode) { if (!isGranted(permission)) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) { } else { ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode); } } else { //直接執(zhí)行相應(yīng)操作了 } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == CAMERA) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { String jpgPath = getCacheDir() + "test.jpg"; takePhotoByPath(jpgPath, 2); } else { // Permission Denied Toast.makeText(MainActivity.this, "您沒有授權(quán)該權(quán)限,請在設(shè)置中打開授權(quán)", Toast.LENGTH_SHORT).show(); } return; } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
總結(jié):
本篇總結(jié)學(xué)習(xí)了Android 6.0的運(yùn)行時權(quán)限及如何適配的問題,但是這個并不是我們公司目前最終的解決辦法,從上面可以看出實現(xiàn)起來還是蠻麻煩的,申請權(quán)限和處理回調(diào)在不同的地方代碼可讀性相對較差,我們最終的解決方案是采用RxJava+RxPermission的方式解決,下一篇將介紹一下如何使用RxPermission解決Android 6.0 權(quán)限適配問題。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android獲取assets文件夾中的數(shù)據(jù)并寫入SD卡示例
這篇文章主要介紹了Android獲取assets文件夾中的數(shù)據(jù)并寫入SD卡示例,對初學(xué)Android開發(fā)的朋友來說是一個很實用的功能,需要的朋友可以參考下2014-07-07詳解Android獲取系統(tǒng)內(nèi)核版本的方法與實現(xiàn)代碼
這篇文章主要介紹了詳解Android獲取系統(tǒng)內(nèi)核版本的方法與實現(xiàn)代碼的相關(guān)資料,這里提供了具體實現(xiàn)獲取內(nèi)核的方法,需要的朋友可以參考下2017-07-07Android開發(fā)中ListView自定義adapter的封裝
這篇文章主要為大家詳細(xì)介紹了android開發(fā)中ListView自定義adapter的封裝,ListView的模板寫法,感興趣的小伙伴們可以參考一下2016-09-09怎樣實現(xiàn)android http-post方法實例說明
android http-post方法在開發(fā)中如何實現(xiàn),具體代碼如下,感興趣的朋友可以參考下哈,希望對大家有所幫助2013-06-06Android中ListView下拉刷新的實現(xiàn)方法實例分析
這篇文章主要介紹了Android中ListView下拉刷新的實現(xiàn)方法,涉及Android操作ListView的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-10-10