L'exception est:
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)
Mon code est ici:
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);
}
J'ai cherché les problèmes et les solutions similaires. Et modifiez le code comme suit:
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);
}
Mais ce n'est pas non plus le travail.
Il est arrivé le Android 5.1 Bien que cela fonctionne bien sur Android 4.3. Y a-t-il quelqu'un qui rencontre le même problème? Demandez une avance. Attendez en ligne ...
J'ai déjà résolu ce problème.
Tout d'abord, ce problème est survenu car StrictMode
empêche la transmission d'URI avec un file://
schéma.
Il y a donc deux solutions:
Modifiez StrictMode
. Voir problème similaire et son code . Mais pour nos applications, il n'est pas réaliste de modifier le code source Android.
Utilisez un autre schéma d'URI, au lieu de file://
. Par exemple, content://
lié à MediaStore
.
J'ai donc choisi la deuxième méthode:
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);
}
En outre, il existe une autre solution .
Donc, je lisais à ce sujet, et il semble que la bonne solution pour gérer cela est la suivante:
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);
}
}
}
Notez qu'il y a une note que Google dit de créer un fichier "content: //" au lieu d'une ressource basée sur "file: //".
C'est de 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.
De plus, vous devrez configurer les éléments suivants: 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>
Remarque: (Tiré du site de 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>
Si vous souhaitez plus d'informations: lisez ici https://developer.Android.com/training/camera/photobasics.html
Outre la solution utilisant FileProvider, il existe une autre façon de contourner ce problème. Mettez simplement la méthode Application.onCreate (). De cette façon, le VM ignore l'exposition de l'URI du fichier.
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
La raison de cette erreur est que le schéma file: // uri n'est plus pris en charge car la sécurité est exposée. https://code.google.com/p/Android/issues/detail?id=203555
Et nous ne pouvons plus utiliser file: // uri avec targetSDK 'N'. https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html
Donc, la réponse est juste. Quiconque utilise file: // a change content: // pour fournir des types de fichiers locaux.
Pour résumer: le schéma file: // n'est plus autorisé à être attaché avec Intent sur targetSdkVersion 24 (Android Nougat)
Vous devez changer votre code si vous prévoyez de prendre en charge api 24+ deux liens: https://developer.Android.com/training/camera/photobasics.htmlhttps: // inthecheesefactory .com/blog/comment-partager-l'accès-à-fichier-avec-fileprovider-on-Android-nougat/en