公司的某个项目中有调用摄像头拍照的功能,在开发过程中使用了类似小米mix2(Miui12.0.1基于Android9) 华为Nova2s(EMUI9.1.0基于Android9)中测试均无问题,但是好巧不巧吧领导在使用时点击对应功能按钮无反应(无法调用摄像头),后面拿到领导的手机发现有钱人用的那是高端大气的Sony并且系统是Android11.

  • 实现代码
<!--相机权限-->
<uses-permission android:name="android.permission.CAMERA" />
<!--读写文件权限-->
<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" /> <!-- 用于写入缓存数据到扩展存储卡 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
private var currentPhotoPath= ""     // 保存文件路径
private lateinit var photoUri: Uri  // 保存照片的uri

@SuppressLint("QueryPermissionsNeeded")
private fun takePicture() {
  Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
     takePictureIntent.resolveActivity(packageManager)?.also {
        val photoFile: File = createImageFile()
         photoFile.also {
            photoUri = FileProvider.getUriForFile(            // 根据文件创建uri
               this,
               "com.imowfms.uploadcertinfo.fileprovider",        // 在清单文件声明的权限全称
               it
             )
         takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)    // 传入目标uri
         startActivityForResult(takePictureIntent,CAMERA_RESULT_CODE)
         }
        }
       }
    }

private fun createImageFile(): File {
    val storageDir: File? = this.filesDir                // 目标存储在 files 文件夹内
    return File.createTempFile(
        "JPEG_${System.currentTimeMillis()}_",         // 文件名
        ".jpg",                                     // 后缀
        storageDir                                     // 存储文件夹
    ).apply {
        currentPhotoPath = absolutePath
    }
}

@SuppressLint("SetTextI18n")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        CAMERA_RESULT_CODE -> {
            val imageFile = File(currentPhotoPath)
            if (resultCode == RESULT_OK){
                // 判断文件是否存在
                // 不存在则提示
                if (!imageFile.exists()){
                    Toast.makeText(this, "图片文件不存在", Toast.LENGTH_SHORT).show()
                    return
                }
                // 存在则转为bitmap显示
                val photo = imageSizeCompress(photoUri)
                // println("bitmap大小: ${photo!!.byteCount}")
                certPicture.setImageBitmap(photo) // 这里是显示图片,控件按照自己的来
            } else if (resultCode == RESULT_CANCELED){ // 拒绝了
                // 未拍摄则提示
                if (FileSizeUtil.getFileSize(imageFile) == 0.toLong()){
                    Toast.makeText(this, "图片未拍摄", Toast.LENGTH_SHORT).show()
                    // 删除本地空文件
                    imageFile.delete()
                    certPicture.isVisible =  false
                    return
                }
            }
        }
    }
}
  • 兼容Android 11 需要在权限文件增加
<!--android11无此代码则无法调用摄像头 -->
<queries>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
</queries>