Android之动态申请权限
Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户。在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的需要动态授予。
Android 6.0以下,在AndroidManifest.xml文件中注册权限即可。
Android 6.0及其以后,既要在AndroidManifest.xml文件中注册,又要动态申请危险权限。
如果没有进行动态申请权限将报下面的权限问题的错
1.动态申请权限
打电话的动态申请权限例子
package com.example.androidnetwork;import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import org.jetbrains.annotations.NotNull;import butterknife.BindView;
import butterknife.ButterKnife;import static android.os.Build.VERSION_CODES.M;public class TestActivity extends AppCompatActivity {private static final String TAG = "TestActivity";private Button mButton;//请求码private int REQUESTCODE=1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);ButterKnife.bind(this);mButton = findViewById(R.id.buttonTest);// getExternalFilesDir(Environment.DIRECTORY_PICTURES);}private void checkPermission() {//1.判断当前手机系统是否大于或等于6.0//4.如果有打电话的授权,就直接拨打电话//1.判断当前手机系统是否大于或等于6.0if(Build.VERSION.SDK_INT>=M){//2.如果大于6.0,则检查是否有打电话的权限授权int isPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);//用于检测程序是否包含某项权限//下面的log如果程序第一次运行checkPermission一般是-1,需要下面的ActivityCompat.requestPermissions去动态//申请权限,当你动态申请过一次后下次就不是-1了,除非删掉程序。Log.d(TAG, "checkPermission: "+isPermission);if(isPermission== PackageManager.PERMISSION_GRANTED){//4.如果有打电话的授权,就直接拨打电话call();}else {//3.如果没有打电话的授权,就要去申请打电话的权限//下面为申请权限的方法,下面的onRequestPermissionsResult方法用于验证此方法申请成功或失败(到时会弹出一个对话框给你选择允许拒绝)//也会导致回调onRequestPermissionsResult方法ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CALL_PHONE},REQUESTCODE);}}else {//5.如果当前版本小于6.0,直接拨打电话call();}}/*此函数为申请权限的回调方法,无论成功或者失败,都会回调这个方法requestCode:上文中提到的请求码permissions:申请的权限grantResults:申请的结果*/@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode==REQUESTCODE){if(grantResults!=null&&grantResults.length>0){//判断用户是否授予了这个权限//因为目前只有打电话这一个权限结果所以使用grantResults[0]if(grantResults[0]==PackageManager.PERMISSION_GRANTED){call();}else {Toast.makeText(this,"您拒绝了拨打电话的权限",Toast.LENGTH_SHORT).show();}}}}public void call(){//下面这个可以使用this的原因是编译时,他没有new一个实现类或者内部类,不然的话就要类名.this//Toast.makeText(this,"你好啊",Toast.LENGTH_SHORT).show();Intent intent = new Intent(Intent.ACTION_CALL);Uri uri = Uri.parse("tel:" + 1008611);intent.setData(uri);startActivity(intent);Log.d(TAG, "text: "+"跳转了");}public void text(View view){checkPermission();}
}
PackageManager.PERMISSION_GRANTED 与 PackageManager.PERMISSION_DENIED ,分别代表着有权限与无权限。通常我们会根据当前权限的状态来决定是否去申请相关权限。
具体内容可看程序注释,比较详细
2.动态申请权限工具类的封装
封装工具类
package com.example.androidnetwork.utils;import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;import android.provider.Settings;
import android.util.Log;import android.widget.Toast;import androidx.core.app.ActivityCompat;/*
申请多个权限的工具类*/
public class PermissionUtils {//请求码public final static int CODE_RECERD_AUDIO = 0;public final static int CODE_GET_ACCOUNTS = 1;public final static int CODE_READ_PHONE_STATE = 2;public final static int CODE_CALL_PHONE = 3;public final static int CODE_CAMERA = 4;public final static int CODE_ACCESS_FINE_LOCATION = 5;public final static int CODE_ACCESS_COARSE_LOCATION = 6;public final static int CODE_READ_EXTERNAL_STORAGE = 7;public final static int CODE_WRITE_EXTERNAL_STORAGE = 8;//权限的名称public static final String PERMISSION_RECERD_AUDIO = Manifest.permission.RECORD_AUDIO;public static final String PERMISSION_GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;public static final String PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;public static final String PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;public static final String PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;//放进数组进行管理private static final String[]requestPermissions = {PERMISSION_RECERD_AUDIO,PERMISSION_GET_ACCOUNTS,PERMISSION_READ_PHONE_STATE,PERMISSION_CALL_PHONE,PERMISSION_CAMERA,PERMISSION_ACCESS_FINE_LOCATION,PERMISSION_ACCESS_COARSE_LOCATION,PERMISSION_READ_EXTERNAL_STORAGE,PERMISSION_WRITE_EXTERNAL_STORAGE};private static final String TAG = "PermissionUtils";//表示授权成功的接口public interface PermissionGrant{void onPermissionGranted(int requestCode);}/*封装请求权限的函数*/public static void requestPermission(Activity activity,int requestCode,PermissionGrant permissionGrant){if(activity==null){return;}//排除不存在的请求码if(requestCode<0||requestCode>=requestPermissions.length){return;}String requestPermission = requestPermissions[requestCode];//小于6.0的默认授权状态if(Build.VERSION.SDK_INT<23){return;}//大于6.0申请授权int checkSelfPermission ;try {checkSelfPermission= ActivityCompat.checkSelfPermission(activity,requestPermission);}catch (Exception e){Toast.makeText(activity,"请打开这个权限:"+requestPermission,Toast.LENGTH_SHORT).show();return;}//判断是否被授权了if(checkSelfPermission!= PackageManager.PERMISSION_GRANTED){//没有被授权,需要进行申请if(ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)){//判断申请的权限是否需要弹出对话框shouldShowRationale(activity,requestCode,requestPermission);}else {ActivityCompat.requestPermissions(activity,new String[]{requestPermission},requestCode);}}else {//用户授权了,可以直接调用相关功能Toast.makeText(activity,"opened:"+requestPermission,Toast.LENGTH_SHORT).show();permissionGrant.onPermissionGranted(requestCode);}}private static void shouldShowRationale(Activity activity, int requestCode, String requestPermission) {showMessageOKCancel(activity, "Rationale" + requestPermission, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCompat.requestPermissions(activity,new String[]{requestPermission},requestCode);}});}/*申请权限结果的方法*/public static void requestPermissionsResult(Activity activity,int requestCode,String[] permissions, int[] grantResults,PermissionGrant permissionGrant){if(activity==null){return;}if(requestCode<0||requestCode>=requestPermissions.length){Toast.makeText(activity,"illegar requestCode:"+requestCode, Toast.LENGTH_SHORT).show();return;}if(grantResults.length==1&&grantResults[0]==PackageManager.PERMISSION_GRANTED){//授权成功了(也就是点击允许了)permissionGrant.onPermissionGranted(requestCode);}else {//获取请求码对应的请求信息String permissionError =requestPermissions[requestCode];openSettingActivity(activity,"Result"+permissionError);}}//打开设置页面private static void openSettingActivity(Activity activity, String msg) {showMessageOKCancel(activity, msg, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Intent intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", activity.getPackageName(), null);intent.setData(uri);activity.startActivity(intent);}});}//弹出是否打开的对话框private static void showMessageOKCancel(Activity activity, String msg, DialogInterface.OnClickListener oklistener){new AlertDialog.Builder(activity).setMessage(msg).setPositiveButton("OK",oklistener).setNegativeButton("Cancel",null).create().show();}
}
使用工具类
package com.example.androidnetwork;import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import com.example.androidnetwork.utils.PermissionUtils;import org.jetbrains.annotations.NotNull;import butterknife.BindView;
import butterknife.ButterKnife;import static android.os.Build.VERSION_CODES.M;public class TestActivity extends AppCompatActivity {private static final String TAG = "TestActivity";private Button mButton;//请求码private int REQUESTCODE=1;PermissionUtils.PermissionGrant permissionGrant= new PermissionUtils.PermissionGrant() {@Overridepublic void onPermissionGranted(int requestCode) {//onPermissionGranted方法里面执行你需要申请动态权限的内容call();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);ButterKnife.bind(this);mButton = findViewById(R.id.buttonTest);// getExternalFilesDir(Environment.DIRECTORY_PICTURES);PermissionUtils.requestPermission(this, PermissionUtils.CODE_CALL_PHONE, permissionGrant);}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);Log.d(TAG, "onRequestPermissionsResult: "+permissions.length);PermissionUtils.requestPermissionsResult(this,requestCode,permissions,grantResults,permissionGrant);}public void call(){//下面这个可以使用this的原因是编译时,他没有new一个实现类或者内部类,不然的话就要类名.this//Toast.makeText(this,"你好啊",Toast.LENGTH_SHORT).show();Intent intent = new Intent(Intent.ACTION_CALL);Uri uri = Uri.parse("tel:" + 1008611);intent.setData(uri);startActivity(intent);Log.d(TAG, "text: "+"跳转了");}public void text(View view){// checkPermission();call();}
}
shouldShowRequestPermissionRationale,回到最初的解释“应不应该解释下请求这个权限的目的”。
1.都没有请求过这个权限,用户不一定会拒绝你,所以你不用解释,故返回false;
2.请求了但是被拒绝了,此时返回true,意思是你该向用户好好解释下了;
(也就是你第一次进行申请的时候弹出的对话框你选择了拒绝,那么就会返回true)
3.请求权限被禁止了,也不给你弹窗提醒了,所以你也不用解释了,故返回fasle;
4.请求被允许了,都给你权限了,还解释个啥,故返回false。
Google的初衷大概就是第一次requestPermissions的时候被拒绝时给你一次解释的机会,所以是让你在请求权限的回调中使用的。
3.一次申请多个权限的方法
// 申请多个权限的请求码public final static int CODE_MULTI_PERMISSION = 100;/* 一次申请多个权限*/public static void requestMultiPermissions(final Activity activity, PermissionGrant grant){//获取没有被授权的权限ArrayList<String> permissionList = getNoGrantedPermission(activity, false);final ArrayList<String> shouldRationalePermissionList = getNoGrantedPermission(activity, true);if(permissionList==null||shouldRationalePermissionList==null){return;}if (permissionList.size()>0) {ActivityCompat.requestPermissions(activity,permissionList.toArray(new String[permissionList.size()]),CODE_MULTI_PERMISSION);}else if (shouldRationalePermissionList.size()>0){showMessageOKCancel(activity, "should open those permissions", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCompat.requestPermissions(activity,shouldRationalePermissionList.toArray(new String[shouldRationalePermissionList.size()]),CODE_MULTI_PERMISSION);}});}else {grant.onPermissionGranted(CODE_MULTI_PERMISSION);}}/ 获取没有被授权的权限列表* */private static ArrayList<String> getNoGrantedPermission(Activity activity,boolean isShouldRationale) {ArrayList<String>permissions = new ArrayList<>();for (int i=0;i<requestPermissions.length;i++){String requestPermission = requestPermissions[i];int checkSelfPermission = -1;try {checkSelfPermission = ActivityCompat.checkSelfPermission(activity,requestPermission);}catch (Exception e){Toast.makeText(activity,"please open those permission",Toast.LENGTH_SHORT).show();return null;}if (checkSelfPermission!=PackageManager.PERMISSION_GRANTED){
// 没有被授权需要去申请if (ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)) {if (isShouldRationale) {permissions.add(requestPermission);}}else {if (!isShouldRationale){permissions.add(requestPermission);}}}}return permissions;}/ 获取申请多个权限的结果* */public static void requestMultiResult(Activity activity,@NonNull String[] permissions, @NonNull int[] grantResults,PermissionGrant permissionGrant){if (activity == null) {return;}Map<String,Integer>perms = new HashMap<>();ArrayList<String> notGranted = new ArrayList<>();for (int i = 0; i < permissions.length; i++) {perms.put(permissions[i],grantResults[i]);if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {notGranted.add(permissions[i]);}}if (notGranted.size() == 0) {Toast.makeText(activity,"all permission succewss",Toast.LENGTH_SHORT).show();permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);}else {openSettingActivity(activity,"those permission need granted!");}}
4.最终整个工具类
package com.animee.loadweb;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/* 申请多个权限的工具类*/
public class PermissonUtils {public final static int CODE_RECERD_AUDIO = 0;public final static int CODE_GET_ACCOUNTS = 1;public final static int CODE_READ_PHONE_STATE = 2;public final static int CODE_CALL_PHONE = 3;public final static int CODE_CAMERA = 4;public final static int CODE_ACCESS_FINE_LOCATION = 5;public final static int CODE_ACCESS_COARSE_LOCATION = 6;public final static int CODE_READ_EXTERNAL_STORAGE = 7;public final static int CODE_WRITE_EXTERNAL_STORAGE = 8;
// 申请多个权限的请求码public final static int CODE_MULTI_PERMISSION = 100;public static final String PERMISSION_RECERD_AUDIO = Manifest.permission.RECORD_AUDIO;public static final String PERMISSION_GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;public static final String PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;public static final String PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;public static final String PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;private static final String[]requestPermissions = {PERMISSION_RECERD_AUDIO,PERMISSION_GET_ACCOUNTS,PERMISSION_READ_PHONE_STATE,PERMISSION_CALL_PHONE,PERMISSION_CAMERA,PERMISSION_ACCESS_FINE_LOCATION,PERMISSION_ACCESS_COARSE_LOCATION,PERMISSION_READ_EXTERNAL_STORAGE,PERMISSION_WRITE_EXTERNAL_STORAGE};
// 表示授权成功的接口public interface PermissionGrant{void onPermissionGranted(int requestCode);}/ 封装请求权限的函数* */public static void requestPermission(Activity activity,int requestCode,PermissionGrant permissionGrant){if (activity == null) {return;}
// 排除不存在的请求码if(requestCode< 0||requestCode>=requestPermissions.length){return;}String requestPermission = requestPermissions[requestCode];
// 小于6.0默认授权状态if(Build.VERSION.SDK_INT<23){return;}int checkSelfPermission;try {checkSelfPermission = ActivityCompat.checkSelfPermission(activity,requestPermission);}catch (Exception e){Toast.makeText(activity,"请打开这个权限:"+requestPermission,Toast.LENGTH_SHORT).show();return;}//判断是否被授权了if (checkSelfPermission!= PackageManager.PERMISSION_GRANTED) {// 没有被授权,需要进行申请if(ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)){shouldShowRationale(activity,requestCode,requestPermission);}else {ActivityCompat.requestPermissions(activity,new String[]{requestPermission},requestCode);}}else {//用户授权了,可以直接调用相关功能Toast.makeText(activity,"opened:"+requestPermission,Toast.LENGTH_SHORT).show();permissionGrant.onPermissionGranted(requestCode);}}private static void shouldShowRationale(final Activity activity, final int requestCode, final String requestPermission) {showMessageOKCancel(activity, "Rationale:" + requestPermission, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCompat.requestPermissions(activity,new String[]{requestPermission},requestCode);}});}/ 申请权限结果的方法* */public static void requestPermissionsResult(Activity activity, int requestCode,@NonNull String[] permissions, @NonNull int[] grantResults,PermissionGrant permissionGrant){if (activity == null) {return;}if(requestCode<0||requestCode>=requestPermissions.length){Toast.makeText(activity,"illegal requestCode:"+requestCode,Toast.LENGTH_SHORT).show();return;}if(grantResults.length==1&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
// 授权成功了permissionGrant.onPermissionGranted(requestCode);}else {String permissionError = permissions[requestCode];openSettingActivity(activity,"Result:"+permissionError);}}/ 获取申请多个权限的结果* */public static void requestMultiResult(Activity activity,@NonNull String[] permissions, @NonNull int[] grantResults,PermissionGrant permissionGrant){if (activity == null) {return;}Map<String,Integer>perms = new HashMap<>();ArrayList<String> notGranted = new ArrayList<>();for (int i = 0; i < permissions.length; i++) {perms.put(permissions[i],grantResults[i]);if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {notGranted.add(permissions[i]);}}if (notGranted.size() == 0) {Toast.makeText(activity,"all permission succewss",Toast.LENGTH_SHORT).show();permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);}else {openSettingActivity(activity,"those permission need granted!");}}/*打开设置界面*/private static void openSettingActivity(final Activity activity, String msg) {showMessageOKCancel(activity, msg, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Intent intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", activity.getPackageName(), null);intent.setData(uri);activity.startActivity(intent);}});}/* 弹出是否打开的对话框*/private static void showMessageOKCancel(Activity activity, String msg, DialogInterface.OnClickListener oklistener){new AlertDialog.Builder(activity).setMessage(msg).setPositiveButton("OK",oklistener).setNegativeButton("Cancel",null).create().show();}/* 一次申请多个权限*/public static void requestMultiPermissions(final Activity activity, PermissionGrant grant){//获取没有被授权的权限ArrayList<String> permissionList = getNoGrantedPermission(activity, false);final ArrayList<String> shouldRationalePermissionList = getNoGrantedPermission(activity, true);if(permissionList==null||shouldRationalePermissionList==null){return;}if (permissionList.size()>0) {ActivityCompat.requestPermissions(activity,permissionList.toArray(new String[permissionList.size()]),CODE_MULTI_PERMISSION);}else if (shouldRationalePermissionList.size()>0){showMessageOKCancel(activity, "should open those permissions", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCompat.requestPermissions(activity,shouldRationalePermissionList.toArray(new String[shouldRationalePermissionList.size()]),CODE_MULTI_PERMISSION);}});}else {grant.onPermissionGranted(CODE_MULTI_PERMISSION);}}/ 获取没有被授权的权限列表* */private static ArrayList<String> getNoGrantedPermission(Activity activity,boolean isShouldRationale) {ArrayList<String>permissions = new ArrayList<>();for (int i=0;i<requestPermissions.length;i++){String requestPermission = requestPermissions[i];int checkSelfPermission = -1;try {checkSelfPermission = ActivityCompat.checkSelfPermission(activity,requestPermission);}catch (Exception e){Toast.makeText(activity,"please open those permission",Toast.LENGTH_SHORT).show();return null;}if (checkSelfPermission!=PackageManager.PERMISSION_GRANTED){
// 没有被授权需要去申请if (ActivityCompat.shouldShowRequestPermissionRationale(activity,requestPermission)) {if (isShouldRationale) {permissions.add(requestPermission);}}else {if (!isShouldRationale){permissions.add(requestPermission);}}}}return permissions;}
}