之前調(diào)試的時(shí)候,出現(xiàn)了一個(gè)問(wèn)題,就是當(dāng)我打開(kāi)二維碼掃描界面的時(shí)候,對(duì)于一部分手機(jī)一直不會(huì)出現(xiàn)那個(gè)掃描框,這點(diǎn)我也很是郁悶,這不好整啊,畢竟二維碼界面是用的別人的,怎么改啊?這個(gè)時(shí)候我分析了一下原因,最后知道只有部分6.0的手機(jī)才會(huì)出現(xiàn)這種情況,那么這就簡(jiǎn)單了。下面我就對(duì)關(guān)于6.0手機(jī)動(dòng)態(tài)申請(qǐng)安全權(quán)限做一下講解:
對(duì)于6.0以下的權(quán)限及在安裝的時(shí)候,根據(jù)權(quán)限聲明產(chǎn)生一個(gè)權(quán)限列表,用戶只有在同意之后才能完成app的安裝,造成了我們想要使用某個(gè)app,就只能默認(rèn)接受其一些不必要的權(quán)限,而在6.0以后,當(dāng)app需要我們授予不恰當(dāng)?shù)臋?quán)限的時(shí)候,我們可以予以拒絕。但是這些權(quán)限也是有限制的,比如說(shuō)只是針對(duì)一些安全權(quán)限做動(dòng)態(tài)授權(quán)處理,如打開(kāi)手機(jī)攝像頭、打開(kāi)聯(lián)系人、打開(kāi)錄音等等,這些涉及到用戶安全權(quán)限的時(shí)候,就要我們開(kāi)發(fā)者手動(dòng)去請(qǐng)求用戶打開(kāi)權(quán)限。廢話就到這里,下面看具體實(shí)現(xiàn)。
1、檢查權(quán)限:
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
}else{
//
}
ContextCompat.checkSelfPermission,主要用于檢測(cè)某個(gè)權(quán)限是否已經(jīng)被授予,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。當(dāng)返回DENIED就需要進(jìn)行申請(qǐng)授權(quán)了。
2、申請(qǐng)權(quán)限:
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
第二個(gè)參數(shù)是需要申請(qǐng)的權(quán)限的字符串?dāng)?shù)組,第三個(gè)參數(shù)為請(qǐng)求碼,主要用于回調(diào)的時(shí)候檢測(cè)。可以從方法名requestPermissions以及第二個(gè)參數(shù)看出,是支持一次性申請(qǐng)多個(gè)權(quán)限的,系統(tǒng)會(huì)通過(guò)彈出對(duì)話框一個(gè)個(gè)的詢問(wèn)用戶是否授權(quán)。
3、權(quán)限的申請(qǐng)回調(diào):
@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;
}
}
}
首先驗(yàn)證請(qǐng)求碼并結(jié)合你的申請(qǐng),然后驗(yàn)證grantResults對(duì)應(yīng)的申請(qǐng)的結(jié)果,如果你申請(qǐng)的權(quán)限數(shù)組有兩個(gè)權(quán)限,那么grantResults的length就為2
還有一點(diǎn):
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS))
// Show an expanation to the userasynchronously– don’t block
// this thread waiting for the user’s response! After the user
// sees the explanation, try again to request the permission.
}
這個(gè)方法就是給用戶一個(gè)權(quán)限申請(qǐng)作出必要的解釋,比如用戶第一次拒絕過(guò)你的權(quán)限申請(qǐng),現(xiàn)在你又點(diǎn)擊拍照,那么久需要調(diào)用這個(gè)方法,作出一個(gè)解釋,解釋為什么需要拍照權(quán)限。
好了,到這里估計(jì)你會(huì)說(shuō),怎么感覺(jué)有點(diǎn)小麻煩呢! 沒(méi)錯(cuò),勞資也感覺(jué)是很麻煩啊,我的理念就是統(tǒng)統(tǒng)一條方法解決一個(gè)問(wèn)題,那么,這時(shí)候上面的都不要再去看了,什么鬼東西,只需要在你的BaseActivity或者BaseFragment中添加幾行我的下面的代碼,然后調(diào)用的時(shí)候,就是一行代碼搞定。(上面的部分統(tǒng)統(tǒng)略去,下面的才是今天的主要)
在你的BaseActivity或者BaseFragment中添加幾行下面的代碼就行了:
private int mPermissionIdx = 0x10;//請(qǐng)求權(quán)限索引
private SparseArray mPermissions = new SparseArray<>();//請(qǐng)求權(quán)限運(yùn)行列表
@SuppressLint("Override")
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
GrantedResult runnable = mPermissions.get(requestCode);
if (runnable == null) {
return;
}
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
runnable.mGranted = true;
}
runOnUiThread(runnable);
}
public void requestPermission(String[] permissions, String reason, GrantedResult runnable) {
if(runnable == null){
return;
}
runnable.mGranted = false;
if (Build.VERSION.SDK_INT < 23 || permissions == null || permissions.length == 0) {
runnable.mGranted = true;//新添加
runOnUiThread(runnable);
return;
}
final int requestCode = mPermissionIdx++;
mPermissions.put(requestCode, runnable);
/*
是否需要請(qǐng)求權(quán)限
*/
boolean granted = true;
for (String permission : permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
granted = granted && checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
}
if (granted) {
runnable.mGranted = true;
runOnUiThread(runnable);
return;
}
/*
是否需要請(qǐng)求彈出窗
*/
boolean request = true;
for (String permission : permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
request = request && !shouldShowRequestPermissionRationale(permission);
}
}
if (!request) {
final String[] permissionTemp = permissions;
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage(reason)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissionTemp, requestCode);
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
GrantedResult runnable = mPermissions.get(requestCode);
if (runnable == null) {
return;
}
runnable.mGranted = false;
runOnUiThread(runnable);
}
}).create();
dialog.show();
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, requestCode);
}
}
}
public static abstract class GrantedResult implements Runnable{
private boolean mGranted;
public abstract void onResult(boolean granted);
@Override
public void run(){
onResult(mGranted);
}
}
那么最最重要的來(lái)了,那就是用法咯:(往下接著看)
比如說(shuō)你需要點(diǎn)擊一下拍照按鈕就打開(kāi)系統(tǒng)的攝像頭進(jìn)行拍照,那么就在你打開(kāi)按鈕的監(jiān)聽(tīng)事件中這么寫:(比如說(shuō)是在CarmerActivity中,繼承BaseActivity)
openCarmer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermission(new String[]{Manifest.permission.CAMERA}, “請(qǐng)求設(shè)備相機(jī)權(quán)限”, new GrantedResult() {
@Override
public void onResult(boolean granted) {
if(granted){//表示用戶允許
createLocalStream();
}else {//用戶拒絕
Toast.makeText(MainActivity.this,”權(quán)限拒絕”,Toast.LENGTH_SHORT).show();
}
}
});
}
});
同樣的在fragment中一樣可以使用,即((AbsBaseActivity)getActivity()).requestPermission(...)這種方式即可,當(dāng)首次彈出系統(tǒng)授權(quán)彈出框,如果用戶點(diǎn)擊拒絕的話,那么第二次再次需要該權(quán)限的話,會(huì)打開(kāi)自定義的提示框且提示自定義的提示描述,所以動(dòng)態(tài)授權(quán)還是非常的人性化的。最后提示一下,如果你覺(jué)得在應(yīng)用內(nèi)每次都是用到的時(shí)候才去授權(quán)比較麻煩,那么你也可以在用戶剛進(jìn)入應(yīng)用后的啟動(dòng)頁(yè)面一次性開(kāi)啟所有的安全權(quán)限,這種方式更加的簡(jiǎn)便。
ok,大功告成!!!