Android(Q)10 上的分割槽外部儲存訪問

戀貓de小郭發表於2020-02-24

Android(API 29)10 釋出至今已經有不少裝置完成升級,如:小米9、Redmi K20pro、華為 P30pro/Mate30pro 、榮耀 v30/v20、Oppo Reno、ONnePlus 7T、谷歌 Pixel 等都已經升級到 Android 10 的支援,不少應用市場也要求應用需要針對 Android 10 進行適配,其中最大的變更之一就是 scoped storage

在針對目前 小米、華為、Pixel 的幾臺 Android 10 手機做了測試,在不設定 requestLegacyExternalStorage 的前提下得到結論(官方還沒完全開啟限制的前提):

  • 1、targetSDK 用 28 編譯的在 Android 10 上還是可以讀取到全部檔案, 之後覆蓋安裝一個使用 targetSDK 29 的,還能繼續可以訪問全路徑。

  • 2、解除安裝後直接用 targetSDK 29 編譯的會讀取不到。

Android(Q)10 上的分割槽外部儲存訪問

而官方明確表示:

明年(2020),主要平臺版本將要求所有應用都使用分割槽儲存,無論應用的目標 SDK 級別是多少。因此,您應該提前確保您的應用能夠使用分割槽儲存。為此,請確保針對搭載 Android 10(API 級別 29)及更高版本的裝置啟用了該行為。

所以不管是使用 requestLegacyExternalStorage 還是降低 targetSDK 都無法在接下來2020 年的 Android(API 29)10 新版更新中被豁免。

雖然作為 Android 開發會因為無法對使用者儲存目錄“為所欲為”而頭痛,但是作為使用者卻是感覺欣喜的。

因為長期以來 Android 使用者的本地儲存目錄都十分雜亂,開發者只要申請一次許可權就可以“為所欲為”地建立和讀取本地儲存,雖然谷歌在 Android 4.4(API 19))引入了存 SAF(Storage Access Framework) , 但是開發者大部分時候都選擇無視。

我甚至想要一個系統標誌出這個檔案是誰建立的 API ,因為最近遇到這個問題卻沒有頭緒: 為什麼相簿裡總是多出一張空白圖片,刪了後不久又重現?

官方解讀

為了讓使用者更好地管理自己的檔案並減少混亂,Android 10(API 29)開始應用在預設情況下會被要求使用 scoped storage(即分割槽儲存),也就是說應用只能看到自己專有的目錄(Context.getExternalFilesDir())以及特定型別的媒體檔案。

注意這個是強制性的,但是會有緩衝期,官方明確額表示,除非你的應用真的有強烈需要訪問專有目錄以及 MediaStore 之外的檔案,否則最好使用分割槽儲存。

使用分割槽儲存的應用對自己建立的檔案始終擁有讀/寫許可權,無論檔案是否位於應用的專有目錄內。這說明了預設分割槽儲存內的檔案也只有應用自己能看到,就像是沙盒內,同時 getExternalFilesDir() 下的檔案會隨著應用解除安裝而清除。

也就是說應用可以無需申請任何許可權使用 getExternalFilesDir()MediaStoreSAF 讀寫檔案,**當然如果使用 MediaStore 讀取其他應用的媒體集合時,是需要 READ_EXTERNAL_STORAGE **。

MediaStore 中支援的型別有:

  • 照片:儲存在 MediaStore.Images 中。
  • 視訊:儲存在 MediaStore.Video 中。
  • 音訊檔案:儲存在 MediaStore.Audio 中。

另外還有其他的限制,比如:

  • 應用沒有 ACCESS_MEDIA_LOCATION 許可權,那麼訪問到的媒體資源中的 Exif 後設資料會被修改.
  • 使用 MediaStore.Files 也僅顯示照片、視訊和音訊檔案,例如不會顯示錶中的 PDF 檔案。

總結起來結論就是:

  • 1、獲取系統相簿、視訊,圖片等需要通過 SAF ,利用 ContentResolverCursor 來提供。
  • 2、訪問公有目錄也需要通過 MediaStoreContentResolver ,比如儲存圖片到外部公共儲存,拷貝檔案到 Download 目錄等等。
  • 3、比如 new File(path).exists(); 等的判斷在公共目錄下不能再用了。

簡單來說就是:應用在自己的沙盒內可以“為所欲為”,通過 MediaStore 可以分類整理檔案,通過 SAF 可以訪問其他應用的公共媒體檔案。

相關實踐操作推薦百度團隊的:《Android 10分割槽儲存介紹及百度APP適配實踐》

Android(Q)10 上的分割槽外部儲存訪問

相關文章