web-dev-qa-db-ja.com

AndroidのFileUriExposedException

画像を含む内部ストレージのフォルダーを開く必要があります。

私は次のコードを使用します。

Java

 File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),  "MyPhotos");
Intent intent = new Intent(Intent.ACTION_VIEW);
String path =folder.getPath();
Uri myImagesdir = Uri.parse("file://" + path );
intent.setDataAndType(myImagesdir,"*/*");   
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

[〜#〜] paths [〜#〜]

 <paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
     <external-path name="images" path="Pictures" />
     <external-path name="external_files" path="."/>
     <external-path name="files_root" path="Android/data/${applicationId}"/> </paths>

マニフェスト

  <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" />
        </provider>

xml/file_paths

<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <external-path name="images" path="Pictures" />
    <external-path name="external_files" path="."/>
    <external-path name="files_root" path="Android/data/${applicationId}"/>
</paths>

[〜#〜] error [〜#〜]

致命的な例外:メインプロセス:Android.apps.bnb.company.myphotos、PID:22482 Android.os.FileUriExposedException:file:/// storage/emulated/0/Pictures/MyPhotosはアプリを超えてIntent.getData()を介して公開されます

内部ストレージのフォルダーを開く別の方法はありますか?ありがとう!

更新#1

このアークティックルの使用 https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-Android-nougat/en 交換しました

Uri myImagesdir = Uri.parse("file://" + path );

 Uri myImagesdir = Uri.parse("content://" + path );

そしてエラーは消えました。

とにかく、このフォルダーを開くには常にアプリを選択する必要があります。

特定のフォルダを開くためにデフォルトでマイファイルアプリを使用する可能性はありますか?

9
Developer

ここで解決策を見つけました ダウンロードフォルダーを開くことができます。インテント?

このコードは、Samsung J7で完璧に機能し、SamsungのデフォルトアプリケーションMy filesを使用して、内部メモリからPicturesフォルダー(およびその他)を開きます。

File path = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
Uri uri = Uri.fromFile(path);
Intent intent = getPackageManager().getLaunchIntentForPackage("com.sec.Android.app.myfiles");
intent.setAction("samsung.myfiles.intent.action.LAUNCH_MY_FILES");
                    intent.putExtra("samsung.myfiles.intent.extra.START_PATH", path.getAbsolutePath());
startActivity(intent);

適切に呼び出す方法を確認するには、各メーカーのFile Managerを逆コンパイルする必要があるようです。 :(そしてそれはあまりにも多くの作業です。まあ...私はそれを行うための一般的な解決策があると仮定しました。

1
Developer

特定のフォルダを開くためにデフォルトでマイファイルアプリを使用する可能性はありますか?

はいいいえ。すべてのデバイスで動作することが100%保証されているわけではありません。

編集1:

以下は、それを行うことができる方法の1つです。私はいくつかのエミュレータでテストしました(Android N Android O)を実行し、デフォルトのファイルエクスプローラをロードします:

_MainActivity.Java_

_    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri dirUri = FileProvider.getUriForFile(this,getApplicationContext().getPackageName() + ".com.example.myapplication",Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //intent.setDataAndtType(); I will change this value in the alternatives below
    }
_

_AndroidManifest.xml_

_<provider
        Android:name=".GenericFileProvider"
        Android:authorities="${applicationId}.com.example.myapplication"
        Android:exported="false"
        Android:grantUriPermissions="true">
        <meta-data
            Android:name="Android.support.FILE_PROVIDER_PATHS"
            Android:resource="@xml/file_paths" />
</provider>
_

_GenericFileProvider.Java_

_public class GenericFileProvider extends FileProvider {
}
_

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

上記のアプローチは、サムスンのような大企業では機能しません

代替案

1。タイプ_DocumentsContract.Document.MIME_TYPE_DIR_の使用

intent.setDataAndType(dirUri,DocumentsContract.Document.MIME_TYPE_DIR);

このアプローチは、いくつかのエミュレーターと限られたデバイスのセットで機能します。 SamsungやHuaweiなどの大手企業では機能しません。

2。タイプ_resource/folder_の使用

intent.setDataAndType(dirUri,"resource/folder");

このアプローチは、ユーザーがESファイルエクスプローラーアプリをインストールした場合にのみ機能します。

を使用することを選択した場合、次を使用して、それを処理する意図があるかどうかを確認する必要があります。

PackageManager packageManager = getActivity()。getPackageManager();

_if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent);
} else {
   // either display error or take necessary action
}
_

3。タイプ_*/*_の使用

intent.setDataAndType(dirUri,"*/*");

ユーザーがIntent ChooserからFile Managerアプリを選択し、_*/*_を処理するデフォルトアプリとしてマークする場合、このアプローチは機能します。ただし、いくつかの欠点があります(一部を公開してくれた@CommonsWareに感謝します)。

  • このタイプは、デバイス上のすべてのアプリをロードし、ユーザーがいずれかを選択してアクションを完了することを許可します。
  • ファイルエクスプローラがなく、ユーザーが他のアプリを選択してインテントをロードすると、他のアプリがクラッシュするか、単に黒い画面が表示されます。例えば。エクスプローラーではなくギャラリーまたは他のアプリを使用して起動すると、ギャラリーアプリがクラッシュするか、黒い画面が表示されます。
  • ファイルエクスプローラーはあるが、ユーザーが他のアプリを使用することにした場合でも、他のアプリがクラッシュする可能性があります

4。タイプ_text/csv_の使用

intent.setDataAndType(uri, "text/csv")

これにより、ユーザーに表示されるアプリの数が制限されますが、使用される_*/*_が適用される場合は同じ制限が適用されます。 csvを処理できるアプリが表示され、ユーザーが選択するとアプリがクラッシュします。

使用可能なデバイス固有の実装がいくつかあります ここ@ Academy of Programmerで言及されているように、デフォルトのファイルマネージャの意図を識別する必要があり、それによる余分の必要性。

結論:

現在のところ特定のタイプをサポートするためのファイルマネージャが従う標準がないため、それを達成するために利用できる標準タイプはありません。将来的にはGoogleが何らかのアプローチを考え出すかもしれません。最良の代替手段は、DropboxやGoogleドライブのように独自のファイルマネージャーを実装することです。この機能を提供するいくつかのライブラリが利用可能です。

9
Sagar

以下のコードは、ストレージから画像を開くために私が使用しています:

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

File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");

File filepath = new File(path + "/" + yourImageName.png);

Uri uri = Uri.fromFile(filepath);

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

編集された回答:

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

File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");

Uri uri = Uri.fromFile(path);

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
2
Shiva Snape