編輯:關於Android編程
Android 6.0版本對於程序員兄弟來說最不友好的就是權限的問題,動態權限的設置曾經讓我很苦惱,目前大部分關於6.0權限設置的框架基本都是一次性訪問多個權限(EasyPermissions),這樣導致的問題就是如果我們申請了三種權限,而用戶只同意了其中一種,下次再申請權限又是一次性申請三種,很不方便對於用戶來說很不友好,偶然情況下發現了安卓猴的這篇文章,
http://sunjiajia.com/2016/04/19/android-m-permissions/
在此基礎上做了修改,就實現了想要的那種效果(仿照微信獲取權限設置,在啟動頁每次只訪問一個權限,用戶同意則繼續訪問下一個權限,如果用戶選擇拒絕,不管用戶選擇的是“不再詢問”還是“拒絕”都視為拒絕,就彈出提示框提示該權限的必要性,指引用戶去打開權限)
下面我們以存儲空間、電話、相機權限為例,
圖片做的不太好,見諒見諒~~
添加權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CALL_PHONE" />
權限處理工具類
package com.fly.permissiondemo; /* * * * * * * =================================== * * * Copyright (c) 2016. * * * 作者:安卓猴 * * * 微博:@安卓猴 * * * 博客:http://sunjiajia.com * * * Github:https://github.com/opengit * * * * * * 注意**:如果您使用或者修改該代碼,請務必保留此版權信息。 * * * =================================== * * * * * */ 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; /** * 權限控制工具類: * 為了適配API23,即Android M 在清單文件中配置use permissions後,還要在程序運行的時候進行申請。 * <p/> * ***整個權限的申請與處理的過程是這樣的: * *****1.進入主Activity,首先申請所有的權限; * *****2.用戶對權限進行授權,有2種情況: * ********1).用戶Allow了權限,則表示該權限已經被授權,無須其它操作; * ********2).用戶Deny了權限,則下次啟動Activity會再次彈出系統的Permisssions申請授權對話框。 * *****3.如果用戶Deny了權限,那麼下次再次進入Activity,會再次申請權限,這次的權限對話框上,會有一個選項“dont ask me again”: * ********1).如果用戶勾選了“dont ask me again”的checkbox,下次啟動時就必須自己寫Dialog或者Snackbar引導用戶到應用設置裡面去手動授予權限; * ********2).如果用戶未勾選上面的選項,若選擇了Allow,則表示該權限已經被授權,無須其它操作; * ********3).如果用戶未勾選上面的選項,若選擇了Deny,則下次啟動Activity會再次彈出系統的Permisssions申請授權對話框。 */ public class PermissionsUtil { // 狀態碼、標志位 public static final int REQUEST_STATUS_CODE = 0x001; public static final int REQUEST_PERMISSION_SETTING = 0x002; //常量字符串數組,將需要申請的權限寫進去,同時必須要在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();//權限都有 void onPermissionsDenied(int requestCode, List<String> perms); } public static void checkAndRequestPermissions(final Activity activity, PermissionCallbacks callback) { if (Build.VERSION.SDK_INT >= 23) { callbacks = callback; // 一個list,用來存放沒有被授權的權限 ArrayList<String> denidArray = new ArrayList<>(); // 遍歷PERMISSIONS_GROUP,將沒有被授權的權限存放進denidArray for (String permission : PERMISSIONS_GROUP_SORT) { int grantCode = ActivityCompat.checkSelfPermission(activity, permission); if (grantCode == PackageManager.PERMISSION_DENIED) { denidArray.add(permission); } } // 如果該字符串數組長度大於0,說明有未被授權的權限 if (denidArray.size() > 0) { //循環處理所有未授權的權限,每次只添加一個權限進行獲取 ArrayList<String> denidArrayNew = new ArrayList<>(); denidArrayNew.add(denidArray.get(0)); // 將denidArray轉化為字符串數組,方便下面調用requestPermissions來請求授權 String[] denidPermissions = denidArrayNew.toArray(new String[denidArrayNew.size()]); requestPermissions(activity, denidPermissions); } else { //已授權 callbacks.onPermissionsGranted(); } } } /** * 關於shouldShowRequestPermissionRationale函數的一點兒注意事項: * ***1).應用安裝後第一次訪問,則直接返回false; * ***2).第一次請求權限時,用戶Deny了,再次調用shouldShowRequestPermissionRationale(),則返回true; * ***3).第二次請求權限時,用戶Deny了,並選擇了“dont ask me again”的選項時,再次調用shouldShowRequestPermissionRationale()時,返回false; * ***4).設備的系統設置中,禁止了應用獲取這個權限的授權,則調用shouldShowRequestPermissionRationale(),返回false。 */ public static boolean showRationaleUI(Activity activity, String permission) { return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission); } /** * 對權限字符串數組中的所有權限進行申請授權,如果用戶選擇了“dont ask me again”,則不會彈出系統的Permission申請授權對話框 */ public static void requestPermissions(Activity activity, String[] permissions) { ActivityCompat.requestPermissions(activity, permissions, REQUEST_STATUS_CODE); } /** * 用來判斷,App是否是首次啟動: * ***由於每次調用shouldShowRequestPermissionRationale得到的結果因情況而變,因此必須判斷一下App是否首次啟動,才能控制好出現Dialog和SnackBar的時機 */ 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; } } }
使用方法:
在啟動頁AppStart跳轉首頁的時候,調用
PermissionsUtil.checkAndRequestPermissions(AppStart.this, new PermissionsUtil.PermissionCallbacks() { @Override public void onPermissionsGranted() { //所有權限都已經獲取到跳轉 toMainActivity(); } @Override public void onPermissionsDenied(int requestCode, List<String> perms) { } });
這個是在AppStart中的回調,現在的處理辦法是,根據每一次提出的權限申請的回調結果來處理對應權限,並且是每一次處理完都會遍歷一次
“PERMISSIONS_GROUP_SORT”,循環處理所有的權限,直到每個權限都獲取到,在“onPermissionsGranted()”中進行跳轉。這樣處理就可以在下次啟動時直接詢問沒有獲得的權限。
@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)) {//讀寫權限 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("在設置-應用-"+ getString(R.string.app_name) +"-權限中開啟存儲空間權限,以正常使用App功能"); } } if (permissions[0].equals(Manifest.permission.CALL_PHONE)) {//電話權限 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("在設置-應用-" + getString(R.string.app_name) + "-權限中開啟電話權限,以正常使用App功能"); } } if (permissions[0].equals(Manifest.permission.CAMERA)) {//電話權限 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//同意 //所有權限均獲取 toMainActivity(); } else {//不同意-提示信息 createLoadedAlertDialog("在設置-應用-"+ getString(R.string.app_name) +"-權限中開啟照相機權限,以正常使用App功能"); } } } }
在設置的權限組裡邊有幾個權限就需要在這個回調中寫幾個判斷來處理對應的友好提示信息,單對單處理,這種方式避免了跟用戶不斷扯犢子,簡單粗暴提示用戶獲取權限,一旦用戶不從,直接跳設置,負責就退出應用。
下面是git地址 https://git.oschina.net/feiyangwei/PermissionDemo.git
這個方案目前還需要完善,如果用戶在打開應用的情況下,去設置裡邊修改權限,我不清楚怎麼監聽這塊權限的修改,微信是直接重新打開應用,這樣就會重新獲取權限,如果有知道的大神可以討論一下 。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
Android TextView 中當文字比較多時希望它橫向滾動顯示,下面是一種親測可行的方法。效果圖:1.自定義TextView,重寫isFocused()方法返回tr
前言我身邊有一部分開發的小伙伴,存在著這樣一種習慣。某一天,突然看到某一款 App 上有個很漂亮的自定義控件(動畫)效果,就會絞盡腦子想辦法去自己實現一發。當然,我自己也
Activity的生命周期圖2 Android生命周期中涉及到的幾個過程 1.啟動Activity:系統會先調用onCreate方法,然後調用onStart方法,最後
做Android應用中,最缺少不了的就是自定義Dialog,對於系統默認提供的Dialog樣式,一般都不復合我們應用的樣式。自定義Dialog需要3步驟即可:1、主要的重