2015-09-17 11 views
22

L'eccezione è:quando prende la foto ottenere - java.lang.Throwable: file: // Uri esposta attraverso ClipData.Item.getUri()

file:// Uri exposed through ClipData.Item.getUri() 
java.lang.Throwable: file:// Uri exposed through ClipData.Item.getUri() 
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1618) 
    at android.net.Uri.checkFileUriExposed(Uri.java:2341) 
    at android.content.ClipData.prepareToLeaveProcess(ClipData.java:808) 
    at android.content.Intent.prepareToLeaveProcess(Intent.java:7926) 
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1506) 
    at android.app.Activity.startActivityForResult(Activity.java:3832) 
    at android.app.Activity.startActivityForResult(Activity.java:3783) 
    at android.support.v4.app.FragmentActivity.startActivityFromFragment(Unknown Source) 
    at android.support.v4.app.Fragment.startActivityForResult(Unknown Source) 
    at me.chunyu.ChunyuDoctor.Utility.w.takePhoto(Unknown Source) 
    at me.chunyu.ChunyuDoctor.Dialog.ChoosePhotoDialogFragment.takePhoto(Unknown Source) 
    at me.chunyu.ChunyuDoctor.Dialog.ChoosePhotoDialogFragment.access$000(Unknown Source) 
    at me.chunyu.ChunyuDoctor.Dialog.b.onClick(Unknown Source) 
    at me.chunyu.ChunyuDoctor.Dialog.ChoiceDialogFragment.onClick(Unknown Source) 
    at android.view.View.performClick(View.java:4848) 
    at android.view.View$PerformClick.run(View.java:20270) 
    at android.os.Handler.handleCallback(Handler.java:815) 
    at android.os.Handler.dispatchMessage(Handler.java:104) 
    at android.os.Looper.loop(Looper.java:194) 
    at android.app.ActivityThread.main(ActivityThread.java:5643) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

il mio codice è qui:

public static void takePhoto(Fragment fragment, int token, Uri uri) { 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    if (uri != null) { 
     intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); 
    } 
    fragment.startActivityForResult(intent, token); 
} 

Ho cercato problemi e soluzioni simili. e modificare il codice come segue:

public static void takePhoto(Fragment fragment, int token, Uri uri) { 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 
      | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
    if (uri != null) { 
     intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); 
     intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); 
    } 
    fragment.startActivityForResult(intent, token); 
} 

Ma non è anche il lavoro.

Succede su Android 5.1 Mentre funziona bene su Android 4.3. C'è qualcuno che incontra lo stesso problema? Chiedi un po 'di anticipo. Attesa online ...

risposta

15

Ho già risolto questo problema.

Innanzitutto, questo problema si è verificato perché StrictMode impedisce il passaggio degli URI con uno schema file://.

Quindi ci sono due soluzioni:

  1. Change StrictMode. Vedi similar problem e its code. Ma per le nostre app, non è realistico modificare il codice sorgente di Android.

  2. Utilizzare un altro schema URI invece di file://. Ad esempio, content:// relativo a MediaStore.

così ho scelto il secondo metodo:

private void doTakePhoto() { 
    try { 
     ContentValues values = new ContentValues(1); 
     values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg"); 
     mCameraTempUri = getActivity().getContentResolver() 
       .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); 

     takePhoto(this, RequestCode.REQCODE_TAKE_PHOTO, mCameraTempUri); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public static void takePhoto(Fragment fragment, int token, Uri uri) { 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 
     | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
    if (uri != null) { 
     intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); 
     intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); 
    } 
    fragment.startActivityForResult(intent, token); 
} 

Inoltre, v'è un altro solution.

+0

"... richiede android.permission.WRITE_EXTERNAL_STORAGE, o grantUriPermission()" –

5

Il motivo di questo errore è che il file: // schema uri non è più supportato perché la sicurezza è esposta. https://code.google.com/p/android/issues/detail?id=203555

E Non possiamo più usare file: // uri dopo con targetSDK 'N'. https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html

Quindi, la risposta è giusta. Chiunque usi il file: // ha cambiato contenuto: // per fornire tipi di file locali.

+1

Grazie, ho declassato 'targetSdk' a ** 23 ** e si è iniziato a lavorare. Intendo 'File.getUriFrom (File file)' – murt

10

Così, mi è stato effettivamente la lettura di questo, e sembra la soluzione giusta per gestire questa situazione è la seguente:

String mCurrentPhotoPath; 

private File createImageFile() throws IOException { 
    // Create an image file name 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    String imageFileName = "JPEG_" + timeStamp + "_"; 
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); 
    File image = File.createTempFile(
     imageFileName, /* prefix */ 
     ".jpg",   /* suffix */ 
     storageDir  /* directory */ 
    ); 

    // Save a file: path for use with ACTION_VIEW intents 
    mCurrentPhotoPath = "file:" + image.getAbsolutePath(); 
    return image; 
} 

static final int REQUEST_TAKE_PHOTO = 1; 

private void dispatchTakePictureIntent() { 
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
    // Ensure that there's a camera activity to handle the intent 
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) { 
     // Create the File where the photo should go 
     File photoFile = null; 
     try { 
      photoFile = createImageFile(); 
     } catch (IOException ex) { 
      // Error occurred while creating the File 
      ... 
     } 
     // Continue only if the File was successfully created 
     if (photoFile != null) { 
      Uri photoURI = FileProvider.getUriForFile(this, 
                "com.example.android.fileprovider", 
                photoFile); 
      takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); 
      startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); 
     } 
    } 
} 

Avviso c'è una nota che Google dice di creare un "tenore: //" file invece di una risorsa basata su "file: //".

Questo da google:

Note: We are using getUriForFile(Context, String, File) which returns a content:// URI. For more recent apps targeting Android N and higher, passing a file:// URI across a package boundary causes a FileUriExposedException. Therefore, we now present a more generic way of storing images using a FileProvider.

Inoltre, è necessario impostare le seguenti: Now, you need to configure the FileProvider. In your app's manifest, add a provider to your application:

<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> 

Nota: (Tratto da sito di Google) Make sure that the authorities string matches the second argument to getUriForFile(Context, String, File). In the meta-data section of the provider definition, you can see that the provider expects eligible paths to be configured in a dedicated resource file, res/xml/file_paths.xml. Here is the content required for this particular example:

<?xml version="1.0" encoding="utf-8"?> 
<paths xmlns:android="http://schemas.android.com/apk/res/android"> 
    <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> 
</paths> 

Se desiderate maggiori informazioni: leggere fino qui https://developer.android.com/training/camera/photobasics.html

3

Oltre la soluzione utilizzando il FileProvider, c'è un altro modo per ovviare a questo. Basta inserire il metodo Application.onCreate(). In questo modo la VM ignora l'esposizione dell'URI del file.

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 
StrictMode.setVmPolicy(builder.build()); 
Problemi correlati