2016-06-21 96 views
14

我跟着this Google tutorial開始意圖捕獲圖像new Intent(MediaStore.ACTION_IMAGE_CAPTURE)。本教程建議使用公共目錄getExternalStoragePublicDirectory,這對我的應用程序非常有用。但是他們的例子改爲使用getExternalFilesDir。然後傳遞文件的URI到意圖MediaStore.EXTRA_OUTPUThave to get a content URI,因爲我想定位到Android N之前瞄準N我只是通過一個文件:// URI和每個人,但谷歌很高興。現在在N我開始得到FileUriExposedException,似乎是not very favorableAndroid:如何獲取內容:// URI在外部存儲中的文件PUBLIC目錄

所以因爲我有一個這樣的文件...

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元數據中指定哪條路徑?所有options I can find用於私人目錄。

+1

「那是正確的權力?」 - 不,因爲你不是'MediaStore'。 「如果我必須使用我自己的提供者共享公共文件,那麼我可以在FILE_PROVIDER_PATHS元數據中指定什麼路徑?」 - ''給你外部存儲的根。 'FileProvider'沒有辦法指定你正在嘗試使用的目錄。 – CommonsWare

+0

@CommonsWare如果FileProvider無法使用該目錄,那麼我是唯一使用私有目錄還是停止目標N的選項?這似乎很愚蠢。感謝您的建議。 – Paul

+0

「如果FileProvider無法使用該目錄」 - 這不是我寫的。這就是說,由於你想要的子目錄的細節因設備而異,試圖使用''會有風險。 「那麼我唯一的選擇是使用私人目錄還是停止定位N?」 - 沒有。你可以編寫你自己的'ContentProvider'。或者,你可以爲我的'StreamProvider'編寫一個插件。或者,您可以在外部存儲上使用自定義目錄,您可以從外部存儲根目錄控制其路徑(儘管這可能是「私人目錄」的含義)。 – CommonsWare

回答

5

TL:DR <external-path name="MyAppFolder" path="." />有效,但安全嗎?您需要自己製作FileProvider。值得一讀的是documentation,但這裏有一個簡短的概要。

正如@CommonsWare提到的,你需要從你的例子與"com.example.fileprovider"取代MediaStore.AUTHORITY,這是你會在你的清單,像這樣定義的權威......

<application>標籤在AndroidManifest,類型以下內容:

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

你得到的例外是由於不具有<meta-data>標籤鏈接到一個XML文件中的所有您FileProvider被允許觸摸路徑。但這是我一直在自己掙扎的文件。

朝你聯繫,在Save the Full-size Photo節結束的教程結束時,谷歌的例子給出這種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提供給其他應用程序(如相機),然後可以讀取和寫入其解析的文件。

如果有任何危險或缺點,我很樂意聽到他們。

3

這是我在我的應用程序中使用的圖片公共目錄。

  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

  • 獲取UriIntent派:

    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); 
    
  • 相關問題