1. ホーム
  2. アンドロイド

Android 8.0エラー android.os.FileUriExposedException が ClipData.Item.getUri() を通してアプリの外部に公開される。

2022-03-16 04:31:54

システムカメラが呼び出されると、システムがスローする               #find . -name test* これはエラーです。具体的なスタック情報は以下の通りです。

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: zzidc.com.education_system, PID: 13382
                  android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/zzidc.com.education_system/files/Pictures/ camera1548744838682.jpg exposed beyond app through ClipData.Item.getUri()
                      at android.os.StrictMode.onFileUriExposed(StrictMode.java:1975)
                      at android.net.Uri.checkFileUriExposed(Uri.java:2363)
                      at android.content.ClipData.prepareToLeaveProcess(ClipData.java:941)
                      at android.content.Intent.prepareToLeaveProcess(Intent.java:9944)
                      at android.content.Intent.prepareToLeaveProcess(Intent.java:9929)
                      at android.app.Instrumentation.execStartActivity(Instrumentation.java:1622)
                      at android.app.Activity.startActivityForResult(Activity.java:4751)
                      startActivityForResult(Activity.java:4691) at android.app.Activity.startActivityForResult(Activity.java:4691)
                      at zzidc.com.education_system.activity.ImageToVideo.openCamera(ImageToVideo.java:78)
                      at zzidc.com.education_system.activity.ImageToVideo.onViewClicked(ImageToVideo.java:61)
                      at zzidc.com.education_system.activity.ImageToVideo_ViewBinding$2.doClick(ImageToVideo_ViewBinding.java:49)
                      at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
                      at android.view.View.performClick(View.java:6291)
                      at android.view.View$PerformClick.run(View.java:24931)
                      at android.os.Handler.handleCallback(Handler.java:808)
                      at android.os.Handler.dispatchMessage(Handler.java:101)
                      at android.os.Looper.loop(Looper.java:166)
                      at android.app.ActivityThread.main(ActivityThread.java:7425)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)


7.0以前

Uri pothoUri = Uri.fromFile(getSavePhotoPath());

private File getSavePhotoPath() {
        String photoFile = getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/camera" + System.currentTimeMillis() + ".jpg" ;;
        File file = new File(photoFile);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        return file;
    }


7.0以降

Android では、Intent や ClipData などのメソッドを含め、アプリ内で file://Uri を他のアプリに公開することができなくなりました。

その理由は、file://Uriの使用には以下のようなリスクがあるためです。

  • このファイルはプライベートなものであり、受け取る file://Uri アプリはこのファイルにアクセスできません。
  • Android 6.0以降のランタイムパーミッションの導入により、file://Uriを受け取るアプリが READ_EXTERNAL_STORAGE パーミッションがない場合、ファイルを読み込む際にクラッシュします。

そのため、googleは FileProvider を生成するために使用することができます。 content://Uri を置き換えるために file://Uri

ここで、education_system はオプションであるが、一意であることが保証される。と互換性がある必要があります。 AndroidManifest.xml のプロバイダは 

authorities remain the same

Uri pothoUri = FileProvider.getUriForFile(this,"education_system",getSavePhotoPath());

AndroidManifest.xml にプロバイダを追加します。 

<provider
            android:authorities="education_system"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

  • android:authorities: プロバイダを識別するために使用されます。
  • android:exported : 他のアプリが現在のコンポーネントを呼び出すことをサポートするかどうか。デフォルトはfalse
  • android:grantUriPermissions : 共有ファイルへのアクセス許可を制御するために使用され、Javaコードで設定することも可能です。

Resの下にxml/provider_path.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>


paths>には、以下のノードが定義できます。

<テーブル 子ノード 対応するパス
files-path

Context.getFilesDir()
cache-path

Context.getCacheDir()
external-cache-path

Context.getExternalCacheDir()
external-files-path

Context.getExternalFilesDir(null)です。
external-path

環境.getExternalStorageDirectory()

file:// 次のページへ content:// の変換ルールは

  1. プレフィックスを置き換える file:// から content://${android:authorities} .
  2. マッチングと置換
    1. paths> の子を繰り返し、ファイルパスのプレフィックスに最大に一致するものを見つける。
    2. ファイルパス内の一致した内容をpathの値で置き換える。
  3. ファイルパスの残りを変更せずに残す。

                                       変換回路図