权限申请库:AndPermission(二)

Quibbler 2022-7-7 592

权限申请库:AndPermission(二)


        在权限申请库:AndPermission(一)中介绍了阿里严振杰所写的权限申请库:AndPermission,虽然很不靠谱被喷的不少,但仍推荐阅读此库的源码。它的源码比较容易阅读和理解,适合Android初学者学习,帮助理解Android的权限机制。

        随着Google对Android的不断升级完善,越来越重视对用户隐私的保护,现在Android框架的权限机制已经固定且稳定可靠,用原生框架足够满足开发需求,无需再借助三方的开源库。


        废话不多说,直接看源码。从with()入口方法开始,该方法有多个重载,可以接收ContextFragmentActivity等多种类型作为参数,这样的设计借鉴了Glide

    public static Option with(Context context) {
        return new Boot(getContextSource(context));
    }
    
    public static Option with(Fragment fragment) {
        return new Boot(new XFragmentSource(fragment));
    }
    
    public static Option with(android.app.Fragment fragment) {
        return new Boot(new FragmentSource(fragment));
    }
    
    public static Option with(Activity activity) {
        return new Boot(new ActivitySource(activity));
    }

        返回Option接口类型,该接口定义了若干方法,也是AndPermission库的几个核心功能。

    public interface Option {
        /**
         * Handle runtime permissions.
         */
        RuntimeOption runtime();
        
        /**
         * Handle request package install permission.
         */
        InstallRequest install();
        
        /**
         * Handle overlay permission.
         */
        OverlayRequest overlay();
        
        /**
         * Handle notification permission.
         */
        NotifyOption notification();
        
        /**
         * Handle system setting.
         */
        Setting setting();
    }

        Option接口唯一实现类是Boot,本篇主要阅读权限申请相关的代码,接着借助runtime()方法返回的Runtime实例进行权限申请操作:

    AndPermission.with(this)
            .runtime()
            .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            .onGranted(new Action<List<String>>() {
                @Override
                public void onAction(List<String> data) {
                    //权限允许
                }
            })
            .onDenied(new Action<List<String>>() {
                @Override
                public void onAction(List<String> data) {
                    //权限拒绝
                }
            })
            .rationale(new Rationale<List<String>>() {
                @Override
                public void showRationale(Context context, List<String> data, RequestExecutor executor) {
                    executor.execute();
                }
            })
            .start();

        上面的主要流程如下图所示(本文流程图均用PlantUML绘制):


        通过Runtimepermission(String... permissions)方法进行权限申请,传入需要申请的权限,方法接收不定长String参数,并且返回一个PermissionRequest对象:

    @Override
    public PermissionRequest permission(@NonNull String... permissions) {
        checkPermissions(permissions);
        return FACTORY.create(mSource).permission(permissions);
    }

        FACTORY是用于创建PermissionRequest的工厂,其基本类型是PermissionRequestFactory,工厂的两个实现类分别是:MRequestFactoryLRequestFactory

    public interface PermissionRequestFactory {
        /**
         * Create permission request.
         */
        PermissionRequest create(Source source);
    }

        这里巧妙的利用了多态设计,在静态代码块中根据Android版本初始化:SDK大于等于23,也就是Android 6.0及以上,使用MRequestFactory;低于23即Android 6.0以下,使用LRequestFactory。这也是Android权限在各版本中最大的区别,详见另一篇《Android Permission 权限总结》

    private static final PermissionRequestFactory FACTORY;
    
    static {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            FACTORY = new MRequestFactory();
        } else {
            FACTORY = new LRequestFactory();
        }
    }


        现在Android版本绝大多数以Android 6.0及以上为主,占比95.6%以上。本篇仍以Android 6.0以上的权限申请流程为主,Android 6.0以下的权限申请直接过。


        这里通过MRequestFactory创建MRequest,最后调用start()方法开启权限请求,这部分流程如下:


        接下来,由RequestExecutor执行权限申请任务:

    @Override
    public void run() {
        Context context = mRequest.getSource().getContext();
        mMessenger = new Messenger(context, this);
        mMessenger.register(getName());
        Intent intent = new Intent();
        intent.setAction(AndPermission.bridgeAction(context, null));
        intent.setPackage(context.getPackageName());
        context.bindService(intent, mConnection, Service.BIND_AUTO_CREATE);
    }

        这一步操作,目的是为了绑定BridgeService,并且构造action标识此次权限申请:{package}.andpermission.bridge

    private static final String ACTION_BRIDGE_SUFFIX = ".andpermission.bridge";
    
    public static String bridgeAction(Context context, String suffix) {
        return context.getPackageName() + ACTION_BRIDGE_SUFFIX + (TextUtils.isEmpty(suffix) ? "" : "." + suffix);
    }


        当BridgeService绑定后,在onServiceConnected()回调中执行下面的流程,通过IBinder执行Service中的权限申请方法:

    private void executeCurrent(IBridge iBridge) throws RemoteException {
        switch (mRequest.getType()) {
            ...
            case BridgeRequest.TYPE_PERMISSION: {
                iBridge.requestPermission(getName(), mRequest.getPermissions());
                break;
            }
            ...
        }
    }


        在BridgeService中实现了IBridge接口中的全部方法:

    private Stub mStub = new Stub() {
        private Source mSource = new ContextSource(BridgeService.this);
        public void requestAppDetails(String suffix) throws RemoteException {
            BridgeActivity.requestAppDetails(this.mSource, suffix);
        }
        public void requestPermission(String suffix, String[] permissions) throws RemoteException {
            BridgeActivity.requestPermission(this.mSource, suffix, permissions);
        }
        ...
    };

        可以看到方法中全部都是调用BridgeActivity的静态方法,这些静态方法定义在BridgeActivity类中,申请权限会启动BridgeActivityAndPermission正是借助BridgeActivity完成权限的申请(整个库是这样的设计思路)。当然这个Activity是不可见的,如同Glide通过给Fragment/Activity插入一个不可见的Fragment,通过监听该Fragment的生命周期来实现对应的请求管理。

    /**
     * Request for permissions.
     */
    static void requestPermission(Source source, String suffix, String[] permissions) {
        Intent intent = new Intent(source.getContext(), BridgeActivity.class);
        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_PERMISSION);
        intent.putExtra(KEY_PERMISSIONS, permissions);
        intent.putExtra(KEY_ACTION_SUFFIX, suffix);
        source.startActivity(intent);
    }

        在BridgeActivityonCreate(Bundle savedInstanceState)方法,根据传入的参数判别执行哪一项操作。权限申请最终还是通过ActivityrequestPermissions()方法完成。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) return;
        Intent intent = getIntent();
        int operation = intent.getIntExtra(KEY_TYPE, -1);
        mActionSuffix = intent.getStringExtra(KEY_ACTION_SUFFIX);
        switch (operation) {
            case BridgeRequest.TYPE_APP_DETAILS: {
                Intent appDetailsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                appDetailsIntent.setData(Uri.fromParts("package", getPackageName(), null));
                startActivityForResult(appDetailsIntent, BridgeRequest.TYPE_APP_DETAILS);
                break;
            }
            case BridgeRequest.TYPE_PERMISSION: {
                String[] permissions = intent.getStringArrayExtra(KEY_PERMISSIONS);
                requestPermissions(permissions, BridgeRequest.TYPE_PERMISSION);
                break;
            }
            ...
        }
    }

        并且在onRequestPermissionsResult(...)回执权限申请结果,此部分流程图如下:

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Messenger.send(this, mActionSuffix);
        finish();
    }


        最后通过Messenger(继承自BroadcastReceiver),将权限申请结果从BridgeActivity通过广播传递给权限申请者MRequest。这里的action和申请权限时传入的一样。

    public static void send(Context context, String suffix) {
        Intent broadcast = new Intent(AndPermission.bridgeAction(context, suffix));
        context.sendBroadcast(broadcast);
    }

        再经过层层回调到onAction(T data)将结果传递给开发者,后面这部分流程如下:




不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com