android 7.0 + 相机拍照 FileUriExposedException

来源:互联网 发布:tensorflow finetune 编辑:程序博客网 时间:2024/06/05 02:47

这个异常只会在Android 7.0 + 出现,当app使用file:// url 共享给其他app时, 会抛出这个异常。

因为在android 6.0 + 权限需要 在运行时候检查, 其他app 可能没有读写文件的权限, 所以google在7.0的时候加上了这个限制。

官方推荐使用 FileProvider 解决这个问题。 
下面我们来看看具体实现步骤。

在manifest.xml文件添加provider,相机,读写文件权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.CAMERA"/><application>   ...   <provider        android:name="android.support.v4.content.FileProvider"        android:authorities="com.example.android.fileprovider"        android:exported="false"        android:grantUriPermissions="true">        <meta-data            android:name="android.support.FILE_PROVIDER_PATHS"            android:resource="@xml/file_paths"></meta-data>    </provider>    ...</application>

注意 android:authorities 里面的值,在后面使用的getUriForFile(Context, String, File) 中, 第二个参数就是这个里面的值。

编写file_paths.xml

<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="http://schemas.android.com/apk/res/android">    <external-path name="my_images" path="images/"/></paths>
paths里面文件的一些可配置选项
<files-path name="name" path="path" /> //相当 Context.getFilesDir() + path, name是分享url的一部分<cache-path name="name" path="path" /> //getCacheDir()<external-path name="name" path="path" /> //Environment.getExternalStorageDirectory()<external-files-path name="name" path="path" />//getExternalFilesDir(String) Context.getExternalFilesDir(null)<external-cache-path name="name" path="path" /> //Context.getExternalCacheDir()     

编写相机获取图片activity : FileProviderActivity

package eebochina.com.testtechniques.fileProvider;import android.Manifest;import android.app.Activity;import android.content.ClipData;import android.content.ContentResolver;import android.content.Intent;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.graphics.BitmapFactory;import android.net.Uri;import android.os.Build;import android.os.Environment;import android.os.ParcelFileDescriptor;import android.provider.MediaStore;import android.support.v4.content.ContextCompat;import android.support.v4.content.FileProvider;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast;import java.io.File;import java.io.FileDescriptor;import java.io.FileNotFoundException;import java.util.List;import eebochina.com.testtechniques.R;public class FileProviderActivity extends AppCompatActivity {    private Button mButton;    private ImageView mImageView;    private Uri contentUri;    private File newFile;    private Activity activity;    private final int NEED_CAMERA = 200;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_file_provider);        activity = this;        mButton = (Button) findViewById(R.id.file_btn);        mImageView = (ImageView) findViewById(R.id.file_show);        mButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //检测是否有相机和读写文件权限                if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)                        != PackageManager.PERMISSION_GRANTED                        || ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)                        != PackageManager.PERMISSION_GRANTED) {                    activity.requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, NEED_CAMERA);                } else {                    startCamera();                }            }        });    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions,                                           int[] grantResults) {        switch (requestCode) {            case NEED_CAMERA:                // 如果权限被拒绝,grantResults 为空                if (grantResults.length > 0                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    startCamera();                } else {                    Toast.makeText(activity, "改功能需要相机和读写文件权限", Toast.LENGTH_SHORT).show();                }                break;        }    }    /**     * 打开相机获取图片     */    private void startCamera() {        File imagePath = new File(Environment.getExternalStorageDirectory(), "images");        if (!imagePath.exists()) imagePath.mkdirs();        newFile = new File(imagePath, "default_image.jpg");        //第二参数是在manifest.xml定义 provider的authorities属性        contentUri = FileProvider.getUriForFile(this, "com.example.android.fileprovider", newFile);        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        //兼容版本处理,因为 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 只在5.0以上的版本有效        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {            ClipData clip =                    ClipData.newUri(getContentResolver(), "A photo", contentUri);            intent.setClipData(clip);            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);        } else {            List<ResolveInfo> resInfoList =                    getPackageManager()                            .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);            for (ResolveInfo resolveInfo : resInfoList) {                String packageName = resolveInfo.activityInfo.packageName;                grantUriPermission(packageName, contentUri,                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION);            }        }        intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);        startActivityForResult(intent, 1000);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (resultCode == RESULT_OK) {            ContentResolver contentProvider = getContentResolver();            ParcelFileDescriptor mInputPFD;            try {                //获取contentProvider图片                mInputPFD = contentProvider.openFileDescriptor(contentUri, "r");                FileDescriptor fileDescriptor = mInputPFD.getFileDescriptor();                mImageView.setImageBitmap(BitmapFactory.decodeFileDescriptor(fileDescriptor));            } catch (FileNotFoundException e) {                e.printStackTrace();            }        }    }}


0 0
原创粉丝点击