Android 相机意图 FileUriExposedException for SDK >= 24

Posted

技术标签:

【中文标题】Android 相机意图 FileUriExposedException for SDK >= 24【英文标题】:Android camera intent FileUriExposedException for SDK >= 24 【发布时间】:2017-04-29 22:03:08 【问题描述】:

我使用此代码从相机获取图片并将其放在 imageview 上:

  private void openCamera()

    mMediaUri =getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

    Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    photoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
    startActivityForResult(photoIntent, REQUEST_TAKE_PHOTO);
   // dialog.dismiss();





private Uri getOutputMediaFileUri(int mediaTypeImage)

    //check for external storage
    if(isExternalStorageAvaiable())
    
        File mediaStorageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

        String fileName = "";
        String fileType = "";
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());

        fileName = "IMG_"+timeStamp;
        fileType = ".jpg";

        File mediaFile;
        try
        
            mediaFile = File.createTempFile(fileName,fileType,mediaStorageDir);
            Log.i("st","File: "+Uri.fromFile(mediaFile));
        
        catch (IOException e)
        
            e.printStackTrace();
            Log.i("St","Error creating file: " + mediaStorageDir.getAbsolutePath() +fileName +fileType);
            return null;
        
        return Uri.fromFile(mediaFile);
    
    //something went wrong
    return null;



private boolean isExternalStorageAvaiable()

    String state = Environment.getExternalStorageState();

    if(Environment.MEDIA_MOUNTED.equals(state))
    
        return true;
    
    else
    
        return false;
    


 public void onActivityResult(int requestCode, int resultCode, Intent data)

    super.onActivityResult(requestCode, resultCode, data);

    if(resultCode == DIALOG_CODE)
    
        String s = data.getStringExtra("choose");

        if(s.equals(getString(R.string.takephoto)))
        
          openCamera();
        
        else if(s.equals(getString(R.string.library)))
        
         // openGallery();
        
    
    else if(resultCode == RESULT_OK)
    
        if (requestCode == REQUEST_TAKE_PHOTO || requestCode == REQUEST_PICK_PHOTO) //dalla fotocamera
        
            if (data != null)  //caso galleria
            
                mMediaUri = data.getData();
            


            Picasso.with(getActivity()).load(mMediaUri).resize(1280, 1280).centerCrop().into(photo, new Callback()
            
                public void onSuccess()
                


                

                @Override
                public void onError() 

                
            );
        
    

在 Marshmallow 中可以正常工作,但在 Nougat 中出现此错误:

E/androidRuntime: FATAL EXCEPTION: main
              PID: 15471
              android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.plen.myapp/files/Pictures/IMG_20161214_1516561294620205.jpg exposed beyond app through ClipData.Item.getUri()
                  at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
                  at android.net.Uri.checkFileUriExposed(Uri.java:2346)
                  at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832)
                  at android.content.Intent.prepareToLeaveProcess(Intent.java:8925)
                  at android.content.Intent.prepareToLeaveProcess(Intent.java:8910)
                  at android.app.Instrumentation.execStartActivity(Instrumentation.java:1519)
                  at android.app.Activity.startActivityForResult(Activity.java:4224)
                  at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
                  at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:77)
                  at android.support.v4.app.ActivityCompatJB.startActivityForResult(ActivityCompatJB.java:26)
                  at android.support.v4.app.ActivityCompat.startActivityForResult(ActivityCompat.java:146)
                  at android.support.v4.app.FragmentActivity.startActivityFromFragment(FragmentActivity.java:937)
                  at android.support.v4.app.FragmentActivity$HostCallbacks.onStartActivityFromFragment(FragmentActivity.java:1046)
                  at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:956)
                  at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:945)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.openCamera(AddAircraftFirstPartFragment.java:263)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.askReadStorage(AddAircraftFirstPartFragment.java:338)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.askWriteStorage(AddAircraftFirstPartFragment.java:355)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.loadNewPhoto(AddAircraftFirstPartFragment.java:159)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.access$000(AddAircraftFirstPartFragment.java:48)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment$1.onClick(AddAircraftFirstPartFragment.java:75)
                  at android.view.View.performClick(View.java:5609)
                  at android.view.View$PerformClick.run(View.java:22266)
                  at android.os.Handler.handleCallback(Handler.java:751)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:154)
                  at android.app.ActivityThread.main(ActivityThread.java:6077)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

我该如何解决这个错误?我已经搜索了解决方案,但没有一个有效。

谢谢

【问题讨论】:

***.com/questions/38200282/…(另见此示例项目:github.com/commonsguy/cw-omnibus/tree/master/Camera/…) @CommonsWare 但如果我使用它,它也适用于果冻豆?或者我需要为以前版本的 Android 使用其他代码? "但是如果我使用它,它也适用于 Jelly Bean?" -- 如果“this”是FileProvider,则问题不在于Android OS版本,而在于用户的相机应用是否支持content作为UriUri的方案。有些会,有些不会。如果“this”是StrictMode 方法,那么所有版本的Android 都可以使用AFAIK,因为它会恢复FileUriExposedException 更改并允许您再次使用file 方案。 【参考方案1】:

代替return Uri.fromFile(mediaFile);

return FileProvider.getUriForFile(MainActivity.this,
    BuildConfig.APPLICATION_ID + ".provider",
    mediaFile);

这需要您将提供程序添加到AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
    ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="$applicationId.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
</application>

对于 AndroidX,请使用 androidx.core.content.FileProvider

然后在res文件夹下的xml文件夹中创建一个provider_paths.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

阅读更多:Full article

【讨论】:

官方文档 - developer.android.com/training/secure-file-sharing/…【参考方案2】:

它可以像下面这样简单地完成。 将这两行放在您的活动的 onCreate 中。

StrictMode.VmPolicy.Builder newbuilder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(newbuilder.build());

URI 暴露将被 Vm 忽略 我解决了我的问题。

【讨论】:

这似乎关闭了很多东西 它将完美运行。我没有发现任何新错误或此代码出现故障。 是的,你是对的。有用。看起来您正在安装一个未配置的策略对象。但它有效? 非常感谢。这对我有用。

以上是关于Android 相机意图 FileUriExposedException for SDK >= 24的主要内容,如果未能解决你的问题,请参考以下文章

Android - 相机意图,返回空结果

Android:调用相机意图后活动被破坏

Android:调用相机意图后活动被破坏

如何在 Android 相机上使用意图添加功能裁剪图像?

Android 10 中的相机意图权限

android中相机捕获的隐式意图