Android 运行时权限处理解析

一.Android6.0权限改变

1. Android6.0版本之前的权限是写在配置文件AndroidManifest.xml中的,Android app在安装的时候Android系统检测配置文件的权限给用户提示app需要的权限,用户可以点击接受和拒绝。但是这种方式用户在Androidapp的时候并不知道这个权限用在哪里有啥危害。于是Android6.0开始改变权限申请的方式,出现了权限组和动态申请权限。

2.从设计来看我们可以想象设计一套这样的功能。一般需要定义一套权限规则,二设计一套权限检测的方法把用户定义的权限解析以及用户申请权限的方法,三设计一个用户操作权限的授权的功能,第四设计一套权限存储更新的功能。这样想就和服务器一样的功能用户需要什么功能通过协议去请求检测这样的功能是不是满足需要功能的权限。

3.从系统底层来看。我们看源码的地址是:http://androidxref.com/9.0.0_r3/xref/frameworks/

从系统源码来看我们可以从上面的功能分析设计上来找对应的模块。权限定义模块,权限检测模块,用户授权模块,权限存储。

1.权限定义模块

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml

687    <!-- Allows an application to send SMS messages.
688         <p>Protection level: dangerous
689    -->
690    <permission android:name="android.permission.SEND_SMS"
691        android:permissionGroup="android.permission-group.SMS"
692        android:label="@string/permlab_sendSms"
693        android:description="@string/permdesc_sendSms"
694        android:permissionFlags="costsMoney"
695        android:protectionLevel="dangerous" />
696
697    <!-- Allows an application to receive SMS messages.
698         <p>Protection level: dangerous
699    -->
700    <permission android:name="android.permission.RECEIVE_SMS"
701        android:permissionGroup="android.permission-group.SMS"
702        android:label="@string/permlab_receiveSms"
703        android:description="@string/permdesc_receiveSms"
704        android:protectionLevel="dangerous"/>
705
706    <!-- Allows an application to read SMS messages.
707         <p>Protection level: dangerous
708    -->
709    <permission android:name="android.permission.READ_SMS"
710        android:permissionGroup="android.permission-group.SMS"
711        android:label="@string/permlab_readSms"
712        android:description="@string/permdesc_readSms"
713        android:protectionLevel="dangerous" />

protectionLevel共有5个选项值分别为signature,system,dangerous,normal,development,简单介绍下这5个值 
System permissions: 表示如果想获取该权限必须为系统应用 

Normal permissions:只需要在AndroidManifest.xml 中声明,如INTERNET,WAKE_LOCK等

Signature permissions:申请该权限的应用和定义该权限的应用有相同签名时,这个权限才会被授予,一些Signature permissions不能被三方应用使用

Dangerous permissions:需要申请运行时权限

Special permissions:如SYSTEM_ALERT_WINDOW需要应用发送Settings.ACTION_MANAGE_OVERLAY_PERMISSION intent去提示用户是否开启该权限

任何一个权限都有自己的所属的权限组。同一组的任何一个权限被授权了,其他权限也自动被授权。

如:android.permission.READ_EXTERNAL_STORAGE和android.permission.WRITE_EXTERNAL_STORAGE都在android.permission-group.STORAGE这个权限组里面,申请权限时同意了组中的一个另一个同时也同意了。

2.权限检测功能模块pms ,用户动态权限检测

 

3.用户权限授权模块GrantPermissionsActivity

https://www.androidos.net.cn/android/6.0.1_r16/xref/packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java

1.系统中定义。

2.调用流程

3.全透明GrantPermissionsActivity源码解析

 

4.权限更新模块

 

5.权限adb命令调试查看:

adb shell dumpsys package + 包名

6.特殊的需求处理。

比如hook住权限调用过程,更改弹窗显示或者拦截显示。

 

二.封装方案

1.通过fragment中带有权限请求和回调的方法进行请求工具封装

1.传入参数

1.上下文  activity 或者fragment

2.请求的权限的列表

3.结果返回后的接口

2.工具封装

1.封装一个请求权限Fragment在fragment中请求

public class PermissionFragment extends Fragment {
    //requestCode
    private static final int PERMISSIONS_REQUEST_CODE = 1;
    private PermissionListener listener;
    public void setListener(PermissionListener listener) {
        this.listener = listener;
    }
    
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void requestPermissions(@NonNull String[] permissions) {
        List<String> requestPermissionList = new ArrayList<>();
        //找出所有未授权的权限
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(getContext(), permission) != PackageManager.PERMISSION_GRANTED) {
                requestPermissionList.add(permission);
            }
        }
        if (requestPermissionList.isEmpty()) {
            //已经全部授权
            permissionAllGranted();
        } else {
            //申请授权
            requestPermissions(requestPermissionList.toArray(new String[requestPermissionList.size()]), PERMISSIONS_REQUEST_CODE);
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode != PERMISSIONS_REQUEST_CODE) {
            return;
        }
        if (grantResults.length > 0) {
            List<String> deniedPermissionList = new ArrayList<>();
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    deniedPermissionList.add(permissions[i]);
                }
            }
            if (deniedPermissionList.isEmpty()) {
                //已经全部授权
                permissionAllGranted();
            } else {
                //勾选了对话框中”Don’t ask again”的选项, 返回false
                for (String deniedPermission : deniedPermissionList) {
                    boolean flag = shouldShowRequestPermissionRationale(deniedPermission);
                    if (!flag) {
                        //拒绝授权
                        permissionShouldShowRationale(deniedPermissionList);
                        return;
                    }
                }
                //拒绝授权
                permissionHasDenied(deniedPermissionList);
            }
        }
    }

    /**
     * 权限全部已经授权
     */
    private void permissionAllGranted() {
        if (listener != null) {
            listener.onGranted();
        }
    }

    /**
     * 权限被拒绝
     *
     * @param deniedList 被拒绝的权限List
     */
    private void permissionHasDenied(List<String> deniedList) {
        if (listener != null) {
            listener.onDenied(deniedList);
        }
    }

    /**
     * 权限被拒绝并且勾选了不在询问
     *
     * @param deniedList 勾选了不在询问的权限List
     */
    private void permissionShouldShowRationale(List<String> deniedList) {
        if (listener != null) {
            listener.onShouldShowRationale(deniedList);
        }
    }
}

2.通过传进来的activity或者fragment上下文生成工具fragment

public class PermissionUtil {
    private static final String TAG = PermissionUtil.class.getSimpleName();
    private PermissionFragment permissionFragment;

    public PermissionUtil(@NonNull FragmentActivity activity) {
        permissionFragment = getRxPermissionsActivity(activity);
    }

    public PermissionUtil(@NonNull Fragment fragment) {
        permissionFragment = getRxPermissionsFragment(fragment);
    }

    private PermissionFragment getRxPermissionsActivity(FragmentActivity activity) {
        PermissionFragment fragment = (PermissionFragment) activity.getSupportFragmentManager().findFragmentByTag(TAG);
        boolean isNewInstance = fragment == null;
        if (isNewInstance) {
            fragment = new PermissionFragment();
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            fragmentManager.beginTransaction().add(fragment, TAG).commit();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    private PermissionFragment getRxPermissionsFragment(Fragment activity) {
        PermissionFragment fragment = (PermissionFragment) activity.getChildFragmentManager().findFragmentByTag(TAG);
        boolean isNewInstance = fragment == null;
        if (isNewInstance) {
            fragment = new PermissionFragment();
            FragmentManager fragmentManager = activity.getChildFragmentManager();
            fragmentManager.beginTransaction().add(fragment, TAG).commit();
            fragmentManager.executePendingTransactions();
        }
        return fragment;
    }

    /**
     * 外部使用 申请权限
     *
     * @param permissions 申请授权的权限
     * @param listener    授权回调的监听
     */
    public void requestPermissions(String[] permissions, PermissionListener listener) {
        permissionFragment.setListener(listener);
        permissionFragment.requestPermissions(permissions);
    }

}

3.结果返回

请求结果通过接口设计

public interface PermissionListener {
    void onGranted();
    void onDenied(List<String> deniedPermission);
    void onShouldShowRationale(List<String> deniedPermission);
}

4.demo下载地址

github:https://github.com/MatrixSpring/AndroidPermission

 

5.更新支持AndroidX地址:

github:https://github.com/MatrixSpring/AppPermission

 

2.通过activity中带有的权限请求和回调的方法

1.传入参数

2.工具封装

3.结果返回

4.demo下载地址

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MatrixData

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值