Android permission management and dynamic application permission

Android permission management


1. Basic introduction

  The Android security architecture stipulates that by default, no application has permission to perform any operations that adversely affect other applications, the operating system, or the user. This includes reading and writing the user's private data such as contacts or email, reading and writing files from other apps, performing network access, keeping the device awake, and more.
  App permissions are based on system security features and help Android support the following goals related to user privacy:

  • Control: Users have control over the data they share with apps.
  • Transparency: Users can understand what data is being used by the app and why the app is accessing it.
  • Data minimization: Apps can only access and use the data needed for the specific task or operation invoked by the user.

permission type

  Android divides permissions into different types, including install-time permissions, runtime permissions, and special permissions. Each permission type indicates the restricted data scope that the application can access and the restricted operation scope that the application can perform after the system grants the permission to the application.

1. Permissions during installation

  Install-time permissions grant apps limited access to restricted data and allow apps to perform restricted actions with minimal impact on the system or other apps. If an install-time permission is declared in an app, the system automatically grants the permission when the user allows the app to install.
  Install-time permissions are divided into several subtypes, including normal permissions and signature permissions.

  • Ordinary permissions
    These permissions allow access to data and actions outside the application sandbox. However, these data and operations pose very little risk to user privacy and the operation of other applications. Normal permissions are assigned a protection level of "normal".

  • Signature Permissions
    When an app declares a signature permission defined by another app, if two apps are signed with the same signature file, the system will grant the permission to the former during installation. Otherwise, the system cannot grant the permission to the former. Signature permissions are assigned a protection level of "signature".

2. Runtime permissions

  Runtime permissions, also known as dangerous permissions, grant an app additional access to restricted data and allow the app to perform restricted actions that have a more severe impact on the system and other apps. So permissions need to be requested at runtime before you can access restricted data or perform restricted operations. When an application requests a runtime permission, the system will pop up a prompt to display the runtime permission application. Many runtime permissions access user private data, which is a special kind of restricted data that contains potentially sensitive information. For example, location information and contact information are private user data. Runtime permissions are assigned a "dangerous" protection level.
  The runtime permission mechanism is a new feature of Android 6.0 (M), so devices of different Android versions and the targetSdkVersion set by the application will affect the performance of the application when applying for dangerous permissions.

  • When used on devices earlier than Android 6.0, the app still uses the old permission system, and dangerous permissions will still be applied for when the app is installed, regardless of whether the targetSdkVersion is greater than 23 or not.
  • When used on Android 6.0 and later devices, it will be judged according to the targetSdkVersion set in the application: 1) If the targetSdkVersion is lower than 23, continue to use the old rules, and apply for dangerous permissions during installation; 2) If targetSdkVersion is greater than or equal to 23, the application needs to dynamically apply for permissions at runtime.

Note: Starting from Android 6.0 (Marshmallow, API 23), users can revoke a certain permission of the application at any time, even if the application's targetSdkVersion is less than 23. Therefore, it is important to ensure that the application can still perform well after failing to request permission.


  If the device is running Android 6.0 or higher, and the app's targetSdkVersion is 23 or higher, the following behavior occurs when the user requests a dangerous permission:

  • If an application requests a dangerous permission that is already listed in its manifest file, and the application does not currently have any permissions for this permission group, the system will display a dialog box to the user asking whether the user authorizes, and the dialog box will describe what the application wants. The permission group to access rather than specific permissions within the group. For example, if an application requests the READ_CONTACTS permission, the system will pop up a dialog box to inform the user that the application needs to access the contacts of the device. If the user allows authorization, the system will grant the required permission to the application.
  • If an app requests a dangerous permission that is already listed in its manifest file, and the app already has other dangerous permissions in that permission group, the system grants that permission immediately without notifying the user. For example, if an app has previously requested and been granted the READ_CONTACTS permission, it will immediately grant that permission when it subsequently requests WRITE_CONTACTS.

Permission group concept:
  According to the functions and characteristics of the device, permissions are divided into permission groups. The system processes permission requests in the form of permission groups, and one permission group may correspond to several permissions applied for in the Manifest. For example, the STORAGE permission group includes READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions. The method of permission group makes it easier for users to understand permissions and handle APP permission requests more conveniently, preventing too many complicated granting of individual permissions.
  Any permission can belong to a permission group, including normal permissions and application-defined permissions. But permission groups affect user experience only when permissions are dangerous. Permission groups for which normal permissions can be ignored.

Dangerous permissions and their corresponding groups are as follows:

insert image description here

3. Special permissions

  Special permissions correspond to specific app actions. Only platforms and original equipment manufacturers (OEMs) can define special permissions. Additionally, special permissions are often defined by platforms and OEMs if they want to prevent someone from performing particularly powerful operations, such as drawing from another application. Special permissions are assigned the "appop" protection level. After Android 6.0, only system apps can use these special permissions.




2. Dynamic Permission Application

1. Main method of use

(1) ContextCompat.checkSelfPermission
  checks whether the application has a dangerous permission. If the application has this permission, the method will return PackageManager.PERMISSION_GRANTED; if the application does not have this permission, the method will return PackageManager.PERMISSION_DENIED.

(2) The ActivityCompat.requestPermissions
  application can dynamically apply for permissions through this method. After calling, a dialog box will pop up to prompt the user to authorize the applied permission group.

(3) ActivityCompat.shouldShowRequestPermissionRationale
  checks whether this permission was rejected last time. This method will return true if the app has previously requested this permission and the user declined the request, but can continue. However, the following situations all return false: 1) The user has never applied for the permission; 2) The user has rejected the permission request in the past and selected the Don't ask again option in the permission request system dialog box; 3) The user allows 4) The device specification prohibits the app from having this permission.
  Therefore, it is useless to use this method alone to make a judgment, and it should be used in the request permission callback.

Note: Different mobile phone systems may have differences in permission processing. Some mobile phone systems choose to reject the authorization application when popping up, and the pop-up will not be popped up by default. Calling this method at this time returns false.

(4) onRequestPermissionsResult
  When the application requests permission, the system will display a dialog box to the user. When the user responds, the system will call the application's onRequestPermissionsResult() method, pass the user response to it, and process the corresponding scene.

2. Call process

(1) Declare the permissions to be applied for in AndroidManifest.xml.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>

(2) Check the permission before applying for the permission. If the application does not have the permission, apply for the permission; if you apply for multiple permissions at a time, you should check the permissions one by one, and finally apply for the unauthorized permissions.

private String PM_SINGLE=Manifest.permission.WRITE_EXTERNAL_STORAGE;
//申请单个权限
public void applyForSinglePermission(){
    Log.i(TAG,"applyForSinglePermission");
    try{
        //如果操作系统SDK级别在23之上(android6.0),就进行动态权限申请
        if(Build.VERSION.SDK_INT>=23){
			//判断是否拥有权限
            int nRet=ContextCompat.checkSelfPermission(this,PM_SINGLE);
            Log.i(TAG,"checkSelfPermission nRet="+nRet);
            if(nRet!= PackageManager.PERMISSION_GRANTED){
                Log.i(TAG,"进行权限申请...");
                ActivityCompat.requestPermissions(this,new String[]{PM_SINGLE},10000);
            }
            else{
                showToast("权限已授权");
            }
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}

private String[] PM_MULTIPLE={
	Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.CAMERA,Manifest.permission.WRITE_CONTACTS
};
//申请多个权限
public void applyForMultiplePermissions(){
    Log.i(TAG,"applyForMultiplePermissions");
    try{
        //如果操作系统SDK级别在23之上(android6.0),就进行动态权限申请
        if(Build.VERSION.SDK_INT>=23){
            ArrayList<String> pmList=new ArrayList<>();
            //获取当前未授权的权限列表
            for(String permission:PM_MULTIPLE){
                int nRet=ContextCompat.checkSelfPermission(this,permission);
                Log.i(TAG,"checkSelfPermission nRet="+nRet);
                if(nRet!= PackageManager.PERMISSION_GRANTED){
                    pmList.add(permission);
                }
            }

            if(pmList.size()>0){
                Log.i(TAG,"进行权限申请...");
                String[] sList=pmList.toArray(new String[0]);
                ActivityCompat.requestPermissions(this,sList,10000);
            }
            else{
                showToast("全部权限都已授权");
            }
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}

(3) Rewrite the onRequestPermissionsResult callback method to monitor and process the user's permission authorization operation.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    try{
        ArrayList<String> requestList=new ArrayList<>();//允许询问列表
        ArrayList<String> banList=new ArrayList<>();//禁止列表
        for(int i=0;i<permissions.length;i++){
            if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
                Log.i(TAG,"【"+permissions[i]+"】权限授权成功");
            }
            else{
				//判断是否允许重新申请该权限
                boolean nRet=ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[i]);
                Log.i(TAG,"shouldShowRequestPermissionRationale nRet="+nRet);
                if(nRet){//允许重新申请
                    requestList.add(permissions[i]);
                }
                else{//禁止申请
                    banList.add(permissions[i]);
                }
            }
        }

        //优先对禁止列表进行判断
        if(banList.size()>0){//告知该权限作用,要求手动授予权限
            showFinishedDialog();
        }
        else if(requestList.size()>0){//告知权限的作用,并重新申请
            showTipDialog(requestList);
        }
        else{
            showToast("权限授权成功");
        }
    }catch (Exception e){
        e.printStackTrace();
        showToast("权限申请回调中发生异常");
    }
}

public void showFinishedDialog(){
    AlertDialog dialog = new AlertDialog.Builder(this)
            .setTitle("警告")
            .setMessage("请前往设置中打开相关权限,否则功能无法正常运行!")
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理
                    finish();
                }
            })
            .create();
    dialog.show();
}

public void showTipDialog(ArrayList<String> pmList){
    AlertDialog dialog = new AlertDialog.Builder(this)
            .setTitle("提示")
            .setMessage("【"+pmList.toString()+"】权限为应用必要权限,请授权")
            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String[] sList=pmList.toArray(new String[0]);
                    //重新申请该权限
                    ActivityCompat.requestPermissions(MainActivity.this,sList,10000);
                }
            })
            .create();
    dialog.show();
}



3. PermissionUtil tool class

  This class is a tool class for Android permission application encapsulated by itself. It can apply for multiple permissions through the permission group name or permission name, and encapsulates the processing logic of user authorization operations. It can pass in the callback interface for User authorization conditions to define different response processing.

PermissionUtil implementation:

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * author:chenjs
 */
public class PermissionUtil {
	private static final String TAG=PermissionUtil.class.getSimpleName();
	private static final boolean LOG_FLAG=true;//日志标识

	//日历
	private static final String[] Group_Calendar={
	        Manifest.permission.READ_CALENDAR,Manifest.permission.WRITE_CALENDAR
	};
	//照相机
	private static final String[] Group_Camera={
	        Manifest.permission.CAMERA
	};
	//通讯录
	private static final String[] Group_Contacts={
	        Manifest.permission.WRITE_CONTACTS,Manifest.permission.GET_ACCOUNTS,
	        Manifest.permission.READ_CONTACTS
	};
	//定位
	private static final String[] Group_Location={
	        Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION
	};
	//麦克风
	private static final String[] Group_Microphone={
	        Manifest.permission.RECORD_AUDIO
	};
	//电话
	private static final String[] Group_Phone={
	        Manifest.permission.READ_PHONE_STATE,Manifest.permission.CALL_PHONE,
	        Manifest.permission.READ_CALL_LOG,Manifest.permission.WRITE_CALL_LOG,
	        Manifest.permission.ADD_VOICEMAIL,Manifest.permission.USE_SIP,
	        Manifest.permission.PROCESS_OUTGOING_CALLS
	};
	//传感器
	private static final String[] Group_Sensors={
	        Manifest.permission.BODY_SENSORS
	};
	//短信
	private static final String[] Group_Sms={
	        Manifest.permission.READ_SMS,Manifest.permission.SEND_SMS,
	        Manifest.permission.RECEIVE_SMS,Manifest.permission.RECEIVE_MMS,
	        Manifest.permission.RECEIVE_WAP_PUSH
	};
	//存储
	private static final String[] Group_Storage={
	        Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE
	};
	private static Map<String,String[]> m_PermissionGroupList=null;
	static{
	    initMap();
	}

	/**
	 * 通过权限组名来申请一组权限
	 * @param context
	 * @param permissionGroupName
	 * @param requestCode
	 * @param listener
	 */
	public static void requestByGroupName(Activity context, String permissionGroupName,int 	requestCode,OnPermissionsListener listener){
	    requestByGroupName(context, new String[]{permissionGroupName}, requestCode, listener);
	}

	/**
	 * 通过权限组名来申请多组权限
	 * @param context Activity上下文
	 * @param pgNameArray 多个要申请的权限组名称
	 * @param requestCode 请求码
	 * @param listener 回调接口
	 */
	public static void requestByGroupName(Activity context, String[] pgNameArray,int 	requestCode,OnPermissionsListener listener){
	    showLog("requestByPermissionGroup");
	    try{
	        //如果操作系统SDK级别在23之上(android6.0),就进行动态权限申请
	        if(Build.VERSION.SDK_INT>=23 && pgNameArray!=null){
	            String[] permissionsList=getAppPermissionsList(context);//应用权限列表
	            ArrayList<String> targetList=new ArrayList<>();
	            if(permissionsList==null || permissionsList.length==0){
	                showLog("获得权限列表为空");
	                return;
	            }

	            for(String groupName:pgNameArray){
	                ArrayList<String> tmpPermissionList=isPermissionDeclared(permissionsList,groupName);
	                if(tmpPermissionList==null){//未找到
	                    showLog("未找到["+groupName+"]中的权限");
	                    continue;
	                }

	                for(int i=0;i<tmpPermissionList.size();i++){
	                    //判断是否拥有权限
	                    int nRet=ContextCompat.checkSelfPermission(context,tmpPermissionList.get(i));
	                    if(nRet!= PackageManager.PERMISSION_GRANTED){
	                        targetList.add(tmpPermissionList.get(i));
	                    }
	                }
	            }

	            if(targetList.size()>0){
	                showLog("进行以下权限申请:"+targetList.toString());
	                String[] sList=targetList.toArray(new String[0]);
	                ActivityCompat.requestPermissions(context,sList,requestCode);
	            }
	            else{
	                showLog("全部权限都已授权");
	                if(listener!=null){
	                    listener.onPermissionsOwned();
	                }
	            }
	        }
	    }catch(Exception e){
	        e.printStackTrace();
	    }
	}

	/**
	 * 通过权限名来申请一组权限
	 * @param context
	 * @param permission
	 * @param requestCode
	 * @param listener
	 */
	public static void requestByPermissionName(Activity context, String permission,int 	requestCode,OnPermissionsListener listener){
	    requestByPermissionName(context, new String[]{permission}, requestCode, listener);
	}

	/**
	 * 通过权限名来申请多组权限
	 * @param context Activity上下文
	 * @param permissionArray 多个要申请的权限名称
	 * @param requestCode 请求码
	 * @param listener 回调接口
	 */
	public static void requestByPermissionName(Activity context, String[] permissionArray,int 	requestCode,OnPermissionsListener listener){
	    showLog("requestPermissions");
	    try{
	        //如果操作系统SDK级别在23之上(android6.0),就进行动态权限申请
	        if(Build.VERSION.SDK_INT>=23 && permissionArray!=null){
	            ArrayList<String> targetList=new ArrayList<>();
	            for(String strPermission:permissionArray){
	                //判断是否拥有权限
	                int nRet=ContextCompat.checkSelfPermission(context,strPermission);
	                if(nRet!= PackageManager.PERMISSION_GRANTED){
	                    targetList.add(strPermission);
	                }
	            }

	            if(targetList.size()>0){
	                showLog("进行以下权限申请:"+targetList.toString());
	                String[] sList=targetList.toArray(new String[0]);
	                ActivityCompat.requestPermissions(context,sList,requestCode);
	            }
	            else{
	                showLog("全部权限都已授权");
	                if(listener!=null){
	                    listener.onPermissionsOwned();
	                }
	            }
	        }
	    }catch(Exception e){
	        e.printStackTrace();
	    }
	}

	/**
	 * 针对申请权限时的用户操作进行处理
	 * @param context
	 * @param permissions 申请的权限
	 * @param grantResults 各权限的授权状态
	 * @param listener 回调接口
	 * @param controlFlag 控制标识,用于判断当响应禁止列表后,是否继续处理可再申请列表(避免出现同时处理禁止列表和可再申请列表,互相干扰,比如弹出两个提示框)
	 */
	public static void onRequestPermissionsResult(Activity context,String[] permissions, int[] 	grantResults,OnPermissionsListener listener,boolean controlFlag) {
	    try{
	        ArrayList<String> requestList=new ArrayList<>();//可再申请列表
	        ArrayList<String> banList=new ArrayList<>();//禁止列表
	        for(int i=0;i<permissions.length;i++){
	            if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
	                showLog("["+permissions[i]+"]权限授权成功");
	            }
	            else{
	                boolean nRet=ActivityCompat.shouldShowRequestPermissionRationale(context,permissions[i]);
	                //Log.i(TAG,"shouldShowRequestPermissionRationale nRet="+nRet);
	                if(nRet){//允许重新申请
	                    requestList.add(permissions[i]);
	                }
	                else{//禁止申请
	                    banList.add(permissions[i]);
	                }
	            }
	        }

	        do{
	            //优先对禁止列表进行判断
	            if(banList.size()>0){
	                if(listener!=null){
	                    listener.onPermissionsForbidden(permissions,grantResults,banList);
	                }
	                if(!controlFlag){//对禁止列表处理后,且控制标识为false,则跳过对可再申请列表的处理
	                    break;
	                }
	            }
	            if(requestList.size()>0){
	                if(listener!=null){
	                    listener.onPermissionsDenied(permissions,grantResults,requestList);
	                }
	            }
	            if(banList.size()==0 && requestList.size()==0){
	                showLog("权限授权成功");
	                if(listener!=null){
	                    listener.onPermissionsSucceed();
	                }
	            }
	        }while (false);
	    }catch (Exception e){
	        e.printStackTrace();
	    }
	}

	/**
	 * 判断权限状态
	 * @param context
	 * @param permission 权限名
	 * @return
	 */
	public static boolean checkPermission(Context context,String permission){
	    try{
	        //如果操作系统SDK级别在23之上(android6.0),就进行动态权限申请
	        if(Build.VERSION.SDK_INT>=23){
	            int nRet= ContextCompat.checkSelfPermission(context,permission);
	            showLog("checkSelfPermission nRet="+nRet);

	            return nRet==PackageManager.PERMISSION_GRANTED? true : false;
	        }
	        return true;
	    }catch(Exception e){
	        e.printStackTrace();
	        return false;
	    }
	}

	/**
	 * 获得当前应用清单中的权限列表
	 * @param context 应用上下文
	 * @return
	 */
	public static String[] getAppPermissionsList(Context context){
	    try{
	        PackageManager packageManager = context.getApplicationContext().getPackageManager();
	        String packageName=context.getApplicationContext().getPackageName();
	        String[] array = packageManager.getPackageInfo(packageName,PackageManager.GET_PERMISSIONS).requestedPermissions;
	        return array;
	    }catch (Exception e){
	        e.printStackTrace();
	    }
	    return null;
	}

	/**
	 * 判断权限列表中是否声明了指定权限组中的权限
	 * @param permissionList 权限列表
	 * @param permissionGroup 权限组名
	 * @return 存在则返回找到的权限组权限,否则返回null
	 */
	public static ArrayList<String> isPermissionDeclared(String[] permissionList, String permissionGroup){
	    try{
	        if(permissionList!=null && permissionGroup!=null){
	            String[] pmGroup=m_PermissionGroupList.get(permissionGroup);
	            if(pmGroup!=null){
	                ArrayList<String> arrayList=new ArrayList<>();
	                //遍历
	                for(int i=0;i<pmGroup.length;i++){
	                    String strPermission=pmGroup[i];
	                    for(int j=0;j< permissionList.length;j++){
	                        if(strPermission.equals(permissionList[j])){//找到指定权限组中的权限
	                            arrayList.add(strPermission);
	                            break;
	                        }
	                    }
	                }
	                if(arrayList.size()==0){
	                    return null;
	                }
	                return arrayList;
	            }
	        }
	    }catch (Exception e){
	        e.printStackTrace();
	    }
	    return null;
	}

	private static void initMap(){
	    if(m_PermissionGroupList==null){
	        m_PermissionGroupList=new HashMap<>();
	        m_PermissionGroupList.put(Manifest.permission_group.CALENDAR,Group_Calendar);
	        m_PermissionGroupList.put(Manifest.permission_group.CAMERA,Group_Camera);
	        m_PermissionGroupList.put(Manifest.permission_group.CONTACTS,Group_Contacts);
	        m_PermissionGroupList.put(Manifest.permission_group.LOCATION,Group_Location);
	        m_PermissionGroupList.put(Manifest.permission_group.MICROPHONE,Group_Microphone);
	        m_PermissionGroupList.put(Manifest.permission_group.PHONE,Group_Phone);
	        m_PermissionGroupList.put(Manifest.permission_group.SENSORS,Group_Sensors);
	        m_PermissionGroupList.put(Manifest.permission_group.SMS,Group_Sms);
	        m_PermissionGroupList.put(Manifest.permission_group.STORAGE,Group_Storage);
	    }
	}

	private static void showLog(String str){
	    if(LOG_FLAG){
	        Log.i(TAG,str);
	    }
	}

	public interface OnPermissionsListener {
	    /**
	     * 权限都已拥有时的处理
	     */
	    void onPermissionsOwned();
	    /**
	     * 权限被禁止时的处理
	     * @param permissions 申请的全部权限
	     * @param grantResults 各权限的授权状态
	     * @param pmList 禁止申请的权限列表
	     */
	    void onPermissionsForbidden(String[] permissions, int[] grantResults,ArrayList<String> pmList);
	    /**
	     * 权限被拒绝时的处理
	     * @param permissions
	     * @param grantResults
	     * @param pmList 可再申请的权限列表
	     */
	    void onPermissionsDenied(String[] permissions, int[] grantResults,ArrayList<String> pmList);
	    /**
	     * 权限申请成功时的处理
	     */
	    void onPermissionsSucceed();
	}
}	

The usage can refer to the following examples:

private final int RequestCode3_1 =10004;
//由使用者根据自身需求进行重写
private PermissionUtil.OnPermissionsListener mListener3_1=new PermissionUtil.OnPermissionsListener() {
    @Override
    public void onPermissionsOwned() {
        showTip("该权限已拥有");
    }

    @Override
    public void onPermissionsForbidden(String[] permissions, int[] grantResults, ArrayList<String> pmList) {
        showTip("以下权限被禁止:"+pmList.toString());
        AlertDialog dialog = new AlertDialog.Builder(mContext)
                .setTitle("警告")
                .setMessage("请前往设置中手动打开"+pmList.toString()+"权限!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                })
                .create();
        dialog.show();
    }

    @Override
    public void onPermissionsDenied(String[] permissions, int[] grantResults, ArrayList<String> pmList) {
        showTip("以下权限被拒绝授权:"+pmList.toString());
        //重新请求权限
        AlertDialog dialog = new AlertDialog.Builder(mContext)
                .setTitle("提示")
                .setMessage("【"+pmList.toString()+"】权限为应用必要权限,请授权")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String[] sList=pmList.toArray(new String[0]);
                        //重新申请权限,通过权限名的方式申请多组权限
                        PermissionUtil.requestByPermissionName(mContext,sList, RequestCode3_1,mListener3_1);
                    }
                })
                .create();
        dialog.show();
    }

    @Override
    public void onPermissionsSucceed() {
        showTip("权限申请成功");
    }
};

public void requestPermission3_1(){
    String[] pgArray=new String[]{
            Manifest.permission_group.SENSORS,Manifest.permission_group.SMS,Manifest.permission_group.STORAGE
    };
    showTip("进行[传感器+短信+存储]权限申请...");
	//通过权限组名来申请指定权限
    PermissionUtil.requestByGroupName(mContext,pgArray, RequestCode3_1,mListener3_1);
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){//可以针对不同的权限申请操作进行不同处理,也可以统一以相同方式处理(不对requestCode进行判断)
        case RequestCode3_1:{
            PermissionUtil.onRequestPermissionsResult(mContext,permissions,grantResults,mListener3_1,false);
            break;
        }
    }
}

Specific tools and demonstration projects are placed on Github, and interested students can learn more about them. If you have any questions, welcome to discuss and make progress together.

GitHub address: https://github.com/JINSHENGCCC/Android_Common/tree/master/AndroidPermission/src




4. Reference

  1. Permissions in Android
  2. Summary of permissions for Android development in seconds
  3. Detailed explanation of Android rights management
  4. Android runtime permission handling
  5. Android 6.0 dynamic permission application
  6. List of Android 6.0 Dangerous Permissions

Guess you like

Origin blog.csdn.net/weixin_56291477/article/details/122613092