Android6.0仿微信權(quán)限設(shè)置
Android 6.0版本對(duì)于程序員兄弟來說最不友好的就是權(quán)限的問題,動(dòng)態(tài)權(quán)限的設(shè)置曾經(jīng)讓我很苦惱,目前大部分關(guān)于6.0權(quán)限設(shè)置的框架基本都是一次性訪問多個(gè)權(quán)限(EasyPermissions),這樣導(dǎo)致的問題就是如果我們申請(qǐng)了三種權(quán)限,而用戶只同意了其中一種,下次再申請(qǐng)權(quán)限又是一次性申請(qǐng)三種,很不方便對(duì)于用戶來說很不友好,偶然情況下發(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 * * * * * * 注意**:如果您使用或者修改該代碼,請(qǐng)務(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)行申請(qǐng)。 * <p/> * ***整個(gè)權(quán)限的申請(qǐng)與處理的過程是這樣的: * *****1.進(jìn)入主Activity,首先申請(qǐng)所有的權(quán)限; * *****2.用戶對(duì)權(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申請(qǐng)授權(quán)對(duì)話框。 * *****3.如果用戶Deny了權(quán)限,那么下次再次進(jìn)入Activity,會(huì)再次申請(qǐng)權(quán)限,這次的權(quán)限對(duì)話框上,會(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申請(qǐng)授權(quán)對(duì)話框。 */ 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ù)組,將需要申請(qǐng)的權(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來請(qǐng)求授權(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).第一次請(qǐng)求權(quán)限時(shí),用戶Deny了,再次調(diào)用shouldShowRequestPermissionRationale(),則返回true; * ***3).第二次請(qǐng)求權(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); } /** * 對(duì)權(quán)限字符串?dāng)?shù)組中的所有權(quán)限進(jìn)行申請(qǐng)授權(quán),如果用戶選擇了“dont ask me again”,則不會(huì)彈出系統(tǒng)的Permission申請(qǐng)授權(quán)對(duì)話框 */ 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)限申請(qǐng)的回調(diào)結(jié)果來處理對(duì)應(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) { } });//請(qǐng)求 } 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è)判斷來處理對(duì)應(yīng)的友好提示信息,單對(duì)單處理,這種方式避免了跟用戶不斷扯犢子,簡單粗暴提示用戶獲取權(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)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android6.0動(dòng)態(tài)申請(qǐng)權(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)申請(qǐng)框架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)文章
Android SwipeRefreshLayout下拉刷新組件示例
SwipeRefrshLayout是Google官方更新的一個(gè)Widget,可以實(shí)現(xiàn)下拉刷新的效果。本文主要介紹了Android之SwipeRefreshLayout下拉刷新組件示例,有興趣的可以了解一下。2017-02-02Android入門之Gallery+ImageSwitcher用法實(shí)例解析
這篇文章主要介紹了Android入門之Gallery+ImageSwitcher用法,對(duì)Android初學(xué)者有很好的參考借鑒價(jià)值,需要的朋友可以參考下2014-08-08Android 實(shí)現(xiàn)夜間模式的快速簡單方法實(shí)例詳解
這篇文章主要介紹了Android 實(shí)現(xiàn)夜間模式的快速簡單方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09淺析Android手機(jī)衛(wèi)士保存手機(jī)安全號(hào)碼
這篇文章主要介紹了淺析Android手機(jī)衛(wèi)士保存手機(jī)安全號(hào)碼的相關(guān)資料,需要的朋友可以參考下2016-04-04開源自研內(nèi)存分析利器Android?Bitmap?Monitor圖片定位詳解
這篇文章主要為大家介紹了Android?Bitmap?Monitor開源自研內(nèi)存分析利器,助你定位不合理的圖片使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Android實(shí)現(xiàn)自動(dòng)播放圖片功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)自動(dòng)播放圖片功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06android startActivityForResult的使用方法介紹
android startActivityForResult的使用方法介紹,需要的朋友可以參考一下2013-05-05Android中利用matrix 控制圖片的旋轉(zhuǎn)、縮放、移動(dòng)
本篇文章是對(duì)Android中利用matrix 控制圖片的旋轉(zhuǎn)、縮放、移動(dòng)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Jsoup 抓取頁面的數(shù)據(jù)實(shí)例詳解
這篇文章主要介紹了Jsoup 抓取頁面的數(shù)據(jù)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12