Android6.0仿微信權(quán)限設(shè)置
Android 6.0版本對于程序員兄弟來說最不友好的就是權(quán)限的問題,動(dòng)態(tài)權(quán)限的設(shè)置曾經(jīng)讓我很苦惱,目前大部分關(guān)于6.0權(quán)限設(shè)置的框架基本都是一次性訪問多個(gè)權(quán)限(EasyPermissions),這樣導(dǎo)致的問題就是如果我們申請了三種權(quán)限,而用戶只同意了其中一種,下次再申請權(quán)限又是一次性申請三種,很不方便對于用戶來說很不友好,偶然情況下發(fā)現(xiàn)了安卓猴的這篇文章,
http://sunjiajia.com/2016/04/19/android-m-permissions/
在此基礎(chǔ)上做了修改,就實(shí)現(xiàn)了想要的那種效果(仿照微信獲取權(quán)限設(shè)置,在啟動(dòng)頁每次只訪問一個(gè)權(quán)限,用戶同意則繼續(xù)訪問下一個(gè)權(quán)限,如果用戶選擇拒絕,不管用戶選擇的是“不再詢問”還是“拒絕”都視為拒絕,就彈出提示框提示該權(quán)限的必要性,指引用戶去打開權(quán)限)
下面我們以存儲(chǔ)空間、電話、相機(jī)權(quán)限為例,
圖片做的不太好,見諒見諒~~


添加權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CALL_PHONE" />
權(quán)限處理工具類
package com.fly.permissiondemo;
/*
*
* *
* * * ===================================
* * * Copyright (c) 2016.
* * * 作者:安卓猴
* * * 微博:@安卓猴
* * * 博客:http://sunjiajia.com
* * * Github:https://github.com/opengit
* * *
* * * 注意**:如果您使用或者修改該代碼,請務(wù)必保留此版權(quán)信息。
* * * ===================================
* *
* *
*
*/
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import java.util.ArrayList;
import java.util.List;
/**
* 權(quán)限控制工具類:
* 為了適配API23,即Android M 在清單文件中配置use permissions后,還要在程序運(yùn)行的時(shí)候進(jìn)行申請。
* <p/>
* ***整個(gè)權(quán)限的申請與處理的過程是這樣的:
* *****1.進(jìn)入主Activity,首先申請所有的權(quán)限;
* *****2.用戶對權(quán)限進(jìn)行授權(quán),有2種情況:
* ********1).用戶Allow了權(quán)限,則表示該權(quán)限已經(jīng)被授權(quán),無須其它操作;
* ********2).用戶Deny了權(quán)限,則下次啟動(dòng)Activity會(huì)再次彈出系統(tǒng)的Permisssions申請授權(quán)對話框。
* *****3.如果用戶Deny了權(quán)限,那么下次再次進(jìn)入Activity,會(huì)再次申請權(quán)限,這次的權(quán)限對話框上,會(huì)有一個(gè)選項(xiàng)“dont ask me again”:
* ********1).如果用戶勾選了“dont ask me again”的checkbox,下次啟動(dòng)時(shí)就必須自己寫Dialog或者Snackbar引導(dǎo)用戶到應(yīng)用設(shè)置里面去手動(dòng)授予權(quán)限;
* ********2).如果用戶未勾選上面的選項(xiàng),若選擇了Allow,則表示該權(quán)限已經(jīng)被授權(quán),無須其它操作;
* ********3).如果用戶未勾選上面的選項(xiàng),若選擇了Deny,則下次啟動(dòng)Activity會(huì)再次彈出系統(tǒng)的Permisssions申請授權(quán)對話框。
*/
public class PermissionsUtil {
// 狀態(tài)碼、標(biāo)志位
public static final int REQUEST_STATUS_CODE = 0x001;
public static final int REQUEST_PERMISSION_SETTING = 0x002;
//常量字符串?dāng)?shù)組,將需要申請的權(quán)限寫進(jìn)去,同時(shí)必須要在Androidmanifest.xml中聲明。
public static String[] PERMISSIONS_GROUP_SORT = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE,
Manifest.permission.CAMERA
};
private static PermissionCallbacks callbacks;
public interface PermissionCallbacks {
void onPermissionsGranted();//權(quán)限都有
void onPermissionsDenied(int requestCode, List<String> perms);
}
public static void checkAndRequestPermissions(final Activity activity, PermissionCallbacks callback) {
if (Build.VERSION.SDK_INT >= 23) {
callbacks = callback;
// 一個(gè)list,用來存放沒有被授權(quán)的權(quán)限
ArrayList<String> denidArray = new ArrayList<>();
// 遍歷PERMISSIONS_GROUP,將沒有被授權(quán)的權(quán)限存放進(jìn)denidArray
for (String permission : PERMISSIONS_GROUP_SORT) {
int grantCode = ActivityCompat.checkSelfPermission(activity, permission);
if (grantCode == PackageManager.PERMISSION_DENIED) {
denidArray.add(permission);
}
}
// 如果該字符串?dāng)?shù)組長度大于0,說明有未被授權(quán)的權(quán)限
if (denidArray.size() > 0) {
//循環(huán)處理所有未授權(quán)的權(quán)限,每次只添加一個(gè)權(quán)限進(jìn)行獲取
ArrayList<String> denidArrayNew = new ArrayList<>();
denidArrayNew.add(denidArray.get(0));
// 將denidArray轉(zhuǎn)化為字符串?dāng)?shù)組,方便下面調(diào)用requestPermissions來請求授權(quán)
String[] denidPermissions = denidArrayNew.toArray(new String[denidArrayNew.size()]);
requestPermissions(activity, denidPermissions);
} else {
//已授權(quán)
callbacks.onPermissionsGranted();
}
}
}
/**
* 關(guān)于shouldShowRequestPermissionRationale函數(shù)的一點(diǎn)兒注意事項(xiàng):
* ***1).應(yīng)用安裝后第一次訪問,則直接返回false;
* ***2).第一次請求權(quán)限時(shí),用戶Deny了,再次調(diào)用shouldShowRequestPermissionRationale(),則返回true;
* ***3).第二次請求權(quán)限時(shí),用戶Deny了,并選擇了“dont ask me again”的選項(xiàng)時(shí),再次調(diào)用shouldShowRequestPermissionRationale()時(shí),返回false;
* ***4).設(shè)備的系統(tǒng)設(shè)置中,禁止了應(yīng)用獲取這個(gè)權(quán)限的授權(quán),則調(diào)用shouldShowRequestPermissionRationale(),返回false。
*/
public static boolean showRationaleUI(Activity activity, String permission) {
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
}
/**
* 對權(quán)限字符串?dāng)?shù)組中的所有權(quán)限進(jìn)行申請授權(quán),如果用戶選擇了“dont ask me again”,則不會(huì)彈出系統(tǒng)的Permission申請授權(quán)對話框
*/
public static void requestPermissions(Activity activity, String[] permissions) {
ActivityCompat.requestPermissions(activity, permissions, REQUEST_STATUS_CODE);
}
/**
* 用來判斷,App是否是首次啟動(dòng):
* ***由于每次調(diào)用shouldShowRequestPermissionRationale得到的結(jié)果因情況而變,因此必須判斷一下App是否首次啟動(dòng),才能控制好出現(xiàn)Dialog和SnackBar的時(shí)機(jī)
*/
public static boolean isAppFirstRun(Activity activity) {
SharedPreferences sp = activity.getSharedPreferences("config", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (sp.getBoolean("first_run", true)) {
editor.putBoolean("first_run", false);
editor.commit();
return true;
} else {
editor.putBoolean("first_run", false);
editor.commit();
return false;
}
}
}
使用方法:
在啟動(dòng)頁AppStart跳轉(zhuǎn)首頁的時(shí)候,調(diào)用
PermissionsUtil.checkAndRequestPermissions(AppStart.this, new PermissionsUtil.PermissionCallbacks() {
@Override
public void onPermissionsGranted() {
//所有權(quán)限都已經(jīng)獲取到跳轉(zhuǎn)
toMainActivity();
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
});
這個(gè)是在AppStart中的回調(diào),現(xiàn)在的處理辦法是,根據(jù)每一次提出的權(quán)限申請的回調(diào)結(jié)果來處理對應(yīng)權(quán)限,并且是每一次處理完都會(huì)遍歷一次
“PERMISSIONS_GROUP_SORT”,循環(huán)處理所有的權(quán)限,直到每個(gè)權(quán)限都獲取到,在“onPermissionsGranted()”中進(jìn)行跳轉(zhuǎn)。這樣處理就可以在下次啟動(dòng)時(shí)直接詢問沒有獲得的權(quán)限。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PermissionsUtil.REQUEST_STATUS_CODE) {
if (permissions[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE)) {//讀寫權(quán)限
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//同意
PermissionsUtil.checkAndRequestPermissions(this, new PermissionsUtil.PermissionCallbacks() {
@Override
public void onPermissionsGranted() {
toMainActivity();
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
});//請求
} else {//不同意-提示信息
createLoadedAlertDialog("在設(shè)置-應(yīng)用-"+ getString(R.string.app_name) +"-權(quán)限中開啟存儲(chǔ)空間權(quán)限,以正常使用App功能");
}
}
if (permissions[0].equals(Manifest.permission.CALL_PHONE)) {//電話權(quán)限
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//同意
PermissionsUtil.checkAndRequestPermissions(this, new PermissionsUtil.PermissionCallbacks() {
@Override
public void onPermissionsGranted() {
toMainActivity();
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
});
} else {//不同意-提示信息
createLoadedAlertDialog("在設(shè)置-應(yīng)用-" + getString(R.string.app_name) + "-權(quán)限中開啟電話權(quán)限,以正常使用App功能");
}
}
if (permissions[0].equals(Manifest.permission.CAMERA)) {//電話權(quán)限
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//同意
//所有權(quán)限均獲取
toMainActivity();
} else {//不同意-提示信息
createLoadedAlertDialog("在設(shè)置-應(yīng)用-"+ getString(R.string.app_name) +"-權(quán)限中開啟照相機(jī)權(quán)限,以正常使用App功能");
}
}
}
}
在設(shè)置的權(quán)限組里邊有幾個(gè)權(quán)限就需要在這個(gè)回調(diào)中寫幾個(gè)判斷來處理對應(yīng)的友好提示信息,單對單處理,這種方式避免了跟用戶不斷扯犢子,簡單粗暴提示用戶獲取權(quán)限,一旦用戶不從,直接跳設(shè)置,負(fù)責(zé)就退出應(yīng)用。
下面是git地址 https://git.oschina.net/feiyangwei/PermissionDemo.git
這個(gè)方案目前還需要完善,如果用戶在打開應(yīng)用的情況下,去設(shè)置里邊修改權(quán)限,我不清楚怎么監(jiān)聽這塊權(quán)限的修改,微信是直接重新打開應(yīng)用,這樣就會(huì)重新獲取權(quán)限,如果有知道的大神可以討論一下 。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android6.0動(dòng)態(tài)申請權(quán)限所遇到的問題小結(jié)
- 談?wù)凙ndroid6.0運(yùn)行時(shí)的權(quán)限處理
- 詳解Android6.0運(yùn)行時(shí)權(quán)限管理
- 一款不錯(cuò)的android6.0、7.0權(quán)限管理器推薦
- android6.0權(quán)限動(dòng)態(tài)申請框架permissiondispatcher的方法
- Android 操作系統(tǒng)獲取Root權(quán)限 原理詳細(xì)解析
- Android獲取ROOT權(quán)限的實(shí)例代碼
- Android權(quán)限操作之uses-permission詳解
- Android權(quán)限控制之自定義權(quán)限
- Android需要提升權(quán)限的操作方法
- 安卓Android6.0權(quán)限動(dòng)態(tài)獲取操作示例
相關(guān)文章
通過FancyView提供 Android 酷炫的開屏動(dòng)畫實(shí)例代碼
這篇文章主要介紹了通過FancyView提供 Android 酷炫的開屏動(dòng)畫的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-12-12
Android中的android:layout_weight使用詳解
layout_weight的作用是設(shè)置子空間在LinearLayout的重要度(控件的大小比重)。layout_weight的值越低,則控件越重要,下面為大家介紹下具體的使用方法2013-06-06
Flutter實(shí)現(xiàn)漸變弧形進(jìn)度條的示例詳解
在Flutter開發(fā)中,構(gòu)建一個(gè)具有視覺吸引力的、反映進(jìn)度的圓形弧形進(jìn)度條是一個(gè)常見需求,本文將詳細(xì)介紹如何使用Flutter和Dart語言實(shí)現(xiàn)這一功能,需要的可以參考下2023-12-12
Flutter中跨組件數(shù)據(jù)傳遞的方法總結(jié)
Flutter中的數(shù)據(jù)傳遞一般包括:父->子,子->父,父->父,也就是說嵌套時(shí)的傳遞以及跨頁面的傳遞,本文整理了三種我們通常使用的方法,需要的可以參考一下2023-06-06
Android HttpURLConnection下載網(wǎng)絡(luò)圖片設(shè)置系統(tǒng)壁紙
這篇文章主要為大家詳細(xì)介紹了Android HttpURLConnection下載網(wǎng)絡(luò)圖片設(shè)置系統(tǒng)壁紙,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
android Socket實(shí)現(xiàn)簡單聊天小程序
這篇文章主要為大家詳細(xì)介紹了android Socket實(shí)現(xiàn)簡單聊天小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

