美文网首页安卓开发相关AndroidAndroid
Android 调用相机拍照,适配到Android 10

Android 调用相机拍照,适配到Android 10

作者: donkingliang | 来源:发表于2019-09-26 19:10 被阅读0次

    今天写的博客是关于Android调用手机相机拍照并显示图片。这是一个很常用的功能,并且这个功能在Android6.0、7.0、10.0等版本上实现都有所不同,需要对Android各个版本进行兼容适配,目前最新的Android版本是Android 10,所以这篇博客适配到Android 10。我自己也写了个demo,方便以后要使用的时候直接拿来。

    调用相机,首先需要申请相机权限。

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

    android 6.0以后,相机权限需要动态申请。

       // 申请相机权限的requestCode
       private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012;
    
       /**
        * 检查权限并拍照。
        * 调用相机前先检查权限。
        */
       private void checkPermissionAndCamera() {
           int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(),
                   Manifest.permission.CAMERA);
           if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) {
               //有调起相机拍照。
               openCamera();
           } else {
               //没有权限,申请权限。
               ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},
                       PERMISSION_CAMERA_REQUEST_CODE);
           }
       }
    
       /**
        * 处理权限申请的回调。
        */
       @Override
       public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
           if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
               if (grantResults.length > 0
                       && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                   //允许权限,有调起相机拍照。
                   openCamera();
               } else {
                   //拒绝权限,弹出提示框。
                   Toast.makeText(this,"拍照权限被拒绝",Toast.LENGTH_LONG).show();
               }
           }
       }
    

    申请权限后,就可以调起相机拍照了。调用相机只需要调用startActivityForResult传一个Intent就可以了,但是这个Intent需要传递一个uri,用于保存拍出来的图片,创建这个uri时,各个Android版本有所不同,需要进行版本兼容。

       //用于保存拍照图片的uri
        private Uri mCameraUri;
    
        // 用于保存图片的文件路径,Android 10以下使用图片路径访问图片
        private String mCameraImagePath;
    
        // 是否是Android 10以上手机
        private boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
    
        /**
         * 调起相机拍照
         */
        private void openCamera() {
            Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            // 判断是否有相机
            if (captureIntent.resolveActivity(getPackageManager()) != null) {
                File photoFile = null;
                Uri photoUri = null;
    
                if (isAndroidQ) {
                    // 适配android 10
                    photoUri = createImageUri();
                } else {
                    try {
                        photoFile = createImageFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                    if (photoFile != null) {
                        mCameraImagePath = photoFile.getAbsolutePath();
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            //适配Android 7.0文件权限,通过FileProvider创建一个content类型的Uri
                            photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                        } else {
                            photoUri = Uri.fromFile(photoFile);
                        }
                    }
                }
    
                mCameraUri = photoUri;
                if (photoUri != null) {
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                    captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    startActivityForResult(captureIntent, CAMERA_REQUEST_CODE);
                }
            }
        }
    
        /**
         * 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法
         */
        private Uri createImageUri() {
            String status = Environment.getExternalStorageState();
            // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
            if (status.equals(Environment.MEDIA_MOUNTED)) {
               return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
            } else {
                return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
            }
        }
    
        /**
         * 创建保存图片的文件
         */
        private File createImageFile() throws IOException {
            String imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            if (!storageDir.exists()) {
                storageDir.mkdir();
            }
            File tempFile = new File(storageDir, imageName);
            if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) {
                return null;
            }
            return tempFile;
        }
    

    接收拍照结果和显示图片

        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == CAMERA_REQUEST_CODE) {
                if (resultCode == RESULT_OK) {
                    if (isAndroidQ) {
                        // Android 10 使用图片uri加载
                        ivPhoto.setImageURI(mCameraUri);
                    } else {
                        // 使用图片路径加载
                        ivPhoto.setImageBitmap(BitmapFactory.decodeFile(mCameraImagePath));
                    }
                } else {
                    Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
                }
            }
        }
    

    这两需要说明一下,Android 10由于文件权限的关系,显示手机储存卡里的图片不能直接使用图片路径,需要使用图片uri加载。关于在Android 10显示手机图片的适配可以看我的另外一篇博客:Android 10加载手机本地图片

    另外虽然我在这篇博客里对Android 10和10以下的手机使用了不同的方式创建uri 和加载图片,但其实Android 10创建uri的方式和使用uri加载图片的方式在10以下的手机是同样适用的。

    android 7.0需要配置文件共享。

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    

    在res目录下创建文件夹xml ,放置一个文件file_paths.xml(文件名可以随便取),配置需要共享的文件目录,也就是拍照图片保存的目录。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <paths>
            <!-- 这个是保存拍照图片的路径,必须配置。 -->
            <external-files-path
                name="images"
                path="Pictures" />
        </paths>
    </resources>
    

    如果想把图片放在手机的共享储存区,比如Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)文件夹下,还需要申请文件读写权限。

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

    文件读写权限同样需要动态申请,申请权限的方式跟上面申请相机权限一样,这里就不再重复了。

    完整的demo请看我的Github

    相关文章

      网友评论

        本文标题:Android 调用相机拍照,适配到Android 10

        本文链接:https://www.haomeiwen.com/subject/lbwcuctx.html