Android 的ExternalStorage | 只放拖鞋的鞋櫃

文章推薦指數: 80 %
投票人數:10人

在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,你一定有PrimaryExternalStorage可以用。

所以將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→新聞業的挑戰



請為這篇文章評分?