-1

我編寫了一個將某些數據導出到文件的Android應用程序。如何訪問由文件管理器共享的文件(如果我的應用程序沒有READ_EXTERNAL_STORAGE

該文件通過ACTION_SENDIntent和我的自定義ContentProvider發佈到其他應用程序。它工作正常。文件可以附加到電子郵件或通過Bluetooth發送。

現在,同一故事的另一方面是應用程序應該能夠接收文件來導入它。我的目的是讓用戶在文件管理器中選擇一個文件並選擇「共享」選項。現在我的intent-filter應該被激活,我的應用程序應該訪問該文件。

我的應用程序沒有READ_EXTERNAL_STORAGE權限,因爲通常它不需要訪問外部存儲中的文件。我不想添加此權限,我不想讓用戶知道我的應用可能訪問他們的照片等等。

根據Intent類的文檔,如果調用應用程序添加了FLAG_GRANT_READ_URI_PERMISSION,它應該足以讓我的應用程序讀取共享文件。

intent-filter

<intent-filter> 
    <action android:name="android.intent.action.SEND"/> 
    <action android:name="android.intent.action.SENDTO"/> 
    <action android:name="android.intent.action.SEND_MULTIPLE"/> 
    <category android:name="android.intent.category.DEFAULT"/> 
    <category android:name="android.intent.category.BROWSABLE"/> 
    <data android:mimeType="*/*"/> 
</intent-filter> 

通過意向濾鏡接收我的代碼來處理的意圖:

Uri uri = null; 
if (uri == null) 
{ 
    uri = intent.getData(); 
} 
if (uri == null) 
{ 
    if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) 
    { 
     uri = (Uri) intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM).get(0); 
    } 
    else 
    { 
     uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); 
    } 
} 
if (uri != null) 
{ 
    try 
    { 
     InputStream stream = getContentResolver().openInputStream(uri); 
     stream.read(); 
     stream.close(); 
     Toast.makeText(this, "Success " + intent.getAction() + " " + uri.toString(), Toast.LENGTH_LONG).show(); 
    } 
    catch (IOException e) 
    { 
     Toast.makeText(this, "Error " + intent.getAction() + " " + uri.toString() + " " + e.getMessage(), Toast.LENGTH_LONG).show(); 
    } 
} 

這僅僅是一個「測試」的代碼,所以我只是儘量讀什麼從文件開始檢查它是​​否有效。

結果是:

  • 我使用ES文件瀏覽器和驚喜「共享」文件到我的應用程序嘗試。通常收到的Uri是一個文件Uri ("file://" scheme)並試圖打開此文件失敗openInputStream與我的應用程序無權訪問該文件的信息。

  • 由於某些原因,我從ES文件資源管理器共享一個媒體文件的文件時,行爲會發生變化。我收到一個"content://" Uri,我的應用程序可以訪問該文件。驚奇似乎仍然發送"file://" Uri並打開文件失敗。

  • 我試圖修改代碼以從ClipData(如果可用)獲得Uris,但它沒有改變任何東西。

  • 當我嘗試從內置的MIUI電子郵件客戶端打開附件時,我還收到file:// Uris並且該文件無法訪問。 (測試此我不得不使用ACTION_VIEW行動,而不是ACTION_SEND

我也嘗試了其他方式。我使用ACTION_GET_CONTENTIntent從我的應用中調用了一個文件選取器,並想從我的應用中使用返回的Uri。結果更糟,因爲即使"content://" Uris也不起作用。

所以,問題是 - 有什麼辦法來訪問的方式,可以讓我的應用程序來訪問共享文件,而不添加READ_EXTERNAL_STORAGE permission從流行的文件管理共享的文件?

我可以在Android的文檔有關FLAG_GRANT_READ_URI_PERMISSION閱讀和file:// Uris被禁止在Android 7.0 開始,所以一切都是理論上的準備,使工作,但在現實世界中我撞到牆上......

我知道我總是可以將READ_EXTERNAL_STORAGE權限添加到我的應用中,或者讓用戶手動將文件複製到我應用的外部存儲目錄(路徑getExternalFilesDir返回的路徑),然後在那裏訪問文件,但這兩個操作都有嚴重的缺陷(安全影響源自不必要的許可或糟糕的用戶體驗)。

是否有任何其他選項可用於使其工作?

+0

'我使用ACTION_GET_CONTENT Intent從我的應用程序中調用了一個文件選取器,並且想從我的應用程序中使用返回的Uri。結果更糟糕,因爲即使是「content://」Uris也不行。抱歉。我不明白什麼是行不通的。您的應用可以使用內容方案打開文件。你還想要什麼? – greenapps

+0

問題是我無法在這種情況下打開內容Uris,因爲系統表示我沒有權限這樣做。我懷疑選擇器應用程序未將Intent中的FLAG_GRANT_READ_URI_PERMISSION標誌設置回發送給我的應用程序,但我沒有ES文件資源管理器的源,因此我無法驗證此內容。 – Bieniu

+0

很難相信。我從未見過ACTION_GET_CONTENT獲取的內容方案不可用。爲什麼在談論ACTION_GET_CONTENT時提到ES文件資源管理器? – greenapps

回答

0

根據Intent類的文檔,如果調用應用程序添加FLAG_GRANT_READ_URI_PERMISSION,它應該足以讓我的應用程序讀取共享文件。

這隻適用於content計劃。

我使用ACTION_GET_CONTENT Intent從我的應用程序中調用了一個文件選取器,並且想從我的應用程序中使用返回的Uri。結果更糟,因爲即使是「content://」Uris也不行。

大概在你的代碼中存在一個bug。你可能會考慮爲此打開一個單獨的Stack Overflow問題。

此外,對於API Level 19+,您可以使用ACTION_OPEN_DOCUMENT,這是建議的Intent操作。

有沒有什麼辦法來訪問從的方式,讓我的應用程序來訪問共享文件而無需添加READ_EXTERNAL_STORAGE權限流行的文件管理共享的文件?

不是如果他們給你一個fileUri。不幸的是ACTION_SEND不提供過濾方案。 :-(

現在,從長遠來看,fileUri值將淡出,由於Android 7.0+打破了24+的一個targetSdkVersion應用程序,試圖將它們納入一個Intent,爲應用程序。

+0

感謝您的回答。所以我猜,到目前爲止沒有運氣......我需要等到目標Android 7.0+成爲標準。 :) – Bieniu

0

的Android不斷推出的支持庫FileProvider類在其他應用程序共享文件,這已經推出了安全方面的原因。

很顯然,在安卓7.0你不能與文件前綴訪問的URI。

除非和直到文件管理員提供的URI爲 內容://而不是file://,您無法訪問這些文件。

相關問題