原創:HuangBo-OEM 百度APP技術團隊
android
Google於 2019年9月3日發佈了Android10 release版本,爲了更好的保護用戶數據並限制設備冗餘文件增長,Android 10版本變動了設備外部存儲訪問方式,外部存儲新特性稱爲分區存儲(Scoped Storage), 分區存儲遵循如下三個原則對外部存儲文件訪問方式從新設計,便於用戶更好的管理外部存儲文件。bash
系統記錄文件由哪一個應用建立,應用不須要存儲權限便可以訪問應用本身建立文件app
添加外部存儲應用私有目錄文件訪問限制,應用即便申請了存儲權限也不能訪問其餘應用外部存儲私有目錄文件框架
添加pdf、office、doc等文件的訪問限制,用戶即便申請了存儲權限也不能訪問其餘應用建立的pdf、office、doc等文件ide
分區存儲存在必定的適配成本,Google爲Android10版本提供了過渡方案,設置應用以兼容模式運行(詳見2.3), Android11將再也不支持該行爲, 各應用須要在Android11發版以前完成分區存儲適配工做。ui
(1)應用私有目錄:存儲應用私有數據,外部存儲應用私有目錄對應Android/data/packagename,內部存儲應用私有目錄對應data/data/packagename;
(2) 共享目錄:存儲其餘應用可訪問文件, 包含媒體文件、文檔文件以及其餘文件,對應設備DCIM、Pictures、Alarms, Music, Notifications,Podcasts, Ringtones、Movies、Download等目錄。spa
應用私有目錄文件訪問方式與以前Android版本一致,能夠經過file path獲取資源。設計
共享目錄文件須要經過MediaStore API或者Storage Access Framework方式訪問
(1)MediaStore API在共享目錄指定目錄下建立文件或者訪問應用本身建立文件,不須要申請存儲權限; (2)MediaStore API訪問其餘應用在共享目錄建立的媒體文件(圖片、音頻、視頻), 須要申請存儲權限,未申請存儲權限,經過ContentResolver查詢不到文件Uri,即便經過其餘方式獲取到文件Uri,讀取或建立文件會拋出異常;
(3)MediaStore API不可以訪問其餘應用建立的非媒體文件(pdf、office、doc、txt等), 只可以經過Storage Access Framework方式訪。;code
(1) 圖片位置信息 一些圖片會包含位置信息,由於位置對於用戶屬於敏感信息, Android 10應用在分區存儲模式下圖片位置信息默認獲取不到,應用經過如下兩項設置能夠獲取圖片位置信息, 在manifest中申請ACCESS_MEDIA_LOCATION 調用MediaStore setRequireOriginal(Uri uri)接口更新圖片Uri;
(2)MediaStore.Files應用分區存儲模式下,MediaStore.Files集合只可以獲取媒體文件信息(圖片、音頻、視頻),獲取不到非media(pdf、office、doc、txt等)文件;
(3) File Path路徑訪問受影響接口開啓分區存儲新特性, Andrioid 10不可以經過File Path路徑直接訪問共享目錄下資源,如下接口經過File路徑操做文件資源,功能會受到影響,應用須要使用MediaStore或者SAF方式訪問。 orm
應用未完成外部存儲適配工做,能夠臨時以兼容模式運行, 兼容模式下應用申請存儲權限,便可擁有外部存儲完整目錄訪問權限,經過Android10以前文件訪問方式運行,如下兩種方法設置應用以兼容模式運行。
(1)Target 小於等於Android 9 (API level 28);
(2)Tagret 大於等於Android 10(API level 29,在manifest中設置requestLegacyExternalStorage屬性爲true。
<manifest ... >
<!-- This attribute is "false" by default on apps targeting
Android 10 or higher. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
複製代碼
Environment.isExternalStorageLegacy()返回值:
true : 應用以兼容模式運行;
false:應用以分區存儲特性運行
備註
應用已完成存儲適配工做且已打開分區存儲開關,若是當前應用以兼容模式運行,覆蓋安裝後應用仍然會以兼容模式運行,卸載從新安裝應用纔會以分區存儲模式運行
分區存儲適配包含文件遷移以及文件訪問兼容性適配兩個部分;
文件遷移是將應用共享目錄文件遷移到應用私有目錄或者Android10要求的media集合目錄。
(1)針對只有應用本身訪問而且應用卸載後容許刪除的文件,須要遷移文件到應用私有目錄文件,能夠經過File path方式訪問文件資源,下降適配成本;
(2)容許其餘應用訪問,而且應用卸載後不容許刪除的文件,文件須要存儲在共享目錄,應用能夠選擇是否進行目錄整改,將文件遷移到Android10要求的media集合目錄。
共享目錄文件不可以經過File path方式讀取,須要使用MediaStore API或者Storage Access Framework框架進行訪問。
系統會自動掃描外部存儲,添加文件到系統已定義的Images、Videos、Audio files、Downloaded files集合中,Android 10經過MediaStore.Images、MediaStore.Video、MediaStore.Audio、MediaStore.Downloads 訪問共享目錄文件資源
Android 10版本 MeidaStore API只容許在共享目錄指定目錄建立文件, 非指定目錄建立文件會拋出IllegalArgumentException, 建立文件目錄彙總以下:
備註Android 4.4引入了Storage Access Framework框架,應用經過系統選擇器訪問 DocumentsProvider 提供文件(包含外部存儲以及雲端存儲, 外部存儲包含應用私有目錄以及共享目錄), SAF機制不須要申請任何存儲權限, 包含Document provider、Client app、Picker三部分:
(1)Document provider:文檔提供者是 DocumentsProvider 子類,數據模型是基於文件層級進行設計的,文檔提供者經過存儲服務(例如Google Drive)管理文件;
(2)Client app:經過調用 ACTION_CREATE_DOCUMENT , ACTION_OPEN_DOCUMENT , and ACTION_OPEN_DOCUMENT_TREE Intent獲取Document provider提供的文件, 應用能夠設置MIME type或者EXTRA_INITIAL_URI選擇須要獲取的文件,onActivityResult接口會返回選擇文件Uri;
(3)Picker:系統UI,應用經過調起系統選擇器獲取Document provider提供的文件信息。
(1) APP主動分享文件給其餘應用,可使用FileProvider方式賦予其餘應用文件讀取權限, FileProvider 應用基於XML配置生成文件Uri,其餘應用不須要申請存儲權限就能夠經過接收Uri獲取文件資源;
(2) Android 10 應用開啓分區存儲,經過File協議Uri或者MediaStore Uri分享文件給其餘應用, 功能會受到影響, 具體以下表格:
百度APP分區存儲適配涉及二十多業務方,歷經3個版本迭代,解決90%場景問題,排查外部存儲共享目錄經過File方式訪問的資源,針對歷史遺留文件, 業務方根據具體場景選擇是否進行文件遷移;針對只有應用本身訪問而且應用卸載後容許刪除的文件,經過文件遷移到外部存儲私有目錄方式進行適配;針對容許其餘應用訪問,而且應用卸載後不容許刪除的文件, 經過使用MediaStore API或者SAF方式進行適配
1.www.youtube.com/watch?v=UnJ…
2.developer.android.com/training/da…
3.developer.android.com/training/da…
4.developer.android.com/training/da…
5.developer.android.com/guide/topic…