例外は次のとおりです。
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)
私のコードはここにあります:
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);
}
同様の問題と解決策を探しました。そして、次のようにコードを変更します。
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);
}
しかし、それも機能しません。
それはAndroid 5.1でうまくいきましたがAndroid 4.3。同じ問題に出会った人はいますか?.
私はすでにこの問題を解決しています。
最初に、StrictMode
がfile://
スキームでURIを渡すことができないため、この問題が発生しました。
したがって、2つのソリューションがあります。
StrictMode
を変更します。 同様の問題 および コード を参照してください。ただし、アプリの場合、Androidソースコードを変更することは現実的ではありません。
file://
の代わりに、別のURIスキームを使用します。たとえば、MediaStore
に関連するcontent://
。
そこで、2番目の方法を選択しました。
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);
}
また、別の solution があります。
だから、私は実際にこれについて読んでいて、これを処理する正しい解決策は次のようです:
_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);
}
}
}
_
Googleが「file://」ベースのリソースではなく「content://」ファイルを作成するように指示していることに注意してください。
これはグーグルからです:
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.
また、次をセットアップする必要があります:_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>
_
注:(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>
_
詳細情報が必要な場合は、こちらをご覧ください https://developer.Android.com/training/camera/photobasics.html
FileProviderを使用したソリューションの他に、これを回避する別の方法があります。 Application.onCreate()メソッドに配置するだけです。このように、VMはファイルURIの露出を無視します。
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
このエラーの理由は、セキュリティが公開されているためfile:// uriスキームがサポートされなくなったためです。 https://code.google.com/p/Android/issues/detail?id=203555
また、targetSDK 'N'を使用すると、file:// uriは使用できなくなります。 https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html
だから、答えは正しい。 file://を使用するユーザーは、content://を変更して、ローカルファイルの種類を提供します。
要約すると、file://スキームは、targetSdkVersion 24(Android Nougat)のIntentでアタッチすることが許可されなくなりました
API 24以上の2つのリンクをサポートする予定がある場合は、コードを変更する必要があります。 https://developer.Android.com/training/camera/photobasics.htmlhttps:// inthecheesefactory .com/blog/how-to-share-access-to-file-with-fileprovider-on-Android-nougat/en