Android 12 保姆級適配指南來啦!
之前還推動過一篇,歡迎一起查閱。
背景
近期,Google Play向所有的應用開發者傳送了一封郵件,郵件中明確了應用將目標API級別更新為Android 12的最後期限。
這表示,Android 12的適配工作不得不提上日程了。
本著將改動最小化的原則,建議在開始適配之前,可以將此次需要適配的一系列行為變更,按照對自身專案的影響程度,先進行優先順序劃分,並依據此優先順序去分批、逐步完成適配工作。
該如何進行劃分呢?可能具體到每個人的專案情況都有所不同,這裡提供一下筆者專案的適配任務優先順序劃分標準,供其他開發者參考:
P0:功能異常
指明確影響到了App功能的正常使用,甚至導致App無法正常啟動或者崩潰率直線上升的行為變更。
P1:體驗下降
指雖不影響功能正常使用,但可能導致獲取資料的準確度下降,或者需要增加操作步驟進而影響使用者體驗的行為變更。
P2:可選優化
指對App本身沒有什麼實質影響,但做好適配後可以增強App健壯性或使用者體驗的行為變更。
接下來,我們就以上面劃分好的優先順序標準,來開始對Android 12的適配工作。
1
影響所有App的行為變更 P0:功能異常
1. 應用啟動畫面
造成影響
簡單講,就是從Android 12開始,所有的App在每次啟動時(特指冷啟動與溫啟動),系統都會為我們加上一個預設的啟動畫面,如下所示:
該啟動畫面主要由以下4個元素組成,分別為:
(1) 應用圖示 :可以是靜態或動畫形式。預設情況下,使用Launcher圖示。
(2) 圖示背景 :可選,在圖示與視窗背景之間需要更高的對比度時很有用。
(3) 前景遮罩 :可選,前景的 ⅓ 將被遮蓋。
(4) 視窗背景 :不透明的單色,預設是所設定主題的 windowBackground 。
雖然這個啟動畫面允許我們一定程度的自定義,但總體都無法跳脫出以上4個元素,且無法去除。如果不做任何處理,加上我們原有的閃屏頁和廣告頁,視覺上會有多個啟動畫面。
適配方案
方案1(懶人專用): 設定除視窗背景之外的元素都為透明。
處理後的效果就是,在啟動時會先顯示由所設定主題的 windowBackground 指定的純色背景,即與大多數開發者之前為了解決啟動黑屏/白屏問題所採用的方法一致。
方案2(常規做法): 改用SplashScreen API定製系統啟動畫面。
缺點就是可定製程度低,可能無法滿足產品的需求;
如果總體的效果可以接受,那麼接下來要處理的就是對原有閃屏頁的取捨,以及與原有廣告頁的畫面銜接了。
但如開頭所言,我們的目標是 將改動最小化 ,那麼,原有閃屏頁該幹嘛還是讓它幹嘛,初始化也好,路由也罷,邏輯不變,要求只是不再顯示而已。
具體做法如下:
1. 新增 SplashScreen compat 庫。
2. 在閃屏頁呼叫 SplashScreen#setKeepOnScreenCondition{ true } 使得預設的啟動畫面持續覆蓋原有的閃屏頁,直到廣告頁開始顯現時,才呼叫 SplashScreen#setKeepOnScreenCondition{ false } 讓頁面重新顯示,以此實現平穩過渡。
2. 麥克風和攝像頭切換開關
造成影響
簡單講,就是從Android 12開始,使用者可以通過狀態列下拉選單中兩個新增的切換開關選項,一鍵啟用/停用攝像頭和麥克風使用許可權。
請注意,這裡的「使用許可權」針對的是裝置上的所有App,是全域性的,不要和Android 6.0的「執行時許可權」混淆。
而兩者在具體表現上也有所不同,在實際操作中:
• 當關閉攝像頭使用許可權後,畫面錄製將繼續進行,但 只會收到空白畫面 ;
• 當關閉麥克風使用許可權後,聲音錄製將繼續進行,但 只會收到無聲影片 。
適配方案
儘管官網上提供了檢查裝置是否支援麥克風和攝像頭切換開關的API,也就是檢查狀態列下拉選單是否有這兩個開關選項,然而這對於我們實際的適配工作幾乎沒有什麼卵用:
SensorPrivacyManager 類倒是有提供檢查指定切換開關是否開啟的API,但由於是系統許可權,因此即使是通過反射形式也無法呼叫:
所幸的是,如果使用者主動關閉了攝像頭或麥克風的使用許可權,那麼當下次App再需要啟動攝像頭或麥克風時,系統就會提醒使用者,相關硬體的使用許可權已關閉,並申請重新開啟:
因此,對於此行為變更的適配,我們要做的,就是驗證在使用者主動關閉了攝像頭或麥克風使用許可權後,App的相關功能是否受影響,至於監聽/提示/重新開啟的工作則交給系統幫我們完成即可。
2
影響目標API級別為Android 12的App的行為變更 P0:功能異常
1. 更安全的元件匯出
造成影響
簡單講,就是以Android 12為目標平臺的App,如果其包含的四大元件中使用到了Intent過濾器(intent-filter),則必須顯式宣告 android:exported 屬性,否則App將 無法在Android 12及更高系統版本的裝置上安裝 :
適配方案
這裡要區分兩種情況:
1. 如果是自身專案使用到了,則按要求顯式宣告即可;
2. 如果是依賴的第三方庫使用到了,那就比較麻煩了。且不說等待第三方庫更新的過程很被動,如果該庫還已停止維護了,那就芭比Q了。
但眾所周知,Android Studio Project在打包時是會合並多個Module的 AndroidManifest.xml 檔案的,基於這種情況,我們就可以通過編寫Gradle指令碼,在打包過程中檢索合並後的 AndroidManifest.xml 檔案中,所有使用到了Intent過濾器但沒有宣告exported屬性的元件,動態地為其加上exported屬性。
具體的Gradle指令碼 已經有人寫過了,這裡就不再貼出了:
http://events.jianshu.io/p/1913b48f2dad
2. 待處理 intent 可變性
造成影響
簡單講,就是以Android 12為目標平臺的App,在構建PendingIntent時,需要指定Flag為 FLAG_IMMUTABLE (建議)或 FLAG_MUTABLE 二者之一,否則App將崩潰並出現以下警告。
適配方案
但同樣可能出現第三方庫的程式碼未正確指定Flag的問題,目前除了等待第三方庫更新之外似乎也沒有更好的措施。
3. 前臺服務啟動限制
造成影響
簡單講,就是以Android 12為目標平臺的App,如果嘗試在後臺執行時啟動前臺服務( startForegroundService ),則會引發 ForegroundServiceStartNotAllowedException 異常( 某些場景除外 ):
http://developer.android.com/guide/components/foreground-services#background-start-restriction-exemptions
適配方案
分兩步走:
1. 檢查App是否有在後臺啟動前臺服務的行為
可在Terminal終端執行以下adb命令,該命令會監控你的App是否有在後臺啟動前臺服務的行為,一旦有此行為,就會在通知欄推送一條提醒,定位到觸發此行為的程式碼處:
adb shell device_config put activity_manager \ default_fgs_starts_restriction_notification_enabled true
2. 考慮改用WorkManager的加急工作來執行後臺任務
4. 精確的鬧鐘許可權
造成影響
簡單講,就是以Android 12為目標平臺的App,如果使用到了AlarmManager來設定定時任務,並且設定的是精準的鬧鐘(使用了 setAlarmClock() 、 setExact() 、 setExactAndAllowWhileIdle() 這幾種方法),則需要確保 SCHEDULE_EXACT_ALARM 許可權宣告且開啟,否則App將崩潰並出現以下警告:
適配方案
分三步走:
1. 在 AndroidManifest.xml 清單檔案中宣告 SCHEDULE_EXACT_ALARM 許可權。
2. 判斷是否具有設定精確鬧鐘的許可權。
3. 開啟鬧鐘和提醒許可權授權頁面,進行授權。
5. 通知 trampoline 限制
造成影響
簡單講,就是我們之前在配置通知(Notification)的點按行為時,可能會通過PendingIntent來啟動一個Service或BrocastReceiver。而以Android 12為目標平臺的App,如果嘗試在Service或BrocastReceiver中內呼叫 startActivity() ,系統會阻止該Activity啟動,並在 Logcat 中顯示以下訊息:
適配方案
分兩步走:
1. 排查哪個Service或BrocastReceiver有此行為
可在Terminal終端執行以下adb命令,該命令會在你點按通知後,識別哪個Service或BrocastReceiver呼叫了 startActivity() ,並輸出相關資訊到Logcat,可以通過關鍵字“NotifInteractionLog”進行過濾:
adb shell dumpsys activity service \ com.android.systemui/.dump.SystemUIAuxiliaryDumpService
2. 考慮在配置通知(Notification)的點按行為時選擇直接啟動Activity
P1:體驗下降
1. 大致位置
造成影響
做過定位功能的Android開發者都知道,Android提供了兩種不同精確度的位置許可權,分別是:
• A CCESS_COARSE_LOCATION (大致位置)
提供裝置位置的估算值,將範圍限定在大約 1.6 公里(1 英里)內。
• ACCESS_FINE_LOCATION (確切位置)
通常將範圍限定在大約 50 米(160 英尺)內,有時精確到幾米(10 英尺)範圍以內。
而在以Android 12為目標平臺的App上,當App嘗試請求 ACCESS_FINE_LOCATION 許可權時,系統許可權對話方塊會提供兩個選項,即允許App獲取確切位置,還是僅允許獲取大致位置。
也即是說,給了使用者拒絕提供確切位置的權力,一旦使用者拒絕,這種情況下App就只能獲取到大致位置了。
適配方案
雖然使用者可能拒絕提供確切位置,但我們依舊可以再次請求升級到確切位置:
當然,在再次請求前提供一個適當的解釋說明是一個比較好的做法,App本身也要做好只能獲取到大致位置時的業務降級處理。
2. 應用休眠
造成影響
簡單講,就是以Android 12為目標平臺的App,如果使用者有長達幾個月的時間沒有開啟過你的App,那麼你之前申請的所有執行時許可權都會被重置為未授權狀態,即使再次開啟也無法恢復,需要重新申請。
適配方案
基本上,只要你的App之前已經做好執行時許可權的的判斷和申請,那對你的App就幾乎沒什麼影響。如果還是想穩妥的測試一下,可以用Terminal終端執行adb命令,手動觸發應用休眠:
http://developer.android.com/topic/performance/app-hibernation#manually-invoke
3. 自定義通知
造成影響
簡單講,就是如果之前App中的通知(Notification)中使用到了自定義內容檢視,並且該檢視是填滿整個通知區域的。那麼當App以Android 12為目標平臺後,檢視將不再能填充整個區域,而是會被縮小到某個固定範圍:
另外,所有通知現在都變成了可展開的,如果你之前設定自定義內容檢視時使用的是 setCustomContentView 方法,那你現在則還需要另外再使用 setBigCustomContentView 方法來設定展開狀態的樣式,以確保通知在收起狀態和展開狀態的樣式能統一。
適配方案
確認被縮減顯示範圍後的自定義內容檢視樣式是否能接受,若不能接受,則根據實際需要調整即可。
3
演示Demo這邊提供了一個Demo,可以幫助我們通過實際操作,快速理解以上行為變更的具體表現,並且由於是輕量級的Demo,所以也方便我們進行改動,快速驗證適配方案的效果:
http://github.com/madchan/SupportAndroid12
最後推薦一下我做的網站,玩Android: wanandroid.com ,包含詳盡的知識體系、好用的工具,還有本公眾號文章合集,歡迎體驗和收藏!
推薦閱讀 :
點選 關注我的公眾號
如果你想要跟大家分享你的文章,歡迎投稿~
┏(^0^)┛明天見!
- Android 12 保姆級適配指南來啦!
- 找出Android卡頓的元凶——全面揭祕渲染機制所造成的卡頓因素~
- 分享一下適配 Android 12 遇到的坑
- Stack Overflow上最熱門的8個Kotlin問題
- APP啟動優化,監控與實踐一起來!
- Android帶你實現增量更新!
- 記一次 Android 線上 OOM 的排查過程
- 把Compose 、MVI新技術合起來, 快速實現 一個玩 Android App
- Android 13種 Drawable,全面掌握!
- 吹爆系列:大廠是如何幹掉OOM的?
- 玩Android又又又更新啦!跟大家彙報一波~
- Android MVC , MVP, MVVM 架構案例學習
- 新技術又又又又叒叒叒來了?
- APP安全漏洞、隱私合規,免費測試!
- 奇怪的知識:ActivityRecord、TaskRecord、ActivityStack、ActivityDisplay用處?
- Android 開發太難了:總聽說的AGP,背後到底做了什麼?
- 適配到Android 12,全版本支援儲存圖片到相簿方案
- “重新設計” Android View 體系?
- 呼叫API就可以完成的需求,為什麼總被追著原理問個不停?
- 讓自定義View更加優雅的一個技巧!