关于Android 6.0动态权限的那些事

最近项目快要结尾的时候,发现了项目在6 0+的设备上运行出现了问题,查看Log发现是权限的问题。这个问题很早就知道,但是自己是5 0的手机,在

最近项目快要结尾的时候,发现了项目在6.0+的设备上运行出现了问题,查看Log发现是权限的问题。这个问题很早就知道,但是自己是5.0的手机,在实际开发的时候忽略了这个,所以这俩天就查了下解决方法。

随便说点

Android 6.0发布都有一年多了,其新引入的(Requesting Permissions at Run Time)运行时权限受众多开发者的关注,随着今年国内手机厂商对6.0系统的普及,觉得Android开发者有必要去了解下了。

在SDK23以前,我们开发的时候要是想要申请权限,直接在AndroidManifest中配置一下就好了,但到了在SDK23+开发的话,我们要是还是这样,当涉及到一些危险权限(Dangerous Permissions)时,程序就又可能会出现崩溃了,这时候需要我们在操作发生之前让用户进行权限授予才能进行下一步的操作。

如果你的app TargetSDK设置在了23以下那么在6.0+系统中运行是不会崩溃的,当然你也可以TargetSDK一直设置在23以下,这样的话你就不需要考虑动态授权的问题了。

下面这张图来自官方文档,给我们展示了哪些权限需要在运行是进行授权。

关于Android 6.0动态权限的那些事

这张图中提及的权限不仅需要在AndroidManifest中进行配置,在SDK23以上开发的时候还需要在运行时让用户进行授权。

使用方法

  • 将targetSdkVersion设置为>= 23,这样的话,在项目的开发种涉及到权限问题时则必须按照Android官方的要求,动态的申请权限。

当然,如果你不想这么做的话,就将将targetSdkVersion设置为设置为 22或22以下 就好了

  • 在AndroidManifest.xml中申请你需要的权限,包括普通权限和需要申请的特殊权限。
  • 接下来就是来申请权限了
    • 1.检查是否由此权限:checkSelfPermission(),如果已经开启,则直接进行需要的操作。
    • 2.如果没有开启,则要判断是否需要向用户解释为何申请权限的原因:shouldShowRequestPermissionRationale。
    • 3.如果需要(返回true),则弹出对话框提示用户申请权限原因,用户确认后申请权限:requestPermissions(),如果不需要(即返回false),则直接申请权限:requestPermissions()。

例子

这里来演示下模拟调用系统相机时需要申请的权限

public class MainActivity extends AppCompatActivity { private Button button; private TextView textView; private final int CAMERA_REQUESTCODE = 0X11;//与回调有关 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); intEvent(); } private void initView() { button = (Button) findViewById(R.id.button); textView = (TextView) findViewById(R.id.textView); } private void intEvent() { button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { takePhoto(); } }); } private void takePhoto() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { /** * 第一次请求权限时,用户如果拒绝,下一次请求调用shouldShowRequestPermissionRationale()方法返回true * 向用户解释为什么需要这个权限 */ if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { new AlertDialog.Builder(this) .setMessage("申请相机权限") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //申请相机权限 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_REQUESTCODE); } }).show(); } else { //申请相机权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_REQUESTCODE); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_REQUESTCODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { textView.setText("相机权限已经申请"); } else { /** * 用户勾选了不在询问 * 提示用户手动打开权限 */ if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { Toast.makeText(this, "相机权限已经禁止", Toast.LENGTH_LONG).show(); } } } }}

当然,别忘了在AndroidManifest中配置相机权限

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

运行结果如下

关于Android 6.0动态权限的那些事 关于Android 6.0动态权限的那些事 关于Android 6.0动态权限的那些事 关于Android 6.0动态权限的那些事

相关API介绍

  • REQUESTCODE :用来进行回调处理,因为申请权限是有回调结果的。
  • ContextCompat.checkSelfPermission :主要用于检测某个权限是否已经被授予,方法参数为(context,需要检测的权限),方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED,当返回PackageManager.PERMISSION_DENIED时需要调用API进行权限申请。
  • ActivityCompat.requestPermissions :用于权限的申请,方法参数为(context,需要申请的权限数组,自定义的请求码),系统会弹出一个申请权限的对话框。
  • shouldShowRequestPermissionRationale :Android原生系统中,如果第二次弹出权限申请的对话框,会出现“以后不再弹出”的提示框,如果用户勾选了,你再申请权限,则shouldShowRequestPermissionRationale返回true,意思是说要给用户一个 解释,告诉用户为什么要这个权限。但是在实际开发中我们需要注意国内一些厂商定制的系统,比如在申请权限时,如果用户选择了拒绝,则不会再弹出对话框,所以我就在回调里面进行处理,如果用户拒绝了这个权限,则打开本应用信息界面,由用户自己手动开启这个权限。

备注

在我的实际项目中涉及到了在Fragment中申请权限,这时候需要注意:

  • 在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的 onRequestPermissionsResult
  • 如果在Fragment中嵌套Fragment,则在子Fragment中使用requestPermissions方 法,这样onRequestPermissionsResult不会回调回来,建议使用 getParentFragment().requestPermissions方法,
    这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment
    @Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); List<Fragment> fragments = getChildFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null) { fragment.onRequestPermissionsResult(requestCode,permissions,grantResults); } } }}
未登录用户
全部评论0
到底啦