2015-09-17 7 views
22

例外がある:時にテイク写真を取得 - java.lang.Throwableの:ファイル:// URIが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) 

私のコードはここにある:

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でもうまくいく一方です。 誰も同じ問題を抱えていますか? 事前にお尋ねください。 オンライン待機中...

答えて

15

私はすでにこの問題を解決しました。

まず、StrictModefile://スキームのURIを渡すのを防ぐため、この問題が発生しました。

  1. 変更StrictMode

    だから2つのソリューションがあります。 similar problemおよびits codeを参照してください。 しかし、私たちのアプリでは、Androidのソースコードを変更するのは現実的ではありません。

  2. file://ではなく、別のURIスキームを使用してください。例えば、は、MediaStoreに関連しています。

    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があります:

は、だから私は、第二の方法を選びました。

+0

は "... android.permission.WRITE_EXTERNAL_STORAGE、またはgrantUriPermissionが必要です()" –

5

このエラーの原因は、セキュリティが公開されているため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://を変更してローカルファイルの種類を提供します。

+1

おかげで、私はへ** 23 ** 'targetSdk'を格下げし、それが作業を開始しました。私は 'File.getUriFrom(ファイルファイル)'を意味します – murt

10

だから、私は実際にこのことについて読んでいた、そしてこれを処理するための正しい解決策は以下のようです:

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://"ベースのリソースを使用します。

これはグーグルからである:

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

3

要約すると: ファイルを://スキームは今targetSdkVersion 24(アンドロイドヌガー)あなたがしなければならない

にテントを添付することが許可されていませんあなたは、APIに24+ 2つのリンクをサポートすることを計画している場合、あなたのコードを変更します。FileProviderを用いて溶液に加え https://developer.android.com/training/camera/photobasics.html https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en

+0

良い1つ、本当に役立ちます –

3

を、この問題を回避する別の方法があります。単にApplication.onCreate()メソッドを使用します。このようにして、VMはファイルURIの公開を無視します。

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 
StrictMode.setVmPolicy(builder.build()); 
関連する問題