Android运行时动态权限获取

运行时动态权限简介

在targetSdkVersion小于23的应用中默认授予AndroidManifest中声明的所有权限,而无需手动授予。当targetSdkVersion在23或以上时,应用默认不会授予“Dangerous”级别的权限,Android默认只要授予该组一个权限即可获得该组的所有权限。

动态权限获取

下面将演示如何通过运行时权限获取来调用系统相机进行拍照和录制视频

首先以targetSdkVersion 23来编译调试应用,要调用相机拍照并存储需要在在AndroidManifest.xml文件里声明以下两个权限:

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

至于界面的代码我这里就不贴上来了,可下载源码查看。这个时候(未加入运行时动态权限检测)如果调试应用,点击拍照按钮你会发现应用会崩溃,其实原因很简单,就是应用没有获取以上两个权限。

因此从targetSdkVersion 23开始,对“Dangerous”级别的权限我们要开启运行时动态权限检测,检测是否有相应权限代码如下:

 if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermission();
            } else {
                openCamera(v);
            }

checkSelfPermission函数检测是否具有某个权限,该函数现有两个版本(推荐使用后一个版本)checkSelfPermission(String permission)ActivityCompat.checkSelfPermission(Context context, String permission)。前一个版本是API 23中引入的,只能在API 23及以上使用。后一个版本是support v4包里的,使用时可以省去了版本检测的代码。该函数的返回值只有两个PackageManager.PERMISSION_GRANTEDPackageManager.PERMISSION_DENIED,即权限被授予和拒绝。这里if语句判断权限是否都被授予了,如果缺少权限则调用requestPermission()去请求权限,否则就进行下一步操作。

    /**
     * 请求权限,一次请求多个
     */
    private void requestPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Snackbar.make(fl, "需要获取相关的权限", Snackbar.LENGTH_INDEFINITE)
                    .setAction("确定", new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    REQUEST_PERMISSION);
                        }
                    })
                    .setActionTextColor(getResources().getColor(R.color.colorAccent))
                    .show();
        } else {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_PERMISSION);
        }
    }

    /**
     * 请求权限结果的回调
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION) {
            if (grantResults[0] == PackageManager.PERMISSION_DENIED && grantResults[1] == PackageManager.PERMISSION_DENIED) {
                Snackbar.make(fl, "未授予任何权限", Snackbar.LENGTH_SHORT)
                        .show();
            } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_DENIED) {
                Snackbar.make(fl, "未授予读写存储空间权限", Snackbar.LENGTH_SHORT)
                        .show();
            } else if (grantResults[0] == PackageManager.PERMISSION_DENIED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                Snackbar.make(fl, "未授予打开相机权限", Snackbar.LENGTH_SHORT)
                        .show();
            } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED){
                openCamera(view);
            }
        }
    }

requestPermissions是权限请求函数,同checkSelfPermission一样也是两个版本,对此这里不再讨论。该函数有个回调函数onRequestPermissionsResult:这里可以判断权限被授予还是拒绝,从而进行下一步操作。

shouldShowRequestPermissionRationale函数同checkSelfPermission一样也是两个版本,对此这里不再讨论。这里详细说明shouldShowRequestPermissionRationale函数的返回值:

1、第一次调用总是返回false,因此直接调用requestPermissions去请求权限组,如图:

2、当第一次请求权限点击拒绝以后,如果再次请求权限,则返回true,这时候权限对话框会多出一个‘不再询问’的选项。如果勾选了该选项,就只能选择拒绝权限,此时若选择了拒绝只能去应用管理授予权限了或者清除数据再次请求。

3、如果勾选了不再询问选项并拒绝权限,再次请求权限时永远返回false,不会显示权限对话框,所有权限都默认被拒绝了,并且直接回调onRequestPermissionsResult函数。

注:SnackBar是Android Support Library里面新增提供的一个控件,类似Toast但比Toast更好用,想要了解请参见我另一篇博客Android Material design之Snackbars

openCamera函数代码如下,一看就明白,这里不再讨论了。


    /**
     * 打开相机
     *
     * @param view
     */
    private void openCamera(View view) {
        file = new File(Environment.getExternalStorageDirectory() + File.separator + "CameraDemo1");
        if (!file.exists()) {
            file.mkdirs();
        }
        vv.setVisibility(View.GONE);
        iv.setVisibility(View.GONE);
        switch (view.getId()) {
            case R.id.bt_picture:
                name = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
                uri = Uri.fromFile(new File(file.getPath() + File.separator + name + ".jpg"));
//                    启动系统相机拍照
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                startActivityForResult(intent, PICTURE);
                break;
            case R.id.bt_video:
                name = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
                uri = Uri.fromFile(new File(file.getPath() + File.separator + name + ".mp4"));
//                    启动系统相机录像
                Intent intent1 = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
                intent1.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                intent1.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                startActivityForResult(intent1, VIDEO);
                break;
        }
    }

AndroidStudio源码下载

时间: 2024-10-06 04:49:14

Android运行时动态权限获取的相关文章

android 6.0+ 动态权限获取

android 6.0+ 的权限 需要动态申请 这里的权限针对的是 敏感权限: SMS(短信) SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS STORAGE(存储卡) READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE CONTACTS(联系人) READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS PHONE(手机) READ_PHONE_STATE CA

【Android运行时权限申请快速学习教程】

1. Android权限介绍 Android权限是Android应用在设备上运行所需要的权力,义务就是为用户带来此Android应用的功能. 问题来源:在Android6.0版本之前,根据App在AndroidManifest申请的权限,在安装此App的时候进行提示权限允许,不允许就不给装不给用,那么我们只能默默的忍受这个APP对我们隐私的侵蚀(Eg.通讯录的读取权限). 解决办法:后来Google发现,诶,这样会导致Android用户们想用这个APP的某些功能而不能用.因此,在Android6

Android 6.0 - 动态权限管理的解决方案(转)

转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案 转载请标注 Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应用权限. 时代总是不断发展, 程序总是以人为本, 让我们为应用添加动态权限管理吧! 这里提供了一个非常不错的解决方案, 提供源码, 项目可以直

Android 开发时如何正确获取使用扩展存储路径

Android 开发时如何正确获取使用扩展存储路径 先介绍一下Android的存储 在 2.x 版本中,Android设备都是单存储,第三方App写文件,必须申请 WRITE_EXTERNAL_STORAGE 权限: 在4.0之后,Android设备开始有了内置闪存,即 primary storage,并且可以外置SD卡,即 secondary external storage device: WRITE_EXTERNAL_STORAGE 权限变成了仅仅控制 primary storage,同时

C# 在运行时动态创建类型

C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译器实例. provider = new CSharpCodeProvider(); //设置编译参数. cp = new CompilerParameters(); cp.GenerateExecutable = false; cp.GenerateInMemory = true; // Gener

C#在运行时动态创建类型的实现方法

本文实例讲述了C#在运行时动态创建类型的实现方法.是C#项目开发中很实用的技巧.分享给大家供大家参考.具体分析如下: 具体来说, C# 在运行时动态的创建类型是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型的 . 主要功能代码如下: public static Assembly NewAssembly() { //创建编译器实例. provider = new CSharpCodeProvider(); //设置编译参数. cp = new CompilerParame

转: gcc 指定运行时动态库路径

gcc 指定运行时动态库路径 Leave a reply 由于种种原因,Linux 下写 c 代码时要用到一些外部库(不属于标准C的库),可是由于没有权限,无法将这写库安装到系统目录,只好安装用户目录下如 /home/youname/lib,可是怎么编译才能让程序正常编译,并且正常运行呢.这样使用gcc:gcc -I/path/to/include/dir -L/path/to/lib/dir -llibname -Wl,-rpath,/path/to/lib/dir -o test test.

LINQ to SQL 运行时动态构建查询条件

在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法. 本文中的例子最终实现的都是同一个功能,从Northwind数据库Customers表中搜索出CompanyName列带有keywords中任意元素的项.keywords是个字符串数组,该数组长度在编译时是不确定的.思路及方法说明写在代码注释中. 1.表达式树 1   public static IEnumerable<Customers> 

java-基础入门-泛型数组列表-解决运行时动态更改数组的问题

泛型数组列表,主要是为了解决运行时动态更改数组的问题 平常我们会定义一个部门里面的人员的一个数组, 但是在实际业务当中,这个数组的大小往往是不确定的, 如果定义过大,那么会浪费空间,定义过小,又不够用, 因为为了解决运行时动态更改数组的问题,我们提出下面的解决方案. package com.ray.object; import java.util.ArrayList; /** * 泛型数组列表 ,解决运行时动态更改数组的问题 * * @author ray * @since 2015-05-04