『Android开源框架』用XXPermissions请求相机权限实现手电筒

简介: 今天实现一个小功能,调用相机权限实现手电筒,顺带学习一下CameraManager系统服务和两个好用的权限请求框架,主要推荐使用XXPermissions


今天实现一个小功能,调用相机权限实现手电筒,顺带学习一下CameraManager系统服务和两个好用的权限请求框架,主要推荐使用XXPermissions

1.权限设置

官方权限概述

manifest.xml中引入相机权限

<!--引入相机权限-->

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

网络异常,图片无法展示
|

2.xml布局文件

网络异常,图片无法展示
|

<?xmlversion="1.0" encoding="utf-8"?>

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"

   xmlns:app="http://schemas.android.com/apk/res-auto"

   xmlns:tools="http://schemas.android.com/tools"

   android:layout_width="match_parent"

   android:layout_height="match_parent"

   tools:context=".MainActivity">

 

   <ImageView

       android:id="@+id/flashBtn"

       android:layout_width="wrap_content"

       android:layout_height="match_parent"

       android:scaleType="centerCrop"

       android:src="@drawable/off"

       app:layout_constraintBottom_toBottomOf="parent"

       app:layout_constraintLeft_toLeftOf="parent"

       app:layout_constraintRight_toRightOf="parent"

       app:layout_constraintTop_toTopOf="parent"/>

 

</RelativeLayout>

3.前备知识

CameraManager官方文档

CameraManager 是系统服务之一,专门用于 检测打开相机,以及 获取相机设备特性

  1. String[] getCameraIdList()获取当前连接的相机设备列表,这个 id 通常都是从 0 开始并依次递增的。

对于一般的手机而言:

后置摄像头一般为 CameraCharacteristics.LENS_FACING_FRONT,常量值为 “0”;前置摄像头一般为 CameraCharacteristics.LENS_FACING_BACK,常量值为 “1”

2.  void setTorchMode(String cameraId, boolean enabled)

打开和关闭指定相机设备的闪光灯功能。

4.XXPermissions框架(推荐)

XXPermissions框架官方文档

4.1框架亮点

  • 首款适配 Android 13 的权限请求框架
  • 首款也是唯一一款适配所有 Android 版本的权限请求框架
  • 简洁易用:采用链式调用的方式,使用只需一句代码
  • 体积感人:功能在同类框架中是最全的,但是框架体积是垫底的
  • 适配极端情况:无论在多么极端恶劣的环境下申请权限,框架依然坚挺
  • 向下兼容属性:新权限在旧系统可以正常申请,框架会做自动适配,无需调用者适配
  • 自动检测错误:如果出现错误框架会主动抛出异常给调用者(仅在 Debug 下判断,把 Bug 扼杀在摇篮中)

4.2集成步骤

  • 如果你的项目 Gradle 配置是在 7.0 以下,需要在 build.gradle 文件中加入

allprojects {

   repositories {

       // JitPack 远程仓库:https://jitpack.io

       maven { url'https://jitpack.io' }

   }

}

  • 如果你的 Gradle 配置是 7.0 及以上,则需要在 settings.gradle 文件中加入

dependencyResolutionManagement {

   repositories {

       // JitPack 远程仓库:https://jitpack.io

       maven { url'https://jitpack.io' }

   }

}

  • 配置完远程仓库后,在项目 app 模块下的 build.gradle 文件中加入远程依赖

android {

   // 支持 JDK 1.8

   compileOptions {

       targetCompatibilityJavaVersion.VERSION_1_8

       sourceCompatibilityJavaVersion.VERSION_1_8

   }

}

 

dependencies {

   // 权限请求框架:https://github.com/getActivity/XXPermissions

   implementation'com.github.getActivity:XXPermissions:16.0'

}

  • 如果项目是基于 AndroidX 包,请在项目 gradle.properties 文件中加入

#表示将第三方库迁移到AndroidX

android.enableJetifier=true

  • 如果项目是基于 Support 包则不需要加入此配置

4.3请求权限

XXPermissions.with(this)

       // 申请单个权限

       .permission(Permission.RECORD_AUDIO)

       // 申请多个权限

       .permission(Permission.Group.CALENDAR)

       // 设置权限请求拦截器(局部设置)

       //.interceptor(new PermissionInterceptor())

       // 设置不触发错误检测机制(局部设置)

       //.unchecked()

       .request(newOnPermissionCallback() {

 

           @Override

           publicvoidonGranted(List<String>permissions, booleanall) {

               if (!all) {

                   toast("获取部分权限成功,但部分权限未正常授予");

                   return;

               }

               toast("获取录音和日历权限成功");

           }

 

           @Override

           publicvoidonDenied(List<String>permissions, booleannever) {

               if (never) {

                   toast("被永久拒绝授权,请手动授予录音和日历权限");

                   // 如果是被永久拒绝就跳转到应用权限系统设置页面

                   XXPermissions.startPermissionActivity(context, permissions);

               } else {

                   toast("获取录音和日历权限失败");

               }

           }

       });

4.4框架其他API

// 判断一个或多个权限是否全部授予了

XXPermissions.isGranted(Contextcontext, String... permissions);

 

// 获取没有授予的权限

XXPermissions.getDenied(Contextcontext, String... permissions);

 

// 判断某个权限是否为特殊权限

XXPermissions.isSpecial(Stringpermission);

 

// 判断一个或多个权限是否被永久拒绝了

XXPermissions.isPermanentDenied(Activityactivity, String... permissions);

 

// 跳转到应用权限设置页

XXPermissions.startPermissionActivity(Contextcontext, String... permissions);

XXPermissions.startPermissionActivity(Activityactivity, String... permissions);

XXPermissions.startPermissionActivity(Activityactivity, String... permission, OnPermissionPageCallbackcallback);

XXPermissions.startPermissionActivity(Fragmentfragment, String... permissions);

XXPermissions.startPermissionActivity(Fragmentfragment, String... permissions, OnPermissionPageCallbackcallback);

 

// 设置不触发错误检测机制(全局设置)

XXPermissions.setCheckMode(false);

// 设置权限申请拦截器(全局设置)

XXPermissions.setInterceptor(newIPermissionInterceptor() {});

5.Dexter框架

Dexter框架官方文档

这个框架不再处于积极开发中,最新的一次的更新是在14个月前。

Dexter 是一个 Android 库,它简化了在运行时请求权限的过程。 Android Marshmallow 包含一项新功能,允许用户在运行应用程序时授予或拒绝权限,而不是在安装时授予所有权限。 这种方法让用户可以更好地控制应用程序,但需要开发人员添加大量代码来支持它。 Dexter 将您的权限代码从您的活动中释放出来,让您可以在任何您想要的地方编写该逻辑。

5.1引入依赖

将库包含在您的build.gradle

dependencies{

   implementation'com.karumi:dexter:6.2.3'

}

5.2单个权限

对于每个权限,注册一个PermissionListener实现以接收请求的状态:

Dexter.withContext(this)

    .withPermission(Manifest.permission.CAMERA)

    .withListener(newPermissionListener() {

        @OverridepublicvoidonPermissionGranted(PermissionGrantedResponseresponse) {/* ... */}

        @OverridepublicvoidonPermissionDenied(PermissionDeniedResponseresponse) {/* ... */}

        @OverridepublicvoidonPermissionRationaleShouldBeShown(PermissionRequestpermission, PermissionTokentoken) {/* ... */}

    }).check();

5.3多个权限

Dexter.withContext(this)

    .withPermissions(

        Manifest.permission.CAMERA,

        Manifest.permission.READ_CONTACTS,

        Manifest.permission.RECORD_AUDIO

    ).withListener(newMultiplePermissionsListener() {

        @OverridepublicvoidonPermissionsChecked(MultiplePermissionsReportreport) {/* ... */}

        @OverridepublicvoidonPermissionRationaleShouldBeShown(List<PermissionRequest>permissions, PermissionTokentoken) {/* ... */}

    }).check();

6.同类权限请求框架之间的对比

适配细节 XXPermissions AndPermission PermissionX AndroidUtilCode PermissionsDispatcher RxPermissions EasyPermissions
对应版本 16.0 2.0.3 1.6.4 1.31.0 4.9.2 0.12 3.0.0
issues 数
框架体积 51 KB 127 KB 90 KB 500 KB 99 KB 28 KB 48 KB
框架维护状态 维护中 停止维护 维护中 停止维护 维护中 停止维护 停止维护
闹钟提醒权限
所有文件管理权限
安装包权限
悬浮窗权限
系统设置权限
通知栏权限
通知栏监听权限
勿扰权限
忽略电池优化权限
查看应用使用情况权限
VPN 权限
Android 13 危险权限
Android 12 危险权限
Android 11 危险权限
Android 10 危险权限
Android 9.0 危险权限
Android 8.0 危险权限
新权限自动兼容旧设备
屏幕方向旋转场景适配
后台申请权限场景适配
Android 12 内存泄漏问题修复
错误检测机制

7.Dexter请求权限实现手电筒

使用这个框架的前提只需要在build.gradle中引入依赖即可

publicclassMainActivityextendsAppCompatActivity {

 

   ImageViewflashBtn;

   booleanstate;

   @Override

   protectedvoidonCreate(BundlesavedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       flashBtn=findViewById(R.id.flashBtn);

 

       Dexter.withContext(this)//指定页面

               .withPermission(Manifest.permission.CAMERA)//指定权限

               .withListener(newPermissionListener() {//创建监听

 

                   @Override

                   publicvoidonPermissionGranted(PermissionGrantedResponsepermissionGrantedResponse) {

                       //运行手电筒

                       runFlashlight();

 

                   }

 

                   //用户提示

                   @Override

                   publicvoidonPermissionDenied(PermissionDeniedResponsepermissionDeniedResponse) {

                       Toast.makeText(MainActivity.this,"Camera permission request",Toast.LENGTH_SHORT).show();

                   }

 

                   @Override

                   publicvoidonPermissionRationaleShouldBeShown(PermissionRequestpermissionRequest, PermissionTokenpermissionToken) {

 

                   }

               }).check();

   }

 

   privatevoidrunFlashlight() {

       flashBtn.setOnClickListener(newView.OnClickListener() {

           @Override

           publicvoidonClick(Viewview) {

               if(!state){

                   //设置相机功能管理

                   CameraManagercameraManager=(CameraManager) getSystemService(Context.CAMERA_SERVICE);

                   try {

                       //getCameraIdList()按标识符返回当前连接的相机设备列表,包括可能被其他相机 API 客户端使用的相机。

                       StringcameraId=cameraManager.getCameraIdList()[0];

                       //打开和关闭指定相机设备的闪光灯功能。

                       cameraManager.setTorchMode(cameraId,true);

                       //设置状态为true,打开

                       state=true;

                       //更改图片资源

                       flashBtn.setImageResource(R.drawable.on);

                   }catch (CameraAccessExceptione){

 

                   }

               }else{

                   //设置相机功能管理

                   CameraManagercameraManager=(CameraManager) getSystemService(Context.CAMERA_SERVICE);

                   try {

                       //getCameraIdList()按标识符返回当前连接的相机设备列表,包括可能被其他相机 API 客户端使用的相机。

                       StringcameraId=cameraManager.getCameraIdList()[0];

                       //打开和关闭指定相机设备的闪光灯功能。

                       cameraManager.setTorchMode(cameraId,false);

                       state=false;

                       flashBtn.setImageResource(R.drawable.off);

                   }catch (CameraAccessExceptione){

 

                   }

               }

 

           }

       });

   }

}

8.XXPermissions请求权限实现手电筒

  • 我的项目的 Gradle 配置是 7.0 及以上,所以我需要在 settings.gradle 文件中加入 maven { url 'https://jitpack.io' }
  • 并且我的项目是基于 AndroidX 包,需要在项目 gradle.properties 文件中加入android.enableJetifier = true
  • 最后在项目 app 模块下的 build.gradle 文件中加入远程依赖

publicclassMainActivityextendsAppCompatActivity {

 

   ImageViewflashBtn;

   booleanstate;

   @Override

   protectedvoidonCreate(BundlesavedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_main);

       flashBtn=findViewById(R.id.flashBtn);

 

       XXPermissions.with(this)

               // 申请单个权限(相机)

               .permission(Permission.CAMERA)

               // 申请多个权限(日历),要申请多个权限只需要把要申请的权限列出来即可

               //.permission(Permission.Group.CALENDAR)

               .request(newOnPermissionCallback() {

                   @Override

                   publicvoidonGranted(List<String>permissions, booleanall) {

                       if (!all) {

                           Toast.makeText(MainActivity.this,"获取部分权限成功,但部分权限未正常授予",Toast.LENGTH_SHORT).show();

                           return;

                       }

                       runFlashlight();

                       Toast.makeText(MainActivity.this,"获取相机权限成功",Toast.LENGTH_SHORT).show();

                   }

 

                   @Override

                   publicvoidonDenied(List<String>permissions, booleannever) {

                       if (never) {

                           Toast.makeText(MainActivity.this,"被永久拒绝授权,请手动授予相机权限",Toast.LENGTH_SHORT).show();

                           // 如果是被永久拒绝就跳转到应用权限系统设置页面

                           XXPermissions.startPermissionActivity(MainActivity.this, permissions);

                       } else {

                           Toast.makeText(MainActivity.this,"获取录音和日历权限失败",Toast.LENGTH_SHORT).show();

                       }

                   }

               });

 

   }

 

   privatevoidrunFlashlight() {

       flashBtn.setOnClickListener(newView.OnClickListener() {

           @Override

           publicvoidonClick(Viewview) {

               if(!state){

                   //设置相机功能管理

                   CameraManagercameraManager=(CameraManager) getSystemService(Context.CAMERA_SERVICE);

                   try {

                       //getCameraIdList()按标识符返回当前连接的相机设备列表,包括可能被其他相机 API 客户端使用的相机。

                       StringcameraId=cameraManager.getCameraIdList()[0];

                       //打开和关闭指定相机设备的闪光灯功能。

                       cameraManager.setTorchMode(cameraId,true);

                       //设置状态为true,打开

                       state=true;

                       //更改图片资源

                       flashBtn.setImageResource(R.drawable.on);

                   }catch (CameraAccessExceptione){

 

                   }

               }else{

                   //设置相机功能管理

                   CameraManagercameraManager=(CameraManager) getSystemService(Context.CAMERA_SERVICE);

                   try {

                       //getCameraIdList()按标识符返回当前连接的相机设备列表,包括可能被其他相机 API 客户端使用的相机。

                       StringcameraId=cameraManager.getCameraIdList()[0];

                       //打开和关闭指定相机设备的闪光灯功能。

                       cameraManager.setTorchMode(cameraId,false);

                       state=false;

                       flashBtn.setImageResource(R.drawable.off);

                   }catch (CameraAccessExceptione){

 

                   }

               }

 

           }

       });

   }

}

9.参考资料

Teacher.Hu(胡老师博客)Android 动态权限最全解析

[Teacher.Hu(胡老师博客)【Android】相对布局(RelativeLayout)最全解析

官方权限概述

运行时请求 Android 权限的 Android 库

Android Camera2 之 CameraManager 详解

Android Support 和 AndroidX


相关文章
|
25天前
|
API Android开发
57. 【Android教程】相机:Camera
57. 【Android教程】相机:Camera
17 0
|
1月前
|
安全 Android开发
Android之OKHttp基本使用和OKHttp发送https请求安全认证
Android之OKHttp基本使用和OKHttp发送https请求安全认证
68 0
|
1月前
|
Java Shell Android开发
android 权限申请
android 权限申请
56 5
|
1月前
|
XML API 数据库
Android权限
Android权限 【5月更文挑战第3天】
33 0
|
1月前
|
API Apache Android开发
对于Android的http请求的容错管理
对于Android的http请求的容错管理
15 1
|
1月前
|
Java Android开发
Android12 双击power键启动相机源码解析
Android12 双击power键启动相机源码解析
63 0
|
1月前
|
Android开发 开发者
Android打开开发者权限
Android打开开发者权限
22 0
|
1月前
|
Android开发
Android 9.0中sdcard 的权限和挂载问题
Android 9.0中sdcard 的权限和挂载问题
21 0
|
1月前
|
Android开发
Android修改默认system/bin/下可执行程序拥有者和权限,使用实例,只有root和系统app权限才能执行某个命令。
Android修改默认system/bin/下可执行程序拥有者和权限,使用实例,只有root和系统app权限才能执行某个命令。 【5月更文挑战第2天】
38 0
|
1月前
|
Android开发
android 12 U盘 /mnt/media_rw 下读取文件异常 没有权限
android 12 U盘 /mnt/media_rw 下读取文件异常 没有权限
78 0