Android7.0权限适配

权限变化

Android从6.0开始对隐私的保护越来越注重,从6.0动态申请权限到Android7.0的“私有目录被限制访问”,虽然对用户保护的力度加大了,但是对于我们开发者来说,之前我们写的代码必须要适配到7.0了,很讨厌哦~下面我们具体讲一下关于7.0方方面面的变化

拍照

 // 请求加载系统照相机
    private static final int TAKE_PICTURE = 0x000001;

// 跳转到系统照相机
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //判断是否有系统相机
        if(cameraIntent.resolveActivity(getActivity().getPackageManager()) != null){
            // 设置系统相机拍照后的输出路径
            // 创建临时文件
            mTmpFile = HexAlbumFileUtils.createTmpFile(getActivity());
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){//判断当前版本号
                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
                startActivityForResult(cameraIntent, TAKE_PICTURE);
            }else {
                ContentValues contentValues = new ContentValues();
                contentValues.put(MediaStore.Images.Media.DATA, mTmpFile.getAbsolutePath());
                Uri uri = getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            }
            startActivityForResult(cameraIntent, TAKE_PICTURE);

        }else{
            Toast.makeText(getActivity(), R.string.hexalbum_msg_no_camera, Toast.LENGTH_SHORT).show();
        }

创建文件

public static File createTmpFile(Context context){

        String state = Environment.getExternalStorageState();
        if(state.equals(Environment.MEDIA_MOUNTED)){
            // 已挂载
            File pic = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
            String fileName = "multi_image_"+timeStamp+"";
            File tmpFile = new File(pic, fileName+".jpg");
            return tmpFile;
        }else{
            File cacheDir = context.getCacheDir();
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
            String fileName = "multi_image_"+timeStamp+"";
            File tmpFile = new File(cacheDir, fileName+".jpg");
            return tmpFile;
        }

    }

在7.0版本以前,我们打开相机保存图片通常方法为:

 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
 startActivityForResult(cameraIntent, TAKE_PICTURE);

但7.0版本后,由于Android7.0执行了“StrictMode API ”的原因,” StrictMode API 政策” 是指禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常。我们可以用下面的方法来实现

ContentValues contentValues = new ContentValues();
                contentValues.put(MediaStore.Images.Media.DATA, mTmpFile.getAbsolutePath());
                Uri uri = getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

我们也可以通过使用FileProvider来实现打开相机保存图片

第一步:创建FileProvider
在清单文件创建:

 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.hexfuture.hexteacher.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">

            <!-- 元数据 -->
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。

第二步:指定共享的目录:

在res/xml文件下创建xml文件名字无所谓 (名字可以随便起,只要和在manifest注册的provider所引用的resource保持一致即可))file_paths.xml:

<resources>
    <paths>
        <external-path path="" name="camera_photos" />
    </paths>
</resources>

上述代码中path=”“,是有特殊意义的,它代码根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了,如果你将path设为path=”pictures”,
那么它代表着共享根目录下的pictures目录(/storage/emulated/0/pictures)任何一个文件,如果你向其它应用分享pictures目录范围之外的文件是不行的。

第三步:使用FileProvider

Uri imageUri = FileProvider.getUriForFile(context, "com.hexfuture.hexteacher.fileprovider", mTmpFile);//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,TAKE_PICTURE);

这样我们就可以在7.0打开相机保存图片了,但sdk6.0以后,我们都需要动态申请权限.

裁剪图片

在7.0之前,我们调用系统裁剪:

Uri outputUri = Uri.fromFile(mTmpFile);
Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

但在7.0以后我们需要使用fileprovide来进行裁剪图片

Uri outputUri = FileProvider.getUriForFile(context, "com.hexfuture.hexteacher.fileprovider",mTmpFile);
Uri imageUri=FileProvider.getUriForFile(context, "com.hexfuture.hexteacher.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);

解析URI

在这我想讲一下URI的改变
4.4之前
Uri : content://media/extenral/images/media/17766
4.4及以后
Uri : content://com.android.providers.media.documents/document/image%3A82482

URI转path路径

 public static String getRealFilePath(final Context context, final Uri uri ) {
        if ( null == uri ) return null;
        final String scheme = uri.getScheme();
        String data = null;
        if ( scheme == null )
            data = uri.getPath();
        else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) {
            data = uri.getPath();
        } else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) {
            //判断URI形式是4.4版本之前还是4.4版本及以后的
            if (DocumentsContract.isDocumentUri(context, uri)) {//4.4及以后解析
                String wholeID = DocumentsContract.getDocumentId(uri);
                // 使用':'分割
                String id = wholeID.split(":")[1];
                String[] projection = { MediaStore.Images.Media.DATA };
                String selection = MediaStore.Images.Media._ID + "=?";
                String[] selectionArgs = { id };

                Cursor cursor = context.getContentResolver().query(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
                        selection, selectionArgs, null);
                int columnIndex = cursor.getColumnIndex(projection[0]);
                if (cursor.moveToFirst()) {
                    data = cursor.getString(columnIndex);
                }
                cursor.close();
            }else {//4.4之前解析
                Cursor cursor = context.getContentResolver().query( uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null );
                if ( null != cursor ) {
                    if ( cursor.moveToFirst() ) {
                        int index = cursor.getColumnIndex( MediaStore.Images.ImageColumns.DATA );
                        if ( index > -1 ) {
                            data = cursor.getString( index );
                        }
                    }
                    cursor.close();
                }
            }

        }
        return data;
    }

如果有什么问题,就可以问我

猜你喜欢

转载自blog.csdn.net/xuhang1993/article/details/73253081