Android 的ExternalStorage | 只放拖鞋的鞋櫃
文章推薦指數: 80 %
在Android 上要儲存檔案經常會用到Internal 或External Storage,對部分的應用程式來說,常見的需求是「把檔案存到SD card」。
從結論來說,Android ...
Android的ExternalStorage
在Android上要儲存檔案經常會用到Internal或ExternalStorage,對部分的應用程式來說,常見的需求是「把檔案存到SDcard」。
從結論來說,Android並沒有SDcard這樣的概念,ExternalStorage也不一定是外接式儲存裝置。
先有這樣的認知,接著就可以問以下幾個問題
有哪些Storage可以用?
Context與Environment有哪些Storage的API可以用?
有怎樣的權限問題?
有哪些Storage可以用打開API文件就可以看到幾個名詞
InternalStorage
PrimaryExternalStorage
SecondaryExternalStorage
InternalStorageUser不能直接存取,只有app可以。
路徑通常就是data/data/
就是手機內部的儲存空間(internalflash),app的設定檔或是SQLite資料庫就是寫在這裡面。
屬於各個應用程式的私密空間,寫在這裡面的東西,在系統安全無虞的前提下,只有該App可以存取。
雖說不能直接存取,但如果是你自己正在開發的app,所以會安裝debuggable的app,就能透過adb的run-as去存取該目錄
12$adbshell$run-as
所以將Primaryexternalstorage當成SDcard一定會被搞得很混亂。
正如前述,ExternalStorage不一定是外接式儲存裝置。
把External換成Shared就會變得容易理解:PrimarySharedStorage
相較於Internalstorage專門儲存一些app私密的資料,有時我們會想存下一些可供分享的檔案,好比程式產出的圖片、照片,或是錄下的聲音,透過網路抓下來的檔案…等等。
這些檔案想要被其他程式使用,系統提供了一個非Internal的Stroage,這就是ExternalStorage。
PrimaryExternalStorage可能是sdcard,也可能是系統自己從internalflash分割一塊出來的空間。
SecondaryExternalStoragePrimary以外,剩下的就是SecondaryExternalStorage,SD-card或是外接式USB硬碟,往往都是這一類。
早期的API並沒有提供存取SecondaryExternalStorage的方法,後來漸漸提供了稍微受限的存取方式,後面再講。
TraditionalStorageandAdoptableStorageAPI上面看不見,但可以從文件裡面看到這個名詞。
TraditionalStorage就是前述那些可以拔插置換的傳統儲存裝置,相對的名詞則是AdoptableStorage。
買了手機卻擔心internalflash不夠大?在Android6.0(M,API23)之後提供了這個功能。
有些手機的SD卡插槽設計得難以拔插,實務上可以視為半永久的儲存裝置。
在這種插槽裝上SD卡,系統就會詢問是否要將其「收養」,變成AdoptableStorage
adopt之後系統便將此storage重新格式化、加密,接著把Primarysharedstorage的東西搬移到上面,開始把這顆裝置當成Priamrysharedstorage來使用。
也因為會被加密,所以沒辦法拔下來給其他裝置使用。
API使用Context跟Environment都有storage相關的API,乍看會有點混亂,表列之後就清晰許多。
Context是跟App相關的東西,Environment是跟系統相關的東西。
在AndroidFroyo之前,app只能拿到internal的目錄來放檔案,想要分享檔案,就要取得系統的primaryexternalstorage的最上層目錄,自己手動建立目錄把檔案放進去。
後來才透過統一的API來給各個App放置自己的cache或是files;所以Context傳回來的都是「專屬於此App的相關目錄」
相較之下,Environment傳回來的就是externalstorage的最上層目錄,或是共用的Publicdirectory
Context.getCacheDir()-取得/data/data//cache
Context.getFilesDir()-取得/data/data//files
ContextCompat.getExternalFilesDirs(Contextcontext,Stringtype)
回傳application-specific的目錄,專屬於這個app,app移除的時候會一併砍掉這個目錄
存取不需要Permission
回傳的File[],第一筆是位在Primaryexternalstorage上面的目錄
ContextCompat.getExternalCacheDirs(Contextcontext)
Environment.getExternalStorageDirectory()
回傳primaryexternalstoragetoppath
若有複數使用者(UserManager),每個user看到的externalstorage不一樣
砍App的時候不會把這裡面的一起砍掉
Environment.getExternalStoragePublicDirectory(Stringtype)
回傳primaryexternalstorage相對應type的目錄
目錄可能不存在,要自己呼叫File.mkdirs()
歷史共業SDcard的歷史從蠻荒時代的1.5就有了,看完一些文章的整理如下
最早開始externalstorage是一個能夠expose給PC的Volume
可能是internalflash上面的一塊空間,也可能是sdcard。
唯一的規則是,它若沒有被PC拿去用,就要被預設掛載起來
單一的permission就可以對整顆externalstorage的任何位置讀寫
Froyo2.2(Apilevel8)之後
permission跟之前一樣
加入了applicationspecificdirectory的概念-/Android/data/[Packagename]
但是移除app的時候,會順便連這個目錄一起移除
若檔案被拿到這個目錄之外,則不會被移除
在早期的時候,系統廠可能自己弄一個primaryexternalstorage及數個secondaryexternalstorage,但此時的API都沒有開放存取secondary。
Samsunggalaxy手機就是這樣,而sdcard都是secondary,所以API都無法存取。
只有系統的app能夠把資料存在上面
Kitkat4.0(Apilevel19)之後
開始能夠存取secondaryexternalstorage。
此時primaryexternalstorage的權限跟以前一樣,secondary的權限規則就不一樣
還是沒有api能夠存取到secondary上,application-specific以外的目錄,好比secondary的根目錄
所以secondary上面的/DCIM/Picture都拿不到囉
AndroidN7.0(Apilevel24)之後
Storage的邏輯上沒什麼大改變。
主要是增加Scopeddirectoryaccess(限定範圍目錄存取)
存取權限Android上面的storage讀取權限,主要是靠Linux上面常見的檔案系統與UID/GID來控管,以FUSE提供檔案存取的介面。
以前是在AndroidManifest.xml裡面宣告了權限,安裝App的時候就批准所有權限。
後來在6.0之後則是執行到需要的時候,才會向使用者要權限
取得了READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE權限之後,便把該app加入sdcard_r或sdcard_w的群組。
所以系統只要設定好各個storage上面各個目錄的權限與群組,就可以控管該app能不能碰檔案了。
Froyo2.2(Apilevel8)之後
/storage/sdcard底下的檔案,所屬的group是sdcard_rwowner是root
Android/data/[PackageName]也是一樣的權限
WRITE_EXTERNAL_STORAGE會讓app加入sdcard_rw這個group,所以就拿到完整的讀寫權限
READ_EXTERNAL_STORAGE會拿到sdcard_r的權限,但是在4.3之前都沒用
Kitkat4.0(Apilevel19)之後
/storage/sdcard底下的檔案所屬的group是sdcard_r
取得READ_EXTERNAL_STORAGE就能加入sdcard_rgroup,能讀取volume上所有的檔案
取得WRITE_EXTERNAL_STORAGE則會加入sdcard_r與sdcard_rw
非owner非groupmember者,在這volume上的read權限被拿掉了
app-specific-dir底下的group也屬於sdcard_r,但是檔案的owner換成app-id,所以app存取自己的目錄時不需要任何權限
Primary與Secondary的目錄權限設定上也略有不同,所以就會有讀寫能力不完全相同的情況,表格整理之後就是這樣
Action
Primary
Secondary
讀最上層目錄
R
R
寫最上層目錄
W
N
讀自己的DataDirectory
Y
Y
寫自己的DataDirectory
Y
Y
讀他人的DataDirectory
R
R
寫他人的DataDirectory
W
N
R=需要ReadPermission,W=需要WritePermission,Y=Always,N=Never
Reference
OntheEdgeoftheSandbox:ExternalStoragePermissions
AndroidSecurity:AnOverviewOfApplicationSandbox
DivingintoSDCardFS:HowGoogle’sFUSEReplacementWillReduceI/OOverhead
2017-08-21
geek
Android
ViewPager與FragmentStatePagerAdapter←Prev
Next→新聞業的挑戰
延伸文章資訊
- 1External Storage Tutorial In Android Studio With Example
In this tutorial we gonna study about storage of data/files in android external storage or you ca...
- 2[Android] 12-4 External storage - 給你魚竿- 痞客邦
Android外部儲存空間通常比較大像是SD卡需要WRITE_EXTERNAL_STORAGE的權限和Internel其實很像只是位置不同只要記得private的是在/storage/SD卡名稱.
- 3Data and file storage overview | Android Developers
Android provides two types of physical storage locations: internal storage and external storage. ...
- 4Android Internal vs External Storage | COBE
Android defines two permissions related to storage: READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STOR...
- 5Android Internal and External storage 讀寫檔案 ... - 隨意窩
http://blog.tonycube.com/2012/03/android-internal-and-external-storage.html1. 存在手機還是SDcardAndroid...