Android-摄像头全解析之-启用系统拍照应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010782846/article/details/90241700

前言

原生Android 手机或平板有一个拍照APP,当我需要更少的步骤启用一个拍照功能的时候可以使用隐性跳转和系统的Android 拍照APP进行交互。

调用Android的原生相机APP流程

  • 在注册清单中限制只有具备拍照功能的Android系统才能安装我们的应用
  • 在注册清单中填写相应需要的权限
  • Android6.0以上需要添加运行时权限
  • 启动Android 系统拍照应用
  • 获取到缩略图或者自定义路径的全尺寸图片
  • 得到的全尺寸图片进行裁剪
  • 把缩略图存储到本地文件或者上传至图片服务器(Android7.0 以上需要关注共享文件的问题)
  • 把图片文件更新到图库

判断是否具备拍照功能

要判断系统是否具备拍照功能,可以使用两种方法来判断,一种是通过在注册清单中特征判断是否支持相机、另一种是运行时判断特性。
方法一:注册清单中检验特征

<manifest ... >
    <uses-feature android:name="android.hardware.camera"
                  android:required="true" />
    ...
</manifest>

方法二:运行时检验特征

Context.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)

方法一和方法二的差异在于,假设使用方法一,那么我们的应用程序无法安装在不支持相机功能的系统中,二方法二可以,方法二主要是在运行时判断以便于屏蔽单个拍照功能的使用而不影响应用程序的其他功能。

拍照应用所需权限

拍照的时候我们需要获取到使用摄像机的权限,假设我们需要把拍摄的照片保存到本地外存中,还需要添加外存的写入权限。

	<!--摄像机设备权限-->
    <uses-permission android:name="android.permission.CAMERA"/>
    <!--写入外存权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

兼容6.0Android设备的运行时权限

自从Android 6.0之后Android对权限进行了危险权限隔离,部分权限需要在运行时请求才能使用,摄像头权限和写入权限都是运行时权限,我们需要对其进行兼容:
检查和获取权限:

if (PermissionUtils.checkSelfPermission(this,permissions)){
        //权限已存在,直接打开摄像头
        takePicture()
 else{
         //未获取到权限,运行时请求获取
         PermissionUtils.requestPermission(this,permissions,REQUST_CODE_PERSSION)
 }

请求权限允许后进行调起拍照应用:

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        var isSuccess=true
        when (requestCode) {
            REQUST_CODE_PERSSION -> {
            	//遍历查询是否有未授权成功的权限
                for (result in grantResults){
                    if (result!=PackageManager.PERMISSION_GRANTED){
                        isSuccess=false
                        break
                    }
                }
                if (isSuccess) {
                    // 获取到权限 ,进行相关操作
                    takePicture()
                } else {
                    //没有获取到权限,进行提示
                }
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

启动系统拍照应用

启动系统应用可以选择自定义文件路径或者使用默认的,假设直接使用默认的图片属于缩略图,如果选择了自定义文件路径得到的就是全尺寸大图,我们需要进行裁剪处理。
默认返回缩略图:
启动拍照

fun takePicture() {
        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureInetnt ->
            takePictureInetnt.resolveActivity(packageManager)?.also {
                startActivityForResult(takePictureInetnt, REQUEST_IMAGE_CAPTURE)
            }
        }
    }

获取缩略图展示

扫描二维码关注公众号,回复: 6752017 查看本文章
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

        if (requestCode== REQUEST_IMAGE_CAPTURE&&resultCode== Activity.RESULT_OK){
            // 处理返回的缩略图
            val thumbnailBitmap=data?.extras?.get("data") as Bitmap
            iv_image.setImageBitmap(thumbnailBitmap)
        }
    }

data?.extras?.get(“data”) 会返回一个Bitmap对象的缩略图,可以直接展示,不存入任何存储设备。
自定义图片文件路径:

手机存储文件的方式分为内存存储和外存存储,使用内存存储不需要添加权限,如果写入外存存储我们就需要添加权限,在使用外存还是内存我列出几点考虑:

  • 应用删除也会导致内存数据被清空,我们可能并不希望应用删除就导致图片被清空
  • 图片对于APP来说并非私密数据,而属于整个系统级别的私密性,可供其他APP分享
  • 图片可能需要放在图库文件夹中,以方便预览

基于以上三点考虑使用外部存储,当然因为图片属于应用级别的私密信息,可考虑使用getExternalFilesDir(),如果使用外部存储,请记得加入写入权限

除了存储的问题,我们还需要考虑到Android7.0以上为了私密性对应用与应用间通讯添加的共享文件限制,我们必须设置可供共享的文件夹,以使得系统级拍照APP能够访问到我们应用程序所提供的路径文件(共享文件的详情我这里就不说了,有兴趣的朋友可以查资料):
为了自定义路径,我们启动系统拍照应用时,我们需要做如下修改:

    fun takePicture() {

        //自定义存储图片的路径
        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureInetnt ->
            takePictureInetnt.resolveActivity(packageManager)?.also {
                val photoFile=try {
                    createImageFiles()
                }catch (ex:IOException){
                    null
                }
                Log.d("test",photoFile?.toString())
                photoFile?.also {
                    val photoURI=FileProvider.getUriForFile(this,"com.lyc.indonesia.mediademo",it)
                    takePictureInetnt.putExtra(MediaStore.EXTRA_OUTPUT,photoURI)
                    startActivityForResult(takePictureInetnt,REQUEST_IMAGE_CAPTURE)
                }

            }
        }
    }

拍摄成功后,需要做如下处理:

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

        if (requestCode== REQUEST_IMAGE_CAPTURE&&resultCode== Activity.RESULT_OK){

            //拍照完成,并保存到currentPhotoPath文件中

            val bitmap=BitmapFactory.decodeFile(currentPhotoPath)
            Log.d("test","文件大小:${FileSizeUtil.getAutoFileOrFilesSize(currentPhotoPath)}")
            iv_image.setImageBitmap(bitmap)
            galleryAddPic()
        }
    }

我们使用图片进行显示后发现,这次获得的图片比之前的大,计算文件大小后可以得出图片文件多达几M,然而一般我们的应用程序不需要这么高质量的全尺寸图片,所以自定义图片路径的程序我们需要对获得的全尺寸进行裁剪,因为本章终点在于拍照功能,我们就不写对图片如何进行裁剪了,因为剪裁的方式很多种,需要对实际情况进行分析,选择一个最优的方案。

更新图库

更新图库需要给图库发送一个广播,广播代码如下:

    private fun  galleryAddPic(){
        Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaIntent->
            val f=File(currentPhotoPath)
            Log.d("test","更新图库 ${f.absolutePath}")
            mediaIntent.data= Uri.fromFile(f)
            sendBroadcast(mediaIntent)
        }
    }

猜你喜欢

转载自blog.csdn.net/u010782846/article/details/90241700