在上篇文章了解到應用級檔案只能被其所創建的應用程式所訪問,那么其他應用程式是不是就無論如何都無法訪問了呢?肯定不是的,只要檔案經過其創建的應用程式授權,還是可以被其他應用程式所訪問的,這也就是應用級檔案的共享,
系統只允許共享包含實際資料的純檔案型別,而不推薦共享包含檔案的目錄型別,
對于檔案的訪問可以使用java.io.File系統檔案類,但是如果想將該檔案分享出去,則需要借助android.net.Uri路徑定位符類,Uri類是Android系統下自定義的路徑定位符規則,其符合Java中定義的java.net.URI標準資源定位符規范,并新增了getPathSegments()獲取分割路徑串列的方法和getQueryParameter(String key)獲取指定的額外引數方法等,
通常思路是將要分享的File檔案物件轉換成特定的Uri路徑定位符物件,在Android7即API 24版本及以后的版本中,系統對Uri增加了授權處理,這將在后文詳細解釋,
之后將該Uri物件可以作android.os.Bundle資料物件通過android.content.Intent意圖類傳遞,
最終在接收到意圖的應用程式中,可以收到Uri路徑并對其做不同處理,即可訪問該路徑下的檔案,針對Uri中的內容不同,一般需要做不同的轉換處理,這將在后文詳細解釋,
檔案分享方
目標版本級別小于24的應用程式
在Android7即API 24版本以前,應用程式內的任何File物件,都可以通過靜態方法Uri.fromFile(File file)將引數 file 直接轉換為Uri物件,
得到的Uri物件可直接操作賦值給Intent意圖物件的setData(Uri data)方法中的引數 data ,或putExtra(String key, Parcelable value)方法中的引數 value,從而分享傳遞出去,
目標版本級別大于等于24的應用程式
從Android7即API 24版本開始,應用程式內部共享檔案,仍然可以使用Uri.fromFile(File file)方法,但是如果想在應用程式中對得到的Uri物件直接傳遞給其他應用程式使用,會拋出android.os.FileUriExposedException例外,因此,在使用androidx依賴包的應用程式中可以借助androidx.core.content.FileProvider檔案分享提供類,在使用support-v4依賴包的應用程式中可以借助android.support.v4.content.FileProvider檔案分享提供類,獲取相關Uri物件,并為其授權,之后才可在不同應用程式間共享訪問,
對于FileProvider的使用,要先做準備作業,
首先需要在應用程式的清單檔案中注冊,在<application></application>標簽中增加<provider></provider>標簽,
在該標簽中指定屬性android:name="androidx.core.content.FileProvider"以系結檔案分享提供類;
另外在該標簽中指定屬性android:authorities="xxx",這里的屬性值xxx是應用程式所在系統內唯一的,其定義規則通常建議以應用程式包名為前綴的域名,且在后文代碼中有使用;
同時在改標簽中指定屬性android:grantUriPermissions="true",屬性值為 true 時,表示允許對得到的Uri所定位的File檔案授予臨時讀寫權限,
最后在改標簽中增加<meta-data/>標簽,以指定所使用的資料資訊,在該資料標簽中,必須定義其屬性為android:name="android.support.FILE_PROVIDER_PATHS",同時定義屬性android:resource="@xml/file_paths" ,這里的屬性值@xml/file_paths是指向定義的資源檔案file_paths.xml,
在自定義的資源目錄 res 下創建子目錄 xml,該目錄中創建檔案 file_paths.xml ,定義<paths></paths>根標簽以指定要分享的檔案路徑,在根標簽中可以根據要分享的檔案所屬路徑不同而使用不同型別的標簽名作為子標簽插入,子標簽中包含有name和path兩個屬性,分別設定該路徑的別名和子目錄,其中子標簽可用型別與代碼中獲取路徑的對應關系可參考下表,
| 代碼獲取路徑 | 子標簽名 |
|---|---|
context.getFilesDir() |
<files-path> |
context.getCacheDir() |
<cache-path> |
Environment.getExternalStorageDirectory() |
<external-path> |
context.getExternalMediaDirs() |
<external-media-path> |
context.getExternalFilesDir() |
<external-file-path> |
context.getExternalCacheDir() |
<external-cache-path> |
在清單檔案中注冊FileProvider之后,就可以在代碼獲取Uri的地方,與低版本中獲取Uri的方法Uri.fromFile(File file)所不同的是,替換為FileProvider的靜態方法getUriForFile(Context context, String authority, File file),引數 context 是當前應用程式所在的背景關系環境;引數 authority 則是在清單檔案中注冊FileProvider時,屬性android:authorities所表示的值;引數 file 依然是應用程式中要分享的檔案物件,
在使用FileProvider.getUriForFile(Context context, String authority, File file)獲取到Uri之后,需要授權給要使用該路徑的應用程式,在能獲取到背景關系環境Context物件的地方,呼叫grantUriPermission (String toPackage, Uri uri, int modeFlags)方法授權,引數 toPackage 即為要授權使用該路徑的應用程式所在包名;引數 uri 是上文獲取到的路徑定位符物件;引數 modeFlags 是用來表示權限型別的標志位,其值目前包括四種:Intent.FLAG_GRANT_READ_URI_PERMISSION=1的讀權限,Intent.FLAG_GRANT_WRITE_URI_PERMISSION=2的寫權限,Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION=4表示長久授權,和Intent.FLAG_GRANT_PREFIX_URI_PERMISSION=8對匹配引數 uri 的前綴的所有路徑定位符均授權,
在對Uri物件授權之后,也就可以像老版本一樣將其封裝到Intent意圖物件中發送給其他應用了,
檔案接收方
一般地,在分享檔案的接收方,如果只是對接收到的檔案內容做讀寫處理,可以借助java.io.FileDescriptor檔案描述類,使用官方推薦的簡單方式操作,
在接收方收到的Intent意圖物件呼叫getData()方法,得到要接收的檔案所對應的Uri路徑定位符物件,
在可以使用背景關系環境Context物件的位置,呼叫其getContentResolver()方法,獲取背景關系環境中的ContentResolver內容決議類物件,
借助ContentResolver物件的openFileDescriptor (Uri uri, String mode)方法,回傳android.os.ParcelFileDescriptor系統封裝的檔案描述類物件,其中引數 uri 就是上文接收到的路徑定位符物件;引數 mode 則標記了檔案的打開方式,包括只讀權限"r",只寫權限"w",追加寫入權限"wa",讀寫權限"rw"等,
在得到ParcelFileDescriptor物件后,呼叫其getFileDescriptor()方法,可以獲得FileDescriptor檔案描述物件,
最終通過得到的檔案描述物件,創建FileInputStream(FileDescriptor fdObj)構造方法或FileOutputStream(FileDescriptor fdObj)構造方法獲取檔案輸入流物件或檔案輸出流物件,以此操作檔案內容,
還有些特殊需求,對于分享檔案接收方來說,是要對收到的檔案獲取其所在目錄并做進一步操作,也就是需要對得到的Uri路徑定位符物件轉換為File檔案物件,這方面官方并沒有像上文那樣簡單統一的呼叫方式,而需要開發者針對不同的版本做單獨處理,
目標版本級別小于29的應用程式
在Android10即API 29之前的版本中,網上有一堆代碼可參考,其思路就是查詢系統資料庫中不同媒體檔案是否與Uri物件所指向位置匹配,進而確定該Uri物件指向的媒體檔案目錄,在應用程式內借助背景關系環境獲取其媒體檔案所在目錄File物件,從而匹配要查詢的Uri路徑定位符物件,
目標版本級別大于等于29的應用程式
從Android10及API 29版本開始,由于應用程式僅可訪問自己磁區存盤內部的檔案,對于收到的分享檔案路徑定位符Uri物件,也只能先使用上文官方推薦的讀取檔案方式,將Uri物件所指向的檔案先保存一份到自己應用程式內部的私有目錄下,再將這份私有目錄下的保存檔案轉為File物件使用,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/304236.html
標籤:Android
上一篇:位元組跳動內部社招面試寶典意外流出!極致經典,堪稱2021年Android社招面試題解的天花板
下一篇:Swift優化
