前言:
Android 6.0 為了保護(hù)用戶隱私廉赔,將一些權(quán)限的申請放在了應(yīng)用運(yùn)行的時(shí)候去申請芋浮, 比如以往的開發(fā)中招狸,開發(fā)人員只需要將需要的權(quán)限在清單文件中配置即可婿滓,安裝后用戶可以在設(shè)置中的應(yīng)用信息中看到:XX應(yīng)用以獲取****權(quán)限甜孤。用戶點(diǎn)擊可以選擇給應(yīng)用相應(yīng)的權(quán)限协饲。此前的應(yīng)用權(quán)限用戶可以選擇允許、提醒和拒絕缴川。在安裝的時(shí)候用戶是已經(jīng)知道應(yīng)用需要的權(quán)限的茉稠。但是這樣存在一個(gè)問題,就是用戶在安裝的時(shí)候把夸,應(yīng)用需要的權(quán)限十分的多(有些開發(fā)者為了省事而线,會請求一些不必要的權(quán)限或者請求全部的權(quán)限),這個(gè)時(shí)候用戶在安裝應(yīng)用的時(shí)候也許并沒有發(fā)現(xiàn)某些侵犯自己隱私的權(quán)限請求恋日,安裝之后才發(fā)現(xiàn)自己的隱私數(shù)據(jù)被竊取膀篮。其實(shí)Android6.0 動態(tài)權(quán)限一方面是為了廣大用戶考慮,另一方面其實(shí)是Google為了避免一些不必要的官司岂膳。
目前針對Android6.0權(quán)限適配的邏輯代碼誓竿,網(wǎng)上已經(jīng)很多了。這里針對用戶拒絕了權(quán)限請求并且選擇了□ 不在提示”時(shí)該如何處理谈截。
權(quán)限流程:
▲在Api 23中, 權(quán)限需要?jiǎng)討B(tài)獲取, 核心權(quán)限必須滿足. 標(biāo)準(zhǔn)流程:
▲但這里有個(gè)問題筷屡,那就是在系統(tǒng)授權(quán)彈窗環(huán)節(jié)涧偷,提醒框會有個(gè)不再提示的復(fù)選框,如果用戶點(diǎn)擊不再提示毙死,并拒絕授權(quán)燎潮,那么再下次授權(quán)的時(shí)候,系統(tǒng)授權(quán)彈窗的提示框就不會在提示扼倘,所以我們很有必要需要自定義權(quán)限彈窗提示框确封,那么流程圖就變成如下了。
權(quán)限類型:
▲ 在圖中唉锌,我們可以看到整個(gè)權(quán)限里隅肥,可以分為系統(tǒng)權(quán)限和特殊權(quán)限授權(quán)。系統(tǒng)權(quán)限中袄简,又分為normal和dangerous類型腥放。
normal:這個(gè)權(quán)限類型并不直接威脅到用戶的隱私,可以直接在manifest清單里注冊绿语,系統(tǒng)會幫我們默認(rèn)授權(quán)的秃症。
dangerous:這個(gè)可以直接給app訪問用戶一些敏感的數(shù)據(jù),不僅需要在manifest清單里注冊吕粹,同時(shí)在使用的時(shí)候种柑,需要向系統(tǒng)請求授權(quán)。
值得注意一點(diǎn)匹耕,這里有特殊權(quán)限授權(quán)的區(qū)別聚请,分別是SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,雖然這兩個(gè)權(quán)限也是屬于dangerous權(quán)限類型稳其,但是這兩個(gè)授權(quán)請求方式和其他dangerous權(quán)限是不一樣的驶赏,需要特殊處理 。
案例介紹:
根據(jù)官方介紹既鞠,當(dāng)發(fā)起首次權(quán)限請求時(shí)不會提供“不再提示”這一選擇煤傍,但如果用戶之前拒絕過權(quán)限請求并且再次發(fā)起權(quán)限請求時(shí),權(quán)限請求對話框才會提供“不在提示”這一選項(xiàng)供用戶選擇嘱蛋,當(dāng)用戶選擇了“不再提示”之后就不會再彈出權(quán)限請求對話框蚯姆。各大手機(jī)廠商的定制系統(tǒng)對該邏輯進(jìn)行了一定的改動,例如小米MIUI系統(tǒng)當(dāng)用戶首次選擇拒絕權(quán)限時(shí)之后就會“不在提示”了洒敏,華為EMUI系統(tǒng)在首次彈出權(quán)限請求時(shí)就會提供“不在提示”的選項(xiàng)龄恋,三星部分系統(tǒng)始終不提供“不在提示”的選項(xiàng)。
當(dāng)用戶選擇了“不在提示”時(shí),開發(fā)者需要引導(dǎo)用戶去設(shè)置頁手動授權(quán)!
但是android 6.0系統(tǒng)并未提供對“不在提示”這一選項(xiàng)的監(jiān)聽摇零,那么開發(fā)者該如何判斷用戶是否選擇了“不在提示”這一選項(xiàng)呢柳刮?
答案是通過shouldShowRequestPermissionRationale()這一方法豁翎。
這一方法的作用是判斷是否需要向用戶解釋為何需要請求該權(quán)限主经。
當(dāng)首次發(fā)起權(quán)限請求時(shí)該方法返回false陪白。
當(dāng)?shù)诙螜?quán)限請求時(shí)該方法返回true窍株。
當(dāng)發(fā)起第二次權(quán)限請求并且當(dāng)用戶選擇了“不再提示”這一選項(xiàng)時(shí)該方法返回false煮落。 通過這個(gè)邏輯我們可以反推出:當(dāng)進(jìn)行第二次權(quán)限請求被拒絕并且shouldShowRequestPermissionRationale()返回false時(shí)敞峭,那么該用戶一定是選擇了“不再提示”這一選項(xiàng)。
▲以RECORD_AUDIO蝉仇,CAMERA旋讹,READ_EXTERNAL_STORAGE為例。全部權(quán)限請求成功轿衔,直接看妹砸沉迹。下面看圖 ヾ(?°?°?)?? 沒圖我會亂說
▲當(dāng)部分權(quán)限受限,且用戶未選中“不再提示”害驹,彈出對話框說明鞭呕,并進(jìn)行請求權(quán)限
▲當(dāng)部分權(quán)限受限,且用戶選中“不再提示”宛官,彈出對話框說明葫松,引導(dǎo)用戶到設(shè)置頁手動授權(quán)
▲主要代碼BaseActivity.java
package com.donkor.demo.permission;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
private final int mRequestCode = 1024;
private RequestPermissionCallBack mRequestPermissionCallBack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/**
* 權(quán)限請求結(jié)果回調(diào)
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
boolean hasAllGranted = true;
StringBuilder permissionName = new StringBuilder();
for (String s : permissions) {
permissionName = permissionName.append(s + "\r\n");
}
switch (requestCode) {
case mRequestCode: {
for (int i = 0; i < grantResults.length; ++i) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
hasAllGranted = false;
//在用戶已經(jīng)拒絕授權(quán)的情況下,如果shouldShowRequestPermissionRationale返回false則
// 可以推斷出用戶選擇了“不在提示”選項(xiàng)底洗,在這種情況下需要引導(dǎo)用戶至設(shè)置頁手動授權(quán)
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
new AlertDialog.Builder(BaseActivity.this).setTitle("PermissionTest")//設(shè)置對話框標(biāo)題
.setMessage("【用戶選擇了不再提示按鈕腋么,或者系統(tǒng)默認(rèn)不在提示(如MIUI)。" +
"引導(dǎo)用戶到應(yīng)用設(shè)置頁去手動授權(quán),注意提示用戶具體需要哪些權(quán)限】" +
"獲取相關(guān)權(quán)限失敗:" + permissionName +
"將導(dǎo)致部分功能無法正常使用亥揖,需要到設(shè)置頁面手動授權(quán)")//設(shè)置顯示的內(nèi)容
.setPositiveButton("去授權(quán)", new DialogInterface.OnClickListener() {//添加確定按鈕
@Override
public void onClick(DialogInterface dialog, int which) {//確定按鈕的響應(yīng)事件
//TODO Auto-generated method stub
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getApplicationContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
dialog.dismiss();
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加返回按鈕
@Override
public void onClick(DialogInterface dialog, int which) {//響應(yīng)事件
// TODO Auto-generated method stub
dialog.dismiss();
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
mRequestPermissionCallBack.denied();
}
}).show();//在按鍵響應(yīng)事件中顯示此對話框
} else {
//用戶拒絕權(quán)限請求珊擂,但未選中“不再提示”選項(xiàng)
mRequestPermissionCallBack.denied();
}
break;
}
}
if (hasAllGranted) {
mRequestPermissionCallBack.granted();
}
}
}
}
/**
* 發(fā)起權(quán)限請求
*
* @param context
* @param permissions
* @param callback
*/
public void requestPermissions(final Context context, final String[] permissions,
RequestPermissionCallBack callback) {
this.mRequestPermissionCallBack = callback;
StringBuilder permissionNames = new StringBuilder();
for (String s : permissions) {
permissionNames = permissionNames.append(s + "\r\n");
}
//如果所有權(quán)限都已授權(quán),則直接返回授權(quán)成功,只要有一項(xiàng)未授權(quán)费变,則發(fā)起權(quán)限請求
boolean isAllGranted = true;
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED) {
isAllGranted = false;
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission)) {
new AlertDialog.Builder(BaseActivity.this).setTitle("PermissionTest")//設(shè)置對話框標(biāo)題
.setMessage("【用戶曾經(jīng)拒絕過你的請求未玻,所以這次發(fā)起請求時(shí)解釋一下】" +
"您好,需要如下權(quán)限:" + permissionNames +
" 請?jiān)试S胡控,否則將影響部分功能的正常使用。")//設(shè)置顯示的內(nèi)容
.setPositiveButton("確定", new DialogInterface.OnClickListener() {//添加確定按鈕
@Override
public void onClick(DialogInterface dialog, int which) {//確定按鈕的響應(yīng)事件
//TODO Auto-generated method stub
ActivityCompat.requestPermissions(((Activity) context), permissions, mRequestCode);
}
}).show();//在按鍵響應(yīng)事件中顯示此對話框
} else {
ActivityCompat.requestPermissions(((Activity) context), permissions, mRequestCode);
}
break;
}
}
if (isAllGranted) {
mRequestPermissionCallBack.granted();
return;
}
}
/**
* 權(quán)限請求結(jié)果回調(diào)接口
*/
interface RequestPermissionCallBack {
/**
* 同意授權(quán)
*/
void granted();
/**
* 取消授權(quán)
*/
void denied();
}
}
▲SplashActivity.java中Button請求權(quán)限主要代碼
requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE},
new RequestPermissionCallBack() {
@Override
public void granted() {
Toast.makeText(SplashActivity.this, "權(quán)限獲取成功旁趟,執(zhí)行下一步操作", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
SplashActivity.this.finish();
}
@Override
public void denied() {
Toast.makeText(SplashActivity.this, "部分權(quán)限獲取失敗昼激,正常功能受到影響,2秒鐘之后自動退出", Toast.LENGTH_LONG).show();
//2秒鐘之后自動退出
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
SplashActivity.this.finish();
}
}, 2000);
}
});
資料與參考:
http://www.cnblogs.com/cr330326/p/5181283.html
http://blog.csdn.net/caroline_wendy/article/details/50587230
妹砸照片及源碼下載地址 : https://github.com/ChenYXin/PermissionDemo
關(guān)于我:
- Android開發(fā)交流QQ群:537891203
- 郵箱:donkor@yeah.net