最近(大概4月中旬)收到華為市場官方的郵件,要求APP端能在五月底之前適配完最新的Android Q系統(tǒng).在這個時間段內(nèi)穿插了兩個項目需求版本,Android Q
的版本也從Bate1
升級到了Bate3
.
Android Q版本的更新還是相當(dāng)大的,在Bate1
版本如果未適配.即使在targetSdkVersion
不是Q的情況下,可能應(yīng)用程序依然不能正常運行.可能是考慮這個操作過于激進(jìn),最新的Bate3
版本把外部存儲沙箱化的過程,繼續(xù)往后延遲一個版本Android至11.大概就是要留出一個版本時間讓大家進(jìn)行適配.
在瀏覽華為官方給出的適配指導(dǎo)文檔以及Android官方的Android Q版本介紹后,大概有一下幾個比較重要的改動:
存儲權(quán)限(外部存儲的沙箱化與iOS一樣的體驗)
在Bate1版本中,Google官方文檔說明,沙盒化是必然在Q版本生效的
可以使用adb shell sm set-isolated-storage on
打開系統(tǒng)的全局沙箱化,并表示在后續(xù)的版本中會逐漸默認(rèn)開啟.對于從低版本升級到Q的系統(tǒng),如果APP的目標(biāo)平臺低于Q,則默認(rèn)不會沙箱化該APP,但是一旦重裝就會受到這個約束.
不過在Bate3中又做了改動,沙箱化的改動不再是全局直接生效,而是針對每個APP的在清單文件中,通過<application android:allowExternalStorageSandbox = “false” ... >
這個字段配置生效,其中如果TargetSDKVersion是Q的話,那么這個值默認(rèn)是true.(在官方文檔中表示這個"allowExternalStorageSandbox"關(guān)鍵字只是暫定的,可能后續(xù)會改動).
針對沒有外部存儲的設(shè)備,如果想要做測試的話,可以使用adb shell sm set-virtual-disk true
指令設(shè)置虛擬磁盤測試.
沙箱化生效后,針對APP訪問外部存儲就大致分了三個部分.
1.訪問自己沙箱內(nèi)的文件
無需任何權(quán)限.自己沙箱的目錄地址是
Context.getExternalFilesDir()
,如果想要保存一張圖片,那么他的地址目錄,應(yīng)該是:Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
.其中訪問自己沙箱內(nèi)的文件,依然可以使用Java的File系統(tǒng).直接使用路徑名.但是如果不是自己沙箱內(nèi)的文件,返回的文件路徑將不能直接使用.
2.訪問外部的公共多媒體文件
在
Bate1
版本中,Google新增了三個權(quán)限READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO
表示訪問media的權(quán)限,取代了之前的READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE
.兼容的話,老版本后者的權(quán)限會在Q平臺默認(rèn)轉(zhuǎn)換成前三個新權(quán)限.針對后三個新權(quán)限,其中讀取Images和Video是一體的,申請一個通過,那么另一個也白給.對于多媒體文件,一個APP只能寫入或者刪除自己插入的文件,其他APP插入的,不能修改.除非APP本身是系統(tǒng)默認(rèn)應(yīng)用.比如APP是默認(rèn)圖庫,那么他可以刪除或者修改其他APP插入的圖片.如果有修改其他APP多媒體文件的需求,要有限申請默認(rèn)的角色權(quán)限.
不過在
Bate3
版本,google又退回了原來的權(quán)限.整體上就是使用MediaStore的API做多媒體文件的訪問.3.訪問外部的下載文件
Google在4.4版本就已經(jīng) 有一套Storage Access Framework(
SAF
) 的 DocumentFile API 進(jìn)行讀寫.通過這種形式還可以持續(xù)獲得某個文件夾的讀取權(quán)限.google說明使用SAF的API可以讀取上邊三種存儲,而不需要任何權(quán)限.
4.訪問其他APP的沙箱文件
類似于分享功能,如果我們需要分享一張自己的沙箱內(nèi)的圖片,到微信或者其他平臺.那么因為沙箱的問題,會造成該文件無法找到.這個解決方案類似于Android7.0上的FileUriExposedException,需要使用V4包提供的FileProvider,將file的傳遞轉(zhuǎn)換為content的傳遞,然后同時賦予暫時的讀權(quán)限.分享的功能,我們使用的是SDK,據(jù)觀察微信的分享SDK用的就是FileProvider的形式.
以上就是Android Q關(guān)于外部存儲的改動,還有諸多細(xì)節(jié)以及新的特性沒有一一列出,畢竟我們主要是想APP的正常運行,這部分對于我們APP的影響,需要檢查的位置主要有:
1.分享 2.修改頭像時圖片選擇 3.上傳評價時圖片的選擇 4.將海報存儲到本地相冊.
設(shè)備唯一標(biāo)識符
AndroidQ中去掉了READ_PHONE_STATE
權(quán)限,取而代之的是一個系統(tǒng)級別的權(quán)限:READ_PRIVILEGED_PHONE_STATE
,所以Android Q平臺無論如何也不會再有IMEI和序列號SerialNumber
1.對于目標(biāo)平臺<Q并且沒有申請READ_PHONE_STATE
權(quán)限,或者目標(biāo)平臺>=Q,嘗試獲取DeviceId或拋出SecurityException.
2.對于目標(biāo)平臺<Q并且申請READ_PHONE_STATE
權(quán)限,那么讀取deviceId(IMEI)為null.
3.通過Build.getSerial()獲取到的值會是unknown.
針對這個變化,需要重新整理APP內(nèi)生成設(shè)備唯一Id的方法:Google官方的指導(dǎo)方法,不過這個方法可能同一設(shè)備不唯一.ANDROID_ID的獲取一直不受影響. 不過這個值可能因為手機(jī)廠商的設(shè)置導(dǎo)致不可用.不過設(shè)備唯一Id一直也沒有100%的解決方案,可以根據(jù)實際情況定奪.
后臺定位權(quán)限
Android Q中新增了后臺定位權(quán)限ACCESS_BACKGROUND_LOCATION
,之前的ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION
則表示用戶請求前臺定位權(quán)限.那么Android的定位權(quán)限對話框就表現(xiàn)的iOS一致.
其中對于老版本,申請了
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION
后,系統(tǒng)會默認(rèn)幫你申請ACCESS_BACKGROUND_LOCATION
,即對話框所示.PS:如果用戶拒絕了后臺定位,那么就只能通過啟動前臺服務(wù)來進(jìn)行前臺定位.而且前臺服務(wù)目標(biāo)需要設(shè)置為locaiton.
foregroundServiceType=“l(fā)ocation”
事實上,根據(jù)適配指導(dǎo),Android Q的后臺定位會有比較大的限制,大概30m一次,如果是導(dǎo)航,啟動前臺服務(wù)依然是必須的.PPS:AndroidQ這里對于應(yīng)用前臺的定義就是有沒有可見的Activity或者前臺service.這一點與Android O中,后臺啟動服務(wù)的后臺又有不一樣.具體可以參考Android 8.0后臺啟動服務(wù).
我們的APP其實對于定位不需要做任何改動.因為不需要后臺定位權(quán)限.
禁止應(yīng)用后臺彈頁面
AndroidQ在開發(fā)者選項中:關(guān)閉允許系統(tǒng)執(zhí)行后臺活動開發(fā)者選項即可啟用限制.只能通過用戶的交互來打開活動,對應(yīng)的解決方法是開啟一個全屏的通知.
這個一般針對電話,鬧鐘此類應(yīng)用.
Android Q非SDK接口限制
與Android P 類似,具體的分析方法,可以參考官方的工具.
我們APP使用較少,主要是三方SDK的使用.
[參考文檔]
https://juejin.im/post/5cad5b7ce51d456e5a0728b0#heading-10
https://developer.android.google.cn/preview/privacy/checklist
https://feng.moe/archives/47/?replyTo=23