webdevqa.jp.net

Android:外部ストレージPUBLICディレクトリ内のファイルのcontent:// URIを取得する方法

私は このGoogleチュートリアル に従って、new Intent(MediaStore.ACTION_IMAGE_CAPTURE)で画像をキャプチャするインテントを開始しました。このチュートリアルでは、getExternalStoragePublicDirectoryでパブリックディレクトリを使用することを推奨しています。ただし、その例では代わりにgetExternalFilesDirを使用しています。次に、MediaStore.EXTRA_OUTPUT Iを使用してファイルのURIをインテントに渡します コンテンツURIを取得する必要があります Android N. NIを対象とする前は、file:// URIを渡すだけで、Google以外のすべての人が満足していましたが、NIではFileUriExposedExceptionの取得を開始しました あまり有利ではない

このようなファイルがあるとすると...

private File createImageFile() throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyAppFolder");
    if (!storageDir.exists() && !storageDir.mkdir())
        Log.w(TAG, "Couldn't create photo folder: " + storageDir.getAbsolutePath());
    File image = new File(storageDir, timeStamp + ".jpg");
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

...パブリックピクチャディレクトリの組み込みプロバイダーを使用してコンテンツURIを取得できますか?もしそうなら?

私は何かを試しました

takePictureIntent.putExtra(
    MediaStore.EXTRA_OUTPUT, 
    FileProvider.getUriForFile(this, MediaStore.AUTHORITY, createImageFile()));

ただ投げるだけ

IllegalArgumentException:Android.support.FILE_PROVIDER_PATHSメタデータがありません

その機関は正しいですか?独自のプロバイダーを使用してパブリックファイルを共有する必要がある場合、FILE_PROVIDER_PATHSメタデータでどのパスを指定できますか? 見つけることができるオプション はすべてプライベートディレクトリ用です。

18
Paul

TL:DR <external-path name="MyAppFolder" path="." />は機能しますが、安全ですか?

自分でFileProviderを作成する必要があります。 documentation を読む価値はありますが、ここで簡単に説明します。

@CommonsWareで述べたように、例のMediaStore.AUTHORITY"com.example.fileprovider"に置き換える必要があります。これは、マニフェストで次のように定義する権限です...

AndroidManifestの<application>タグ内に、次のように入力します。

<provider
    Android:name="Android.support.v4.content.FileProvider"
    Android:authorities="com.example.fileprovider"
    Android:exported="false"
    Android:grantUriPermissions="true">
    <meta-data
        Android:name="Android.support.FILE_PROVIDER_PATHS"
        Android:resource="@xml/file_paths" />
</provider>

発生している例外は、FileProviderがアクセスできるすべてのパスを含むxmlファイルにリンクする<meta-data>タグがないためです。しかし、私が自分自身と苦労してきたのは、このファイルの内容です。

リンクしたチュートリアルの終わりに向かって、 フルサイズの写真を保存 セクションの終わりに、Googleがこのfile_paths.xmlに与える例は次のとおりです。

<?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>

"my_images"は、例では"MyAppFolder"に置き換えられます。そのチュートリアルでGoogleは主張している

パスコンポーネントは、Environment.DIRECTORY_PICTURESで呼び出されたときにgetExternalFilesDir()によって返されるパスに対応します。 com.example.package.nameをアプリの実際のパッケージ名に置き換えてください。

...そしてそれを打ち込むと、あなたと私が探しているパブリックピクチャーディレクトリを参照しているのではないことがわかりましたそのパスを使用すると、この例外が発生する理由を説明します。

Java.lang.IllegalArgumentException:/storage/emulated/0/Pictures/MyAppFolder/{filename}.jpgを含む構成されたルートの検索に失敗しました

今後の参考のためにここに残し、大きな質問への回答に移ります。APIレベル24以上のアプリをターゲットとするアプリによって作成されたパブリックピクチャディレクトリ内のファイルを他のアプリが操作できるようにするには、どのパスを指定できますか?

@CommonsWareが言ったように、「目的のサブディレクトリの詳細はデバイスによって異なる」ため、パブリックピクチャディレクトリへのパスを宣言することはできませんが、機能する方法を見つけました。

<external-path name="MyAppFolder" path="." />は、FileProviderが他のアプリ(カメラなど)にコンテンツURIを提供できるようにします。これにより、解決先のファイルを読み書きできるようになります。

何か危険やマイナス面があれば是非聞いてください。

12
pumpkinpie65

これが、写真のパブリックディレクトリ用のアプリで使用しているものです。

  1. 次のようにファイルを作成します。

    File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME");
    
  2. ファイルプロバイダーのメタデータで次のパスを指定します。

    <paths>
        <external-path name="secure_name" path="Pictures/YOUR_APP_NAME" />
    </paths>
    

"secure_name"は、セキュリティ上の理由から、共有しているサブディレクトリの名前(この場合、"YOUR_APP_NAME")を非表示にするために使用されます。

「写真」はEnvironment.DIRECTORY_PICTURESに対応します。

  1. Uriを取得して、Intentで送信します。

    final Uri theUri = FileProvider.getUriForFile(activity,
                        getString(R.string.fileprovider_authorities),
                        theFile);
    theIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    theIntent.putExtra(MediaStore.EXTRA_OUTPUT, theUri);
    
5
Stan Mots