大家好,我是皇叔,最近開了一個安卓進階漲薪訓練營,可以幫助大家突破技術&職場瓶頸,從而度過難關,進入心儀的公司。
詳情見文章:沒錯!皇叔開了個訓練營

Android 10 首次引入了全局返回手勢,但直到返回觸發才能看到目標上層畫面。13 針對該特性進行了優化,即返回觸發之前可以預覽上層畫面。同時徹底廢棄了返回鍵相關的 API,這將對現有的 App 邏輯產生巨大的影響!
前言Android 13 針對包括手機、大屏、摺疊屏等 Android 設備推出了可預見型返回手勢(Predictive Back Gesture)特性。該特性將便於用戶在返回完成之前可以先預覽到目標畫面或結果,這樣的話可以允許他們決定是否要繼續返回或者放棄並停留在當前畫面。

另外引入關於KEYCODE_BACKKeyEvent 相關的一系列變更。
為節省篇幅和統一認識,後續的相關描述將按照如下規則簡稱:


後續將按照如下幾個方面去闡述:
簡單來說會產生如下影響:
備註:無關TargetSDKVersion,運行在 13 上只要支持新返回導航均會受收到如上的影響。
KEYCODE_BACK 非推薦準確含義是 13 上一旦開啟新返回導航支持,無論是 Back Gesture 的觸發還是 Back KeyButton 的點擊,App 均無法監聽到 KEYCODE_BACK 事件。即相關的如下 API 將無法被回調:
除了上述提到的具體變更以外,所有 KEYCODE_BACK 的相關邏輯都得測試一下是否存在問題,比如容易忽略的 View、Dialog$Builder。
簡單來說,檢查下現有代碼是否用到了如下 API:
大多數 App 都會選擇自定義返回導航,可選的方式包括 SDK 的原生 API 和 AndroidX 的 Callback API。依據這些情況的不同、App 適配的意願不同,適配的方案也不一樣。
沒有自定義返回導航的場景加入新返回導航的支持即可,具體見《4.1 加入新返回導航的支持》章節。
自定義返回導航的場景需要按照現有 API 是否接入了 AndroidX 的 OnBackPressedDispatcher 進行分情況適配。
Manifest 中針對新返回導航特性引入的屬性enableOnBackInvokedCallback默認是 false,即默認不支持該特性,支持的話需要聲明為 true。
<application...android:enableOnBackInvokedCallback="true"...>...</application>實測發現:即便聲明成了 false,但如果代碼中殘存了 13 的新 API(比如 OnBackInvokedCallback)的使用,仍會導致新返回導航發生作用。
也就是說,不支持的話,就不要使用任何新的返回相關 API。
4.2 關閉新返回導航的支持正如上面所述,按照如下即可關閉對新返回導航的支持:
對於已使用 AndroidX 返回 API 的 App 只需開啟新返回導航的支持,其他的適配工作交由 AndroidX 框架來完成。
Supporting the predictive back gesture requires updating your app, using theOnBackPressedCallbackAppCompat 1.6.0-alpha03(AndroidX) or higher API.
筆者按照官方說明將AppCompat包升級到了1.6.0-alpha03。
dependencies{implementation'androidx.appcompat:appcompat:1.6.0-alpha03'}使用其提供的OnBackPressedCallbackAPI 監聽 Activity 的 Back 操作如下:
classBackKeyTestActivityAppCompat:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){...onBackPressedDispatcher.addCallback(object:OnBackPressedCallback(true){overridefunhandleOnBackPressed(){Log.d("BackGesture","Activity#handleOnBackPressed()")}})}overridefundispatchKeyEvent(event:KeyEvent):Boolean{Log.d("BackGesture","Activity#dispatchKeyEvent()event:$event")returnsuper.dispatchKeyEvent(event)}overridefunonKeyDown(keyCode:Int,event:KeyEvent):Boolean{Log.d("BackGesture","Activity#onKeyDown()event:$event")returnsuper.onKeyDown(keyCode,event)}overridefunonKeyUp(keyCode:Int,event:KeyEvent):Boolean{Log.d("BackGesture","Activity#onKeyUp()event:$event")returnsuper.onKeyUp(keyCode,event)}overridefunonBackPressed(){Log.d("BackGesture","onBackPressed()")super.onBackPressed()}}可是實測發現:
12-Back Gesture 的執行日誌:
05-3110:35:28.7321126711267DBackGesture:Activity#dispatchKeyEvent()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK,...}05-3110:35:28.7331126711267DBackGesture:Activity#onKeyDown()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK,...}05-3110:35:28.7331126711267DBackGesture:Activity#dispatchKeyEvent()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK,...}05-3110:35:28.7331126711267DBackGesture:Activity#onKeyUp()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK,...}05-3110:35:28.7331126711267DBackGesture:onBackPressed()05-3110:35:28.7341126711267DBackGesture:Activity#handleOnBackPressed()12-Back KeyButton 的執行日誌:
05-3110:37:21.7241126711267DBackGesture:Activity#dispatchKeyEvent()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK...}05-3110:37:21.7241126711267DBackGesture:Activity#onKeyDown()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK...}05-3110:37:21.8461126711267DBackGesture:Activity#dispatchKeyEvent()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK...}05-3110:37:21.8461126711267DBackGesture:Activity#onKeyUp()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK...}05-3110:37:21.8461126711267DBackGesture:onBackPressed()05-3110:37:21.8461126711267DBackGesture:Activity#handleOnBackPressed()調試了一下,發現 AppCompat 框架里使用 13 的新 SDK API 前的版本判斷有問題:
publicclassComponentActivity{protectedvoidonCreate(@NullableBundlesavedInstanceState){...if(Build.VERSION.SDK_INT>=33){mOnBackPressedDispatcher.setOnBackInvokedDispatcher(getOnBackInvokedDispatcher());}...}}publicfinalclassOnBackPressedDispatcher{CancellableaddCancellableCallback(@NonNullOnBackPressedCallbackonBackPressedCallback){...if(Build.VERSION.SDK_INT>=33){updateBackInvokedCallbackState();onBackPressedCallback.setIsEnabledConsumer(mEnabledConsumer);}returncancellable;}}Beta版的SDK_INT常量仍然是12L的 32,到正式發布才會改為 33,所以版本判斷應當使用BuildCompat的如下 API:
//BuildCompat.javapublicstaticbooleanisAtLeastT(){returnVERSION.SDK_INT>=33||(VERSION.SDK_INT>=32&&isAtLeastPreReleaseCodename("Tiramisu",VERSION.CODENAME));}官方文檔提示說的是使用 1.6.0-alpha03 及以上,那麼 03 應該是首次引入上述適配的版本,可能還沒做好。查了下 AppCompat 包是否出現最新版本,果然有個1.6.0-alpha04。
Version 1.6.0-alpha04
May 18, 2022
更新了後確實好了,即 13 上開啟支持的話,無論是 Back Gesture 還是 Back KeyButton,能像預期的那樣都只會輸出 androidX 版本的 Callback,Back 相關 KeyEvent 回調將不再執行。
05-3110:55:10.77350415041DBackGesture:Activity#handleOnBackPressed()但仍有一點未達預期:
適配步驟:
遷移已有的系統返回處理邏輯到 AndroidX 的OnBackPressedDispatcherAPI,他需要指定 OnBackPressedCallback 實現,詳細的可參考如何提供自定義返回導航
對於 Activity:
classMyActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)valcallback=onBackPressedDispatcher.addCallback(this){//Handlethebackbuttonevent}}...}對於 Fragment:
publicclassFormEntryFragmentextendsFragment{@OverridepublicvoidonAttach(@NonNullContextcontext){super.onAttach(context);OnBackPressedCallbackcallback=newOnBackPressedCallback(true//defaulttoenabled){@OverridepublicvoidhandleOnBackPressed(){showAreYouSureDialog();}};requireActivity().getOnBackPressedDispatcher().addCallback(this,//LifecycleOwnercallback);}}禁用原有的系統返回手勢回調,比如 onBackPressed()、KEYCODE_BACK
解釋:getOnBackPressedDispatcher 早在 13 之前就已經支持,既然換了就沒必要保留 SDK API 邏輯。
最後記得加入新返回導航的支持。
適配步驟:
運行在 13 及之後的版本上使用全新的 SDK API 即OnBackInvokedCallback,12及之前的版本仍可使用舊的返回 API
在 Activity、Dialog、Window 等 Window 級別的組件里需要監聽返回手勢的邏輯處註冊實現了onBackInvoked方法的 OnBackInvokedCallback。這將阻止當前的 Activity 被結束,這樣的話當用戶觸發了系統返回操作的話你的 Callback 將有機會執行你預期的返回動作
為了確保正確支持系統「後退導航」的未來增強功能,你的 App 必須註銷 OnBackInvokedCallback。否則,用戶在使用系統後退導航時可能會看到不良行為,例如,在視圖之間「卡住」並強制他們退出應用。
To ensure that future enhancements to the system Back navigation are properly supported, your appMUSTunregister theOnBackInvokedCallback. Otherwise, users may see undesirable behavior when using a system Back navigation—for example, "getting stuck" between views and forcing them to force quit your app.
@OverridevoidonCreate(){if(BuildCompat.isAtLeastT()){getOnBackInvokedDispatcher().registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,()->{//...});}}比如 WebView 需要攔截返回手勢以回退網頁,當已經返回到主畫面的時候應當註銷該 Callback 讓系統來處理 finish。
同樣的,加入新返回導航的支持。
備註:onBackPressed() 邏輯保留也沒有關係,並不會發生衝突,而且為了兼容 13 之前的系統功能本就應該保留。
registerOnBackInvokedCallback() 說明registerOnBackInvokedCallback() 調用的時候需要提供如下兩個參數:
priority:按照註冊的逆序進行,但如果是高優先級的先回調。可選範圍:int 型,亦可選如下預設常量:
但不可以是負值、否則會發生IllegalArgumentException異常
java.lang.IllegalArgumentException: Application registered OnBackInvokedCallback cannot have negative priority. Priority: -1
callback:OnBackInvokedCallback 實例,會在 Back Gesture 觸發、Back KeyButton 按壓的時候被回調
實際結果:只有最後一個 register 的 Callback 得到調用,但如果列表里存在 PRIORITY_OVERLAY 等更高優先級的 Callback 的話則優先。與如下描述不符:
When back is triggered, callbacks on the in-focus window are invoked in reverse order in which they are added within the same priority. Between different priorities, callbacks with higher priority are invoked first.
和 KEYCODE_BACK 相關的有很多 API 可以處理、場景也很繁雜,簡單舉例如下:
覆寫 Activity#onKeyUp() 處理 KEYCODE_BACK 的 UP
覆寫 Activity#dispatchKeyEvent() 將 KeyEvent 傳遞到 Fragment 處理
覆寫 Activity#onBackPressed() 處理返回回調
調用 Dialog#setOnKeyListener() 處理 KEYCODE_BACK
調用 AlertDialog.Builder#setOnKeyListener() 處理 KEYCODE_BACK
覆寫 Dialog#dispatchKeyEvent() 處理 KEYCODE_BACK
覆寫 EditText#onKeyPreIme() 處理 KEYCODE_BACK
甚至還有覆寫 View 的 dispatchKeyEvent() 等函數處理 KEYCODE_BACK
適配的目的在於確保如下:
以上述的案例 1 的代碼為例,如下是如何改造以保證能在 12 和 13 上運行一樣的 Key 相關動作:
classActivity{privatevaronBackInvokedCallback:OnBackInvokedCallback?=nulloverridefunonCreate(savedInstanceState:Bundle?){...if(BuildCompat.isAtLeastT()){onBackInvokedCallback=OnBackInvokedCallback{onBackEvent()}.also{onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,it)}}}overridefunonDestroy(){super.onDestroy()if(BuildCompat.isAtLeastT()){onBackInvokedCallback?.let{onBackInvokedDispatcher.unregisterOnBackInvokedCallback(it)}}}privatefunonBackEvent(){//if(...)returnfalseif(...)return//when(keyCode){//KeyEvent.KEYCODE_BACK->{methodA()}//KeyEvent.KEYCODE_MENU->{...}//else->{}//}methodA()//returnif(...){//true//}elsesuper.onKeyDown(keyCode,event)}//為兼容舊版仍需完全保留overridefunonKeyDown(keyCode:Int,event:KeyEvent?):Boolean{...}}如上適配的關鍵點在於:除了在 Manifest 中將 enableOnBackInvokedCallback 屬性打開和註冊 OnBackInvokedCallback() 以外,重點在於如何實現 onBackInvoked() 來達到舊版的同等返回邏輯:
此外,需要留意如下一些細節:
新的 Callback 如何區分 dispatchKeyEvent()、onKeyDown()、onKeyUp() 的時機?
無法區分,開啟新返回導航之後只有一個 OnBackInvokedCallback 回調時機,其在Back Gesture Trigger或Back KeyButton Up時觸發。
原本時序:dispatchKeyEvent(DOWN) -> onKeyDown() -> dispatchKeyEvent(UP) -> onKeyUp()
新的 Callback 如何針對 KEYCODE_BACK 的 DOWN 和 UP 作區分?
無法區分,開啟新返回導航之後只有最終的 Callback,沒有 DOWN 和 UP 之分。
新的 Callback 針對 dispatchKeyEvent() 等處理的 return true、false、super 如何區分?
Back 以外,比如 Menu KeyEvent 的監聽是否受影響?
不受影響。之前的 Menu Key 等監聽在 13 上仍可以監聽到、正常運行,可以保留。
如何兼容 13 以前的版本呢?
新老處理共存,判斷運行版本:13 上開啟的話執行新邏輯,13 以前繼續沿用舊邏輯。
Activity、Fragment 以及 Dialog 眾多的情況下,可在 Base 類里加入統一的註冊和銷毀 Callback 的復用代碼。
為了不干預不需要處理的子類,默認不進行註冊。需要的子類覆寫isNeedInterceptBackEvent()返回 true 並實現自己的 Callback 邏輯即可。
如下的 BaseActivity 事例代碼:
openclassBaseActivity:AppCompatActivity(){privatevaronBackInvokedCallback:OnBackInvokedCallback?=null/***Innerclassforhandlebackcallbacktotally.*/internalclassOnBackInvokedCallbackInnerconstructor(baseActivity:BaseActivity):OnBackInvokedCallback{privatevalactivity:WeakReference<BaseActivity>overridefunonBackInvoked(){activity.get()?.apply{onBackEvent()}}init{activity=WeakReference(baseActivity)}}/***Overridethismethodandreturntrueifchildwannahandlebackevent.*/openfunisNeedInterceptBackEvent():Boolean=false/***DefaultbackoperationisinvokingonBackPressed().*Childactivitycouldoverrideandimplementitsownoperation.*/openfunonBackEvent(){onBackPressed()}overridefunonCreate(savedInstanceState:Bundle?){...if(isNeedInterceptBackEvent()&&BuildCompat.isAtLeastT()){onBackInvokedCallback=OnBackInvokedCallbackInner(this).also{onBackInvokedDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,it)}}}overridefunonDestroy(){...if(BuildCompat.isAtLeastT()){onBackInvokedCallback?.let{onBackInvokedDispatcher.unregisterOnBackInvokedCallback(it)}}}}需要的子類進行覆寫。
classBackKeyHandleActivity:BaseActivity(){...overridefunisNeedInterceptBackEvent():Boolean=trueoverridefunonBackEvent(){...}//兼容13之前的邏輯overridefunonBackPressed(){...}}6. 新返回導航支持與否的深入比較和原理分析針對採用新 SDK 返回 API 方案分別在 13 上開啟和關閉新返回導航的支持,觀察 KeyEvent 相關的 Log 輸出,並嘗試分析一些原理方面的差異。
6.1 開啟支持Back Gesture開啟新的返回手勢支持的話,只能收到 OnBackInvokedCallback 回調,確實無法像以前一樣靈活、精細地處理 KEYCODE_BACK 了。
如下的系統日誌可以瞥見 Callback 處理的一些細節。
05-2610:26:27.929787787DNoBackGesture:Startgesture:MotionEvent{action=ACTION_DOWN...}05-2610:26:27.929787787DNoBackGesture:Prediction[1653531987929,47,633,-1,0.000000,1]05-2610:26:27.930787787DNoBackGesture:resetmTriggerBack=false05-2610:26:27.931787852DShellBackPreview:initAnimationmMotionStarted=false05-2610:26:27.932787787DNoBackGesture:Gesture[1653531987932,alw=TRUE,TRUE,TRUE,FALSE,disp=Point(1080,2340),wl=82,il=0,wr=82,ir=0,excl=SkRegion()]05-2610:26:27.9335992725DCoreBackPreview:FocusedwindowfoundusinggetFocusedWindowToken05-2610:26:27.9335992725DCoreBackPreview:startBackNavigationcurrentTask=Task{1d3c440#502type=...},callbackInfo=OnBackInvokedCallbackInfo{...}05-2610:26:27.934787852DShellBackPreview:ReceivedbackNavigationInfo:BackNavigationInfo{...}05-2610:26:27.963787787DOnBackInvokedDispatcher:ViewRootImpl.registerBackCallbackOnWindow.Dispatcher:android.window.WindowOnBackInvokedDispatcher@be64a11Package:com.android.systemuiIWindow:android.view.ViewRootImpl$W@5c4e776Session:android.view.IWindowSession$Stub$Proxy@3998bd705-2610:26:27.968787787VOnBackInvokedDispatcher:ProxysetActualandroid.window.WindowOnBackInvokedDispatcher@be64a11.Currentnull05-2610:26:27.968787787VOnBackInvokedDispatcher:Proxytransferring0callbackstoandroid.window.WindowOnBackInvokedDispatcher@be64a1105-2610:26:28.27139783978DBackGesture:onBackInvoked()通過 adb shell dumpsys input 命令確實也沒有看到 InputFlinger 發送 KEYCODE_BACK 的記錄。
MotionEvent(deviceId=8,eventTime=2965229468000,source=TOUCHSCREEN|STYLUS,displayId=0,action=DOWN...)MotionEvent(deviceId=8,eventTime=2965457324000,source=TOUCHSCREEN|STYLUS,displayId=0,action=MOVE...)...MotionEvent(deviceId=8,eventTime=2965524225000,source=TOUCHSCREEN|STYLUS,displayId=0,action=UP...)Back KeyButtonBack KeyButton 場景也是一樣,開啟新返回導航支持的話,只能收到 OnBackInvokedCallback 回調。
05-2610:59:05.85444974497DOnBackInvokedDispatcher:ViewRootImpl.registerBackCallbackOnWindow.Dispatcher:android.window.WindowOnBackInvokedDispatcher@ad0c7c7Package:com.android.systemuiIWindow:android.view.ViewRootImpl$W@2ade1f4Session:android.view.IWindowSession$Stub$Proxy@f606e1705-2610:59:05.90444974497VOnBackInvokedDispatcher:ProxysetActualandroid.window.WindowOnBackInvokedDispatcher@ad0c7c7.Currentnull05-2610:59:05.90444974497VOnBackInvokedDispatcher:Proxytransferring0callbackstoandroid.window.WindowOnBackInvokedDispatcher@ad0c7c705-2610:59:05.97777007700DBackGesture:onBackInvoked()05-2610:59:06.49577007700VOnBackInvokedDispatcher:Proxyunregisterandroid.app.Activity$$ExternalSyntheticLambda0@a72f76.Actual=android.window.WindowOnBackInvokedDispatcher@1da92aa05-2610:59:06.49577007700VOnBackInvokedDispatcher:Proxyunregistercom.example.tiramisu_demo.MainActivity$$ExternalSyntheticLambda1@d37f96a.Actual=android.window.WindowOnBackInvokedDispatcher@1da92aa05-2610:59:27.69644974497DOnBackInvokedDispatcher:ViewRootImpl.registerBackCallbackOnWindow.Dispatcher:android.window.WindowOnBackInvokedDispatcher@cdfd9cPackage:com.android.systemuiIWindow:android.view.ViewRootImpl$W@da2b3a5Session:android.view.IWindowSession$Stub$Proxy@f606e1705-2610:59:27.70744974497VOnBackInvokedDispatcher:ProxysetActualandroid.window.WindowOnBackInvokedDispatcher@cdfd9c.Currentnull05-2610:59:27.70744974497VOnBackInvokedDispatcher:Proxytransferring0callbackstoandroid.window.WindowOnBackInvokedDispatcher@cdfd9c但 dump input 卻出現了 Back 的 KeyEvent 記錄,這是為什麼呢?
此處留個懸念,後面會揭開謎底。
MotionEvent(deviceId=8,eventTime=2276120343000,source=TOUCHSCREEN|STYLUS,displayId=0,action=DOWN...)KeyEvent(deviceId=-1,eventTime=2276124000000,source=KEYBOARD,displayId=0,action=DOWN,flags=0x00000048,keyCode=BACK(4)...)MotionEvent(deviceId=8,eventTime=2276205324000,source=TOUCHSCREEN|STYLUS,displayId=0,action=UP...)KeyEvent(deviceId=-1,eventTime=2276266000000,source=KEYBOARD,displayId=0,action=UP,flags=0x00000048,keyCode=BACK(4)...)6.2 關閉支持Back Gesture當關閉支持後 Back Gesture 場景下能和舊版本一樣收到 KEYCODE_BACK 了。
05-2611:09:28.23567846784DBackGesture:dispatchKeyEvent()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK...}05-2611:09:28.23667846784DBackGesture:dispatchKeyEvent()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK...}05-2611:09:28.24067846784DBackGesture:onBackPressed()dump input 也可以證實該 KeyEvent 的真實存在,而且可以看到 Back Gesture 的 UP 之後連續注入了 KEYCODE_BACK 的 DOWN 和 UP 的細節。
MotionEvent(deviceId=8,eventTime=585598303000,source=0x00005002,displayId=0,action=DOWN...)MotionEvent(deviceId=8,eventTime=585812734000,source=0x00005002,displayId=0,action=MOVE...)...MotionEvent(deviceId=8,eventTime=585858936000,source=0x00005002,displayId=0,action=UP...)KeyEvent(deviceId=-1,eventTime=585859000000,source=0x00000101,displayId=0,action=DOWN,flags=0x00000048,keyCode=4...)KeyEvent(deviceId=-1,eventTime=585860000000,source=0x00000101,displayId=0,action=UP,flags=0x00000048,keyCode=4...)Back KeyButton自不必說,Back KeyButton 的按下當然也可以收到 KEYCODE_BACK。
05-2610:48:21.58058175817DBackGesture:dispatchKeyEvent()event:KeyEvent{action=ACTION_DOWN,keyCode=KEYCODE_BACK...}05-2610:48:21.63558175817DBackGesture:dispatchKeyEvent()event:KeyEvent{action=ACTION_UP,keyCode=KEYCODE_BACK...}05-2610:48:21.63558175817DBackGesture:onBackPressed()但與 Gesture 不同,dump input 的結果可以看到:在 Back KeyButton 上按下時注入了 KEYCODE_BACK 的 DOWN,抬起注入了 UP。
MotionEvent(deviceId=8,eventTime=352268883000,source=0x00005002,displayId=0,action=DOWN...)KeyEvent(deviceId=-1,eventTime=352289000000,source=0x00000101,displayId=0,action=DOWN...)MotionEvent(deviceId=8,eventTime=352378721000,source=0x00005002,displayId=0,action=UP...)KeyEvent(deviceId=-1,eventTime=352386000000,source=0x00000101,displayId=0,action=UP...)6.3 Back 相關時序的變化總結13 上開啟支持之後,如果是點擊 Back KeyButton,從 dump 來看仍然發出了 KEYCODE_BACK,猜測與你大體是這樣:
這裡不禁產生一個疑問:
經過思考,覺得不免又如下幾點可能:
需要說明的是,當關閉新返回導航支持後,為了兼容舊的 API,Back Gesture 仍像以前一樣發送 KEYCODE_BACK。當然這肯定是暫時的,後續系統肯定會強制使用該特性,到時候這個 Back Gesture 就再也不用發送 KEYCODE_BACK 了。
7. 注意和殘留事項製作了一張 Android 13 新返回導航適配流程圖供大家快速查閱。
做個簡單總結:
如果決定支持新返回導航即聲明enableOnBackInvokedCallback為 true,之後需依據 App 集成了 SDK API 還是 AndroidX API 決定適配的方案。
另外還需要留意上述章節提及的注意事項和殘留事項。
當然如果沒有餘力適配,決定捨棄可預測型返回手勢、OnBackInvokedDispatcher 新 API 以及KEYCODE_BACK等一系列變更,可以選擇什麼也不做。
但早在 13 之前,官方已推薦使用 AndroidX 的 OnBackPressedDispatcher 來取代onBackPressed,13 花這麼大精力完全廢棄 onBackPressed 並向 AOSP 新增了 OnBackInvokedDispatcher 等系列 API。
從這個趨勢來看,估計到 Android 14 這個新返回導航就會成為強制要求,開發者們當儘早適配才是!
參考官方文檔:
SDK API:
AndroidX API:



微信改了推送機制,真愛請星標本公號👇