前一篇博客中介紹了Android6.0運行時權限渠缕,最近遇到這么一個情況仰楚,就是一個App以前都是在SD卡根目錄直接新建了一個XXX/image/目錄岔霸,來保存圖片緩存的薛躬,但是如果適配到Android6.0,我們就需要彈出對話框給用戶呆细,來申請WRITE_EXTERNAL_STORAGE權限型宝,如果僅僅是緩存圖片為了提高加載速度,對于一個小白用戶來講絮爷,好像并不是什么值得讓他授權的理由趴酣。。坑夯。
下面記錄一下我是怎么處理的岖寞,其實這次處理也不能叫做Android6.0權限適配了,不過對于WRITE_EXTERNAL_STORAGE這個權限而言柜蜈,的確有一些需要注意的地方(坑)使我們以前沒有關心的仗谆。
首先,App在手機上保存文件或者緩存數據時跨释,我認為應該遵守以下幾點:
1.不要隨意占用用戶的內置存儲胸私。
2.不要隨意在SD卡上新建目錄,應該放置自己應用包名對應的擴展存儲目錄下鳖谈,卸載App時可以被自動清除岁疼。
3.對占用的磁盤空間有上限,并按照一定的策略進行清除缆娃。
在Android系統(tǒng)中捷绒,根據調用的系統(tǒng)API接口,有3種目錄可以給我們寫入文件:
1.應用私有存儲(內置存儲)
獲取方式:
Context.getFileDir():獲取內置存儲下的文件目錄贯要,可以用來保存不能公開給其他應用的一些敏感數據如用戶個人信息
Context.getCacheDir():獲取內置存儲下的緩存目錄暖侨,可以用來保存一些緩存文件如圖片,當內置存儲的空間不足時將系統(tǒng)自動被清除(然而具體多大崇渗,清除時的策略我也沒查到字逗。京郑。)
絕對路徑:
Context.getFileDir():/data/data/應用包名/files/
Context.getCacheDir():/data/data/應用包名/cache/
寫權限:不需要申請
這是手機的內置存儲,沒有root的過的手機是無法用文件管理器之類的工具查看的葫掉。而且這些數據也會隨著用戶卸載App而被一起刪除些举。這兩個目錄其實就對應著設置->應用->你的App->存儲空間下面的清除數據和清楚緩存,如下圖所示俭厚。
2.應用擴展存儲(SD卡)
獲取方式:
Context.getExternalFilesDir():獲取SD卡上的文件目錄
Context.getExternalCacheDir():獲取SD卡上的緩存目錄
絕對路徑:
Context.getExternalFilesDir():SDCard/Android/data/應用包名/files/
Context.getExternalCacheDir():SDCard/Android/data/應用包名/cache/
寫權限:
API < 19:需要申請
API >= 19:不需要申請
既然是SD卡上的目錄户魏,那么是可以被其他的應用讀取到的,所以這個目錄下挪挤,不應該存放用戶的敏感信息叼丑。同上面一樣的,這里的文件會隨著App卸載而被刪除扛门,也可以由用戶手動在設置界面里面清除鸠信。
3.公共存儲(SD卡)
獲取方式:Environment.getExternalStorageDirectory()
絕對路徑:SDCard/你設置的文件夾名字/
寫權限:需要申請
如果我們的App需要存儲一些公共的文件,甚至希望下載下來的文件即使在我們的App被刪除之后论寨,還可以被其他App使用症副,那么就可以使用這個目錄。這個目錄是始終需要申請SD寫入權限的政基。
有了前一節(jié)的介紹,其實很清楚了沮明,根據最開始提到的規(guī)則辕坝,其實如果僅僅是做了簡單的圖片緩存工作,那么我們應該把圖片緩存放到/data/data/應用包名/cache/或者SDCard/Android/data/應用包名/cache/荐健,因為在6.0系統(tǒng)(API > 23)時酱畅,不需要申請權限就可以向這兩個目錄寫入文件。而且/data/data/應用包名/cache/目錄江场,是內置存儲的應用私有緩存目錄纺酸,在系統(tǒng)空間不夠時還會被自動清除,對于圖片緩存來講也是一個不錯的管理策略址否,不過谷歌建議我們最好還是自己實現緩存清除管理餐蔬,例如用DiskLruCache。
實際上我們可以在API >= 19(不一定非要大于23)時佑附,就可以在不需要申請權限的情況下把文件放到這兩個目錄了樊诺。如果開發(fā)的時候足夠規(guī)范,即使在API < 19時音同,我們申請到寫入權限后词爬,我們也應該手動創(chuàng)建和前面相同的目錄,使得應用存儲數據目錄統(tǒng)一化权均。
好了,是不是現在不用SD卡上創(chuàng)建的目錄XXX/image/恋沃,直接改為改為SDCard/Android/data/應用包名/cache/image/就OK了橡类?還真不完全是這樣的。芽唇。。
取劫?匆笤??納尼谱邪?炮捧??惦银?
通常我們開發(fā)App時會設置targetSDKVersion=23時咆课,并同時向前兼容,還會設置minSdkVersion=14表示支持的最低系統(tǒng)版本是Android4.0(API = 14)扯俱。也就是說我們的build.gradle一般長這樣:
android {
compileSdkVersion 23
buildToolsVersion"23.0.2"
...
defaultConfig {
applicationId"xxx.xxx"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName"1.0"
}
...
}
但是前面我們說過书蚪,通過Context.getExternalCacheDir()接口獲取應用擴展存儲目錄時,只有在API >= 19時才不需要申請權限迅栅。也就是說如果是上面這種兼容到API 14的應用殊校,還是需要在AndroidManifest.xml中注冊WRITE_EXTERNAL_STORAGE權限的。
前一篇博客Android6.0運行時權限簡介知道读存,如果在AndroidManifest.xml文件里注冊過WRITE_EXTERNAL_STORAGE为流,當App運行在一臺6.0的設備時,即使你的App全程都沒有調用requestPermissons來申請權限让簿,用戶還是可以在Android6.0系統(tǒng)上進入設置->應用->你的App->權限里面敬察,取消存儲空間這一個權限。記住是運行在6.0系統(tǒng)的機器上尔当,這是關鍵莲祸,因為低于6.0的系統(tǒng)根本沒有這個設置。
如下圖所示椭迎,只要在manifest里面注冊了虫给,就可以動態(tài)取消之!
此時會發(fā)生什么侠碧?抹估??此時你的圖片在6.0機器上也就沒法緩存嘍弄兜。药蜻。/(ㄒoㄒ)/~~
為啥按墒健?6.0機器上语泽,我不是不需要申請權限就可以獲得寫入SDCard/Android/data/應用包名/cache/目錄嗎贸典?實際測試時發(fā)現,當用戶取消了權限之后踱卵,SDK接口中與File相關的API全部都返回空了廊驼,于是我們就沒法寫文件了。
其實我們還需要做的是:
將AndroidManifest.xml文件中的
改為
android:maxSdkVersion="18"/>
表示只在API <= 18時惋砂,才申請WRITE_EXTERNAL_STORAGE權限妒挎。這樣用戶就無法在Android6.0系統(tǒng)的設置下面看到存儲空間權限的開關,當然也就無法關閉它了西饵,如下圖所示酝掩。