2018-07-15 22:51:16 q97531x 阅读数 114
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12872 人正在学习 去看看 CSDN讲师

什么是android动态权限

android动态权限是google在android6.0中引入的一种在程序运行时请求的权限,动态一词就是用于区分6.0以前的静态获取权限的方式。6.0以前权限只在安装app时列明,同意安装即意味着同意授予权限。这有可能导致用户的隐私权受到侵犯。所以在6.0以后危险的权限一律需要通过请求允许后方能调用

动态权限的分类

系统权限分为两类:正常权限和危险权限:

  • 正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。
  • 危险权限会授予应用访问用户机密数据的权限。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须明确批准您的应用使用这些权限。

1.需要用户手动赋予的权限( Dangerous Permissions)

所属权限组 权限
日历 READ_CALENDAR;WRITE_CALENDAR
相机 CAMERA
联系人 READ_CONTACTS;WRITE_CONTACTS;GET_ACCOUNTS
位置 ACCESS_FINE_LOCATION; ACCESS_COARSE_LOCATION
麦克风 RECORD_AUDIO
电话 READ_PHONE_STATE;CALL_PHONE;READ_CALL_LOG;WRITE_CALL_LOG;WRITE_CALL_LOG;ADD_VOICEMAIL; USE_SIP;PROCESS_OUTGOING_CALLS
传感器 BODY_SENSORS
短信 SEND_SMS;RECEIVE_SMS;READ_SMS;RECEIVE_WAP_PUSH;RECEIVE_MMS
存储 READ_EXTERNAL_STORAGE;WRITE_EXTERNAL_STORAGE

权限申请关键代码

/**
     * 判断用户是否拥有该权限
     * @param permission 申请的权限
     * @return
     */
    private boolean hasPermission(String permission) {
        int result = PermissionChecker.checkSelfPermission(context, permission);
        if (result != PermissionChecker.PERMISSION_GRANTED) {
            return false;
        }
        return true;
    }
/**
     * 获取是否点击了不再询问按钮,只在androidM生效,动态权限是android6.0以上需求
     * @param permissionName
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private boolean isNeverAsk(@NonNull String permissionName) {
        return ((Activity)context).shouldShowRequestPermissionRationale(permissionName);
    }
/**
     * 动态请求权限 系统会弹个框
     *
     * @param permissions 待用户授权的权限集
     */
    private void requestPermission(String[] permissions) {
        ActivityCompat.requestPermissions(this, permissions, REQ_CODE);
    }

参考资料

https://developer.android.google.cn/guide/topics/security/permissions

2018-08-07 16:39:17 feather_wch 阅读数 215
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12872 人正在学习 去看看 CSDN讲师

Android 6.0以上动态权限申请的简单实例。
转载请注明链接:https://blog.csdn.net/feather_wch/article/details/81483960

Android 6.0 动态权限

最后修改: 2018/8/7-1(23:00)


简介

自从Android 6.0开始,一些重要权限不仅要保留原来的静态注册,还需要进行额外的动态注册。

动态注册方法

在AndroidManifest中申请权限

<!-- 添加可监听电话状态的权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

代码中进行动态申请

必须要在Activity中,Application中无法处理弹窗的需求

/**
 * 检查和申请权限
 */
public void requestPermission(){
    //判断是否已经赋予权限
    if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED
        || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED
        || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED){

        //多个权限一起进行申请
        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE
            }, 1);//RequestCode = 1,用于处理弹窗结果
    }else{
        Log.d(TAG, "Has Permission: READ_PHONE_STATE");
        /*============================================
         * 如果已经具有权限,就直接走接下来的流程。
         * * 该方法根据自己的业务逻辑去实现。
         *===================================*/
        doNextWork();
    }
}

处理动态申请权限的结果

  1. 处理动态申请权限的结果.
  2. 用户点击了拒绝或者同意后触发.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    //requestCode 对应于`requestPermissions`的requestCode
    switch(requestCode){
        case 1:
            //获取到了权限(按顺序,对三个权限进行验证)
            if(grantResults.length > 2
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED
                    && grantResults[2] == PackageManager.PERMISSION_GRANTED
                    ){
                doNextWork();
            }else{
                //没有获取到权限,直接退出app。不然也没办法继续使用。
                Toast.makeText(this, "App must has permission!", Toast.LENGTH_SHORT).show();
                finish();
            }
            break;
        default:
            break;
    }
}
2018-10-24 20:10:48 u010257120 阅读数 211
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12872 人正在学习 去看看 CSDN讲师

Android动态权限

动态权限基本每个项目都用得到,懒得每次都写整理一下自己用,尽量少点copy(╯0╰)
不想漫天飞舞的引入别人的依赖,简单的事情尽量不要搞复杂,除非真的有必要。

动态预览

Alt

使用权限情景:

  1. App初始化时申请所有权限
  2. 部分涉及权限操作的地方,要检查权限是否可用

代码部分

1.工具类(PermissionManager.java)

	package com.huan.squirrel.appermission.util;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;

import com.huan.squirrel.appermission.R;

import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;

/**
 * 系统权限管理
 * Created by huan on 2017/11/14.
 */
public class PermissionManager {
    private static int REQUEST_PERMISS_CODE = 3248;
    //请求悬浮
    public static int SYSTEM_ALERT_WINDOW_CODE = 11004;
    private Activity context;
    private static PermissionManager instance;
    AlertDialog.Builder builder;
    AlertDialog dialog;

    public static PermissionManager getInstance(Activity context) {
        if (instance == null) {
            instance = new PermissionManager(context);
        }
        return instance;
    }

    public PermissionManager(Activity context) {
        this.context = context;
    }

    //普通权限
    private static String[] PERMISSIONS_ALL = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};
    //需要的特殊权限,需要进入设置页面才能授权的
    private static String[] PERMISSIONS_SPE = {Manifest.permission.SYSTEM_ALERT_WINDOW, Manifest.permission.INSTALL_PACKAGES};

    //初始化app所需的权限
    public void initPermission() {
        if (builder != null && dialog != null) {
            dialog.dismiss();
        }
        if (getPermissionStatus2(context, PERMISSIONS_SPE)) {//初始化特殊权限
            if (!getPermissionStatus(context, PERMISSIONS_ALL)) {//初始化普通权限
                chekPermission(context, PERMISSIONS_ALL, new PermissionManager.OnCheckPermissionListener() {
                    @Override
                    public void onPassed() {
                        //必须授权所有权限才能使用则,否则嵌套循环
                        initPermission();
                    }

                    @Override
                    public void onNoPassed() {
                        //必须授权所有权限才能使用则,否则嵌套循环
                        initPermission();
                    }
                });
            }
        }
    }

    //特殊权限弹窗后进入设置页面处理
    public void showPermissionSettingDialog(final Context context, String permission) {
        switch (permission) {
            case Manifest.permission.INSTALL_PACKAGES:
                //弹框提示用户手动打开
                showAlert(context, "安装权限", "需要打开允许来自此来源,请去设置中开启此权限", new DialogInterface.OnClickListener() {
                    @RequiresApi(api = Build.VERSION_CODES.O)
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //此方法需要API>=26才能使用
                        startInstallPermissionSettingActivity((Activity) context);
                    }
                });
                break;
            case Manifest.permission.SYSTEM_ALERT_WINDOW:
                //弹框提示用户手动打开
                showAlert(context, "悬浮窗权限", "需要打开在其他应用中显示", new DialogInterface.OnClickListener() {
                    @RequiresApi(api = Build.VERSION_CODES.O)
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //此方法需要API>=26才能使用
                        getOverlayPermission((Activity) context);
                    }
                });
                break;
        }
    }

    //跳转到设置-请求悬浮窗权限
    @TargetApi(Build.VERSION_CODES.M)
    public void getOverlayPermission(Activity context) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        intent.setData(Uri.parse("package:" + context.getPackageName()));
        //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivityForResult(intent, SYSTEM_ALERT_WINDOW_CODE);
    }

    // 跳转到设置-允许安装未知来源-页面
    @TargetApi(Build.VERSION_CODES.O)
    public static void startInstallPermissionSettingActivity(final Activity context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Uri packageURI = Uri.parse("package:" + context.getPackageName());
            //注意这个是8.0新API
            Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
            //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    }

    //检查安装app权限是否可用
    public static boolean getPermissionStatusByName(Context context, String permissionName) {
        //兼容8.0
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            switch (permissionName) {
                case Manifest.permission.INSTALL_PACKAGES:
                    return context.getPackageManager().canRequestPackageInstalls();
                case Manifest.permission.SYSTEM_ALERT_WINDOW:
                    return Settings.canDrawOverlays(context);
            }
        }
        return true;
    }

    //获取普通权限是否可用
    @TargetApi(Build.VERSION_CODES.M)
    public static boolean getPermissionStatus(Context context, String permissionName) {
        // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int i = ContextCompat.checkSelfPermission(context, permissionName);
            // 权限是否已经 授权 GRANTED---授权  DINIED---拒绝
            return (i == PackageManager.PERMISSION_GRANTED);
        }
        return true;
    }

    //特殊权限
    public boolean getPermissionStatus2(Context context, String[] permissions) {
        // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 检查该权限是否已经获取
            for (String str : permissions) {
                if (!getPermissionStatusByName(context, str)) {
                    showPermissionSettingDialog(context, str);
                    return false;
                }
            }
        }
        return true;
    }

    //普通权限
    public static boolean getPermissionStatus(Context context, String[] permissions) {
        // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 检查该权限是否已经获取
            for (String str : permissions) {
                if (!getPermissionStatus(context, str)) {
                    return false;
                }
            }
        }
        return true;
    }

    public static  void chekPermission(Context context, String[] permissions, OnCheckPermissionListener listener) {
        // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 检查该权限是否已经获取
            boolean useful = getPermissionStatus(context, permissions);
            if (!useful) {
                // 如果没有授予该权限,就去提示用户请求
                showDialogTipUserRequestPermission(context, permissions);
            } else {
                listener.onPassed();
            }
        } else {
            listener.onPassed();
        }
    }

    // 提示用户该请求权限的弹出框
    private static void showDialogTipUserRequestPermission(final Context context, final String[] permission) {
        new AlertDialog.Builder(context)
                .setTitle("权限不可用")
                .setMessage("请开启权限后,再继续操作")
                .setPositiveButton("立即开启", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startRequestPermission(context, permission);
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(context, "请开启权限后再操作", Toast.LENGTH_LONG).show();
                        instance.initPermission();
                    }
                }).setCancelable(false).show();
    }

    // 开始提交请求权限
    private static void startRequestPermission(final Context context, String[] permissions) {
        ActivityCompat.requestPermissions((Activity) context, permissions, REQUEST_PERMISS_CODE);
    }

    //部分权限需要延时后生效
    public void showProcess() {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //重新检查所有权限是否可用
                initPermission();
            }
        }, 1000);
    }

    /**
     * 监听器,监听权限是否通过
     */
    public interface OnCheckPermissionListener {
        void onPassed();//通过

        void onNoPassed();//不通过
    }

    /**
     * alert 消息提示框显示
     *
     * @param context  上下文
     * @param title    标题
     * @param message  消息
     * @param listener 监听器
     */
    public void showAlert(Context context, String title, String message, DialogInterface.OnClickListener listener) {
        builder = new AlertDialog.Builder(context);
        builder.setTitle(title);
        builder.setMessage(message);
        builder.setPositiveButton("确定", listener);
        builder.setCancelable(false);
        builder.setIcon(R.mipmap.ic_launcher);
        dialog = builder.create();
        dialog.show();
    }
}

2.使用部分(MainActivity.java)

package com.huan.squirrel.appermission;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.huan.squirrel.appermission.util.PermissionManager;

import static com.huan.squirrel.appermission.util.PermissionManager.SYSTEM_ALERT_WINDOW_CODE;

public class MainActivity extends AppCompatActivity {

    private Context context;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /*********************     需要权限的功能要再次检查权限是否可用    start     ******************************************/
        context = this;
        final Button btn_permission = findViewById(R.id.btn_permission);

        final String[] PERMISSIONS_ALL = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA};
        btn_permission.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PermissionManager.chekPermission(context, PERMISSIONS_ALL, new PermissionManager.OnCheckPermissionListener() {
                    @Override
                    public void onPassed() {
                        Toast.makeText(context,"权限已经全部开启",Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onNoPassed() {
                        Toast.makeText(context,"部分权限未开启",Toast.LENGTH_LONG).show();
                    }
                });
            }
        });

        /*************************   需要权限的功能要再次检查权限是否可用  end      **************************************/
    }

    /************************  app第一次打开页面设置app运行必要的权限    start     ***************************************/
    @Override
    protected void onResume() {
        super.onResume();
        PermissionManager.getInstance(this).initPermission();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(SYSTEM_ALERT_WINDOW_CODE==requestCode){
            PermissionManager.getInstance(this).showProcess();
        }else{
            PermissionManager.getInstance(this).initPermission();
        }
    }

    //处理权限申请回调(写在Activity中)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        PermissionManager.getInstance(this).initPermission();
    }
    /**********************     app第一次打开页面设置app运行必要的权限    start   ***************************************/

}

使用

1.activity中声明全部的权限
复制三个方法 onResume, onActivityResult, onRequestPermissionsResult

2.某些需要权限才能操作的时候需要检查
使用 PermissionManager.chekPermission()方法处理

问题

1.有些地方还存在问题没有好的解决。如 获取悬浮窗权限的时候,跳转到设置页面手动开启权限后,返回MainActivity并通过Settings.canDrawOverlays方法没有及时返回true,要延迟一会儿。
2.没有对onActivityResult方法做过多的判断,全都在resume方法中重新检查并初始化权限(容易让人诟病)。
3.特殊权限需要的时候自己添加处理。

源码

https://github.com/squirrelhuan/APPermission

2018-04-10 22:14:55 ArimaKisho 阅读数 277
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12872 人正在学习 去看看 CSDN讲师

在《Android6.0动态权限申请总结》一文中,我们详细分析了6.0之前与之后的权限管理变化。以及使用4个方法来适配Android6.0的动态权限申请。

忘记或者想要看的朋友,在此奉上文章链接:Android6.0动态权限申请总结

在文章的最后我们说了,这样适配动态权限步骤繁琐、代码分散,对于一个项目维护来说,并不是很好的一件事情。

并且我们讨论了一种我们期望的动态权限申请方案。

本篇文章我们来讲一下对于动态权限申请的封装方案。先上github项目地址:一个优雅的Android6.0动态权限申请库

我们先来看一下具体使用起来是怎么样的:

(1)声明你需要申请的权限:

final String[] permissions = new String[]{
    Manifest.permission.WRITE_EXTERNAL_STORAGE,
    Manifest.permission.CAMERA,
    Manifest.permission.CALL_PHONE
};

(2)创建PermissionRequest类对象并调用request方法:

new PermissionRequest(
    getActivity()
).request(
    permissions,
    new PermissionRequestListener() {
        @Override
        public void onAllowAllPermissions() {
            //所有申请的权限均被允许
        }

        @Override
        public void onDenySomePermissions(Collection<String> denyPermissions) {
            //申请的权限中有权限被拒绝
        }

        @Override
        public void onDenyAndNeverAskAgainSomePermissions(
            Collection<String> denyAndNeverAskAgainPermissions
        ) {
            //申请的权限中有权限被拒绝并勾选了不再提示
        }
    }
);

两步结束,就是这么简单粗暴。仅仅通过两个步骤我们就解决了Android6.0的动态权限问题。对比一下上一篇的代码,这次我们没有被分散的回调,业务代码完全可以集中写在PermissionRequestListener中。而且动态权限申请不再被局限于Activity和Fragment中,只要可以获得到Activity对象,我们可以在任何地方调用该库,来请求动态权限。这样确实实现了我们在上一篇最后所期望达到的结果。

接下来,简单描述一下封装过程。

(1)首先我们定义一个PermissionRequestListener接口。为我们上一篇所讲的动态权限请求结果的3种情况,分别提供一个回调方法。并且在有权限被拒绝 和 有权限被拒绝并不再提示 2种情况下,将被拒绝和不再提示的权限回传给用户。供用户选择性处理。

public interface PermissionRequestListener {

    /**
     * 所有申请的权限均被允许的回调
     */
    void onAllowAllPermissions();

    /**
     * 申请的权限中有权限被拒绝的回调
     */
    void onDenySomePermissions(Collection<String> denyPermissions);

    /**
     * 申请的权限中有权限被拒绝并勾选了不再提示的回调
     */
    void onDenyAndNeverAskAgainSomePermissions(Collection<String> denyAndNeverAskAgainPermissions);

}

(2)接下来我们定义一个PermissionRequest类,该类用于接收用户的申请权限列表和PermissionRequestListener实现类。用于请求权限和回调权限结果的函数。

但是有一个问题出现了。就是Android系统的requestPermissions函数和权限申请的结果回调函数onRequestPermissionsResult是在Activity和Fragment中的。为了更好的将这两个函数也封装起来,我们采用一个没有UI界面的Fragment作为中转。该Fragment所做的事情只有一个,就是申请权限和得到结果。

public class PermissionRequest {

    private static final int REQUEST_CODE = 1990;
    private static final String FRAGMENT_TAG = "PermissionRequestFragment";

    private Activity mActivity;

    public PermissionRequest(
            @NonNull Activity activity
    ) {
        mActivity = activity;
    }

    public void request(
            @NonNull String[] permissions,
            @NonNull PermissionRequestListener permissionRequestListener
    ) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            permissionRequestListener.onAllowAllPermissions();
        } else {
            PermissionRequestListenerWrapper permissionRequestListenerWrapper
                    = new PermissionRequestListenerWrapper(permissionRequestListener);
            if (!EventBus.getDefault().isRegistered(permissionRequestListenerWrapper)) {
                EventBus.getDefault().register(permissionRequestListenerWrapper);
            }

            if (mActivity != null) {
                PermissionRequestFragment permissionRequestFragment;
                Fragment fragment = mActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
                if (fragment != null && fragment instanceof PermissionRequestFragment) {
                    permissionRequestFragment = (PermissionRequestFragment) fragment;
                } else {
                    permissionRequestFragment
                            = PermissionRequestFragment.makeFragment(REQUEST_CODE);
                    mActivity.getFragmentManager().beginTransaction().add(
                            permissionRequestFragment,
                            FRAGMENT_TAG
                    ).commitAllowingStateLoss();
                    mActivity.getFragmentManager().executePendingTransactions();
                }
                if (permissionRequestFragment.isAdded()) {
                    permissionRequestFragment.requestPermissions(
                            permissions,
                            REQUEST_CODE
                    );
                }
            }
        }
    }

}

(3)没有UI界面的Fragment

public class PermissionRequestFragment extends Fragment {

    public static final String REQUEST_CODE = "REQUEST_CODE";
    private int mRequestCode;

    public static PermissionRequestFragment makeFragment(
            int requestCode
    ) {
        PermissionRequestFragment permissionRequestFragment
                = new PermissionRequestFragment();
        Bundle arguments = new Bundle();
        arguments.putInt(REQUEST_CODE, requestCode);
        permissionRequestFragment.setArguments(arguments);
        return permissionRequestFragment;
    }

    @Nullable
    @Override
    public View onCreateView(
            LayoutInflater inflater,
            ViewGroup container,
            Bundle savedInstanceState
    ) {
        View view = super.onCreateView(inflater, container, savedInstanceState);
        Bundle arguments = getArguments();
        if (arguments != null) {
            mRequestCode = arguments.getInt(REQUEST_CODE);
        }
        return view;
    }

    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            @NonNull String[] permissions,
            @NonNull int[] grantResults
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == mRequestCode) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                int length = grantResults.length;
                LinkedHashSet<String> denyAndNeverAskAgainPermissions = new LinkedHashSet<>();
                LinkedHashSet<String> denyPermissions = new LinkedHashSet<>();
                for (int i = 0; i < length; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        boolean b = shouldShowRequestPermissionRationale(permissions[i]);
                        if (!b) {
                            //申请的权限中有权限被拒绝并勾选了不再提示
                            denyAndNeverAskAgainPermissions.add(permissions[i]);
                        } else {
                            //申请的权限仅仅是被用户拒绝
                            denyPermissions.add(permissions[i]);
                        }
                    }
                }
                if (denyAndNeverAskAgainPermissions.size() > 0) {
                    //申请的权限中有权限被拒绝并勾选了不再提示
                    EventBus.getDefault().post(
                            new OnDenyAndNeverAskAgainSomePermissionsEvent(
                                    denyAndNeverAskAgainPermissions
                            )
                    );
                } else if (denyPermissions.size() > 0) {
                    //申请的权限中有权限被拒绝
                    EventBus.getDefault().post(new OnDenySomePermissionsEvent(
                            denyPermissions
                    ));
                } else {
                    //所有申请的权限均被允许
                    EventBus.getDefault().post(new OnAllowAllPermissionsEvent());
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().post(new OnPermissionRequestFragmentDestroyEvent());
    }

}

(4)这里我们采用EventBus根据不同的结果发出不同的Event。而对于用户传进来的PermissionRequestListener,我们对其做了一层包装,使他能够获得到Fragment发来的事件:

public class PermissionRequestListenerWrapper {

    private PermissionRequestListener mPermissionRequestListener;

    public PermissionRequestListenerWrapper(PermissionRequestListener permissionRequestListener) {
        mPermissionRequestListener = permissionRequestListener;
    }

    @Subscribe
    public void onReceivedOnAllowAllPermissionsEvent(
            OnAllowAllPermissionsEvent onAllowAllPermissionsEvent
    ) {
        if (mPermissionRequestListener != null) {
            mPermissionRequestListener.onAllowAllPermissions();
        }
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    @Subscribe
    public void onReceivedOnDenySomePermissionsEvent(
            OnDenySomePermissionsEvent onDenySomePermissionsEvent
    ) {
        if (mPermissionRequestListener != null) {
            mPermissionRequestListener.onDenySomePermissions(
                    onDenySomePermissionsEvent.getDenyPermissions()
            );
        }
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    @Subscribe
    public void onReceivedOnDenyAndNeverAskAgainSomePermissionsEvent(
            OnDenyAndNeverAskAgainSomePermissionsEvent onDenyAndNeverAskAgainSomePermissionsEvent
    ) {
        if (mPermissionRequestListener != null) {
            mPermissionRequestListener.onDenyAndNeverAskAgainSomePermissions(
                    onDenyAndNeverAskAgainSomePermissionsEvent.getDenyAndNeverAskAgainPermissions()
            );
        }
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    @Subscribe
    public void onReceivedOnPermissionRequestFragmentDestroyEvent(
            OnPermissionRequestFragmentDestroyEvent onPermissionRequestFragmentDestroyEvent
    ) {
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

}

到此,这个动态权限封装库我们就做好了。期间,对于requestPermissions和onRequestPermissionsResult封装遇到了些问题。后来在Github上看到了这个库:RxPermissions,得到了解决方案。

学习之路很长,大家共勉吧!




2019-02-26 17:48:56 songqinging 阅读数 153
  • Android 6.0运行时权限讲解

    本节课中会对Android 6.0系统中新增的运行时权限功能进行一次透彻的讲解,包含运行时权限的引入背景、基本用法、佳封装实践等,还会讲一些很多人并不知道的运行时权限微技巧。

    12872 人正在学习 去看看 CSDN讲师

Android 6.0版本之后,需要配置动态权限,动态权限代码有点多,纯粹记住是比较难的,所以这里提供一下模板代码,直接copy即可,然后修改或增加需要的权限即可。
基类文件RequestPermissionsActivityBase:

package com.android.face.permission;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Trace;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Activity that asks the user for all {@link #getDesiredPermissions} if any of
 * {@link #getRequiredPermissions} are missing.
 *
 * NOTE: As a result of b/22095159, this can behave oddly in the case where the final permission
 * you are requesting causes an application restart.
 */
public abstract class RequestPermissionsActivityBase extends Activity
        implements ActivityCompat.OnRequestPermissionsResultCallback {
    public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";

    /** Whether the permissions activity was already started. */
    protected static final String STARTED_PERMISSIONS_ACTIVITY = "started_permissions_activity";

    private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;

    /**
     * @return list of permissions that are needed in order for {@link #PREVIOUS_ACTIVITY_INTENT} to
     * operate. You only need to return a single permission per permission group you care about.
     */
    protected abstract String[] getRequiredPermissions();
    
    /**
     * @return list of permissions that would be useful for {@link #PREVIOUS_ACTIVITY_INTENT} to
     * operate. You only need to return a single permission per permission group you care about.
     */
    protected abstract String[] getDesiredPermissions();

    protected Intent mPreviousActivityIntent;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
        
        // Only start a requestPermissions() flow when first starting this activity the first time.
        // The process is likely to be restarted during the permission flow (necessary to enable
        // permissions) so this is important to track.
        if (savedInstanceState == null) {
            requestPermissions();
        }
    }
    
    /**
     * If any permissions the Contacts app needs are missing, open an Activity
     * to prompt the user for these permissions. Moreover, finish the current activity.
     *
     * This is designed to be called inside {@link Activity#onCreate}
     */
     protected static boolean startPermissionActivity(Activity activity,
                                                     String[] requiredPermissions, Class<?> newActivityClass) {
         if (!hasPermissions(activity, requiredPermissions)) {
            final Intent intent = new Intent(activity,  newActivityClass);
            activity.getIntent().putExtra(STARTED_PERMISSIONS_ACTIVITY, true);
            intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
            activity.startActivity(intent);
            activity.finish();
            return true;
        }
        
        return false;
    }
    
    protected boolean isAllGranted(String permissions[], int[] grantResult) {
        for (int i = 0; i < permissions.length; i++) {
            if (grantResult[i] != PackageManager.PERMISSION_GRANTED
                    && isPermissionRequired(permissions[i])) {
                return false;
            }
        }
        return true;
    }
    
    private boolean isPermissionRequired(String p) {
        return Arrays.asList(getRequiredPermissions()).contains(p);
    }
    
    private void requestPermissions() {
        Trace.beginSection("requestPermissions");
        try {
            // Construct a list of missing permissions
            final ArrayList<String> unsatisfiedPermissions = new ArrayList<>();
            for (String permission : getDesiredPermissions()) {
                if (checkSelfPermission(permission)
                        != PackageManager.PERMISSION_GRANTED) {
                    unsatisfiedPermissions.add(permission);
                }
            }
            if (unsatisfiedPermissions.size() == 0) {
                throw new RuntimeException("Request permission activity was called even"
                        + " though all permissions are satisfied.");
            }
            ActivityCompat.requestPermissions(
                    this,
                    unsatisfiedPermissions.toArray(new String[unsatisfiedPermissions.size()]),
                    PERMISSIONS_REQUEST_ALL_PERMISSIONS);
        } finally {
            Trace.endSection();
        }
    }
    
    @Override
    public int checkSelfPermission(String permission) {
        return ContextCompat.checkSelfPermission(this, permission);
    }
    
    protected static boolean hasPermissions(Context context, String[] permissions) {
        Trace.beginSection("hasPermission");
        try {
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(context, permission)
                        != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
            return true;
        } finally {
            Trace.endSection();
        }
    }
}

子类文件RequestPermissionsActivity:

package com.android.face.permission;

import android.Manifest.permission;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;

/**
 * Activity that requests permissions needed for activities exported from Contacts.
 */
public class RequestPermissionsActivity extends RequestPermissionsActivityBase {
    private static final String[] REQUIRED_PERMISSIONS = new String[]{
            permission.CALL_PHONE,
            permission.READ_PHONE_STATE,
            permission.READ_CONTACTS,
            permission.ACCESS_COARSE_LOCATION,
            permission.WRITE_EXTERNAL_STORAGE,
            permission.READ_EXTERNAL_STORAGE,
            permission.CAMERA,
            permission.RECORD_AUDIO
    };
    
    @Override
    protected String[] getRequiredPermissions() {
        return REQUIRED_PERMISSIONS;
    }

    @Override
    protected String[] getDesiredPermissions() {
        return REQUIRED_PERMISSIONS;
    }
    
    public static boolean startPermissionActivity(Activity activity) {
        return startPermissionActivity(activity, REQUIRED_PERMISSIONS,
                RequestPermissionsActivity.class);
    }
    
    @Override
    public void onRequestPermissionsResult(
            int requestCode, String permissions[], int[] grantResults) {
        if (permissions != null && permissions.length > 0
                && isAllGranted(permissions, grantResults)) {
            mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            startActivity(mPreviousActivityIntent);
            finish();
            overridePendingTransition(0, 0);
        } else {
            //Toast.makeText(this, R.string.missing_required_permission, Toast.LENGTH_SHORT).show();
            finish();
        }
    }
    
    /**
     * M: Add for check basic permissions state.
     */
    public static boolean hasBasicPermissions(Context context) {
        return hasPermissions(context, REQUIRED_PERMISSIONS);
    }
}

然后只要在Activity类中的方法onCreate开始部分调用:

if (RequestPermissionsActivity.startPermissionActivity(this)) {
    return;
}

将上面两个类代码copy到文件,然后如上调用一把,再将需要的权限申请写到RequestPermissionsActivity类的数组REQUIRED_PERMISSIONS中,最后还需要将对应的权限申请配置在AndroidManifest.xml文件中。

按照上面步骤做一遍,运行应用就会弹出权限界面了。

没有更多推荐了,返回首页