Android 16(API 36)及以上设备,在 React Native 混合应用(原生 Activity 嵌套 RN Fragment)中,点击物理返回键时,应用直接退到后台(桌面),而不是先返回 RN 内部的上一级页面。
Android 15 及以下,返回键的处理流程如下:
物理按键 → dispatchKeyEvent() → onKeyDown() → onBackPressed() → 自定义逻辑
onBackPressed() 的默认实现是 finish()(销毁 Activity),而开发者通常重写 onBackPressed() 或在其调用链中插入自定义逻辑(如"先让 RN 消费返回,否则退到后台")。
旧代码的返回逻辑是"挂载"在 onBackPressed() 这个环节上的。
而Android 16 引入了预测性返回(Predictive Back)动画,系统需要在执行返回动作之前提前预览返回后的界面。为了支持这个特性,旧的 KeyEvent.KEYCODE_BACK 分发机制被废弃。dispatchKeyEvent() → onKeyDown() → onBackPressed() 这条调用链在 Android 16 上被绕过。系统强制使用 OnBackPressedDispatcher 来管理所有返回事件。
再看下,旧代码失效,是因为HomeActivity 中原本有这段逻辑:
Kotlin
override fun onBackPressedSupport() {
if (currentFragment?.onBackPressedSupport() == true) {
return
}
moveTaskToBack(true) // 预期:退到后台
}
这段逻辑本身是正确的,但它没有注册到新的 OnBackPressedDispatcher 上。在 Android 16 中:
系统检查 OnBackPressedDispatcher,发现如果没有注册任何回调,系统执行默认策略:调用 super.onBackPressed() → finish() 。 由于 HomeActivity 是应用的根 Activity,finish() 会销毁 Activity 并将任务栈切到桌面。用户感知为:直接退到后台(跳过了 RN 内部页面的逐级返回)
Android 16 及以上(新调用链):

解决方案是,在 HomeActivity的 onCreate 中注册 OnBackPressedCallback,在回调中实现返回逻辑。 代码如下:
Kotlin
class MainActivity : AppCompatActivity() {
private var currentFragment: RNHostFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 初始化代码。。。
// 适配 Android 16 预测性返回
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// 1. 优先让 RN Fragment 处理返回
if (rnFragment?.onBackPressedSupport() == true) {
return
}
// 2. 如果 RN 未消费,则退到后台
moveTaskToBack(true)
}
})
}
// 兼容旧版(可选,保留作为兜底)
override fun onBackPressed() {
if (rnFragment?.onBackPressedSupport() == true) {
return
}
moveTaskToBack(true)
}
}
RNHostFragment 内部需要实现一个查询方法 onBackPressedSupport(): Boolean:
返回 true:RN 内部有页面可返回,已执行 Pop 操作
返回 false:RN 已在根页面,需 Activity 自己处理
Kotlin
class RNHostFragment : Fragment() {
// 查询 RN 导航栈状态,返回 true 表示已消费
fun onBackPressedSupport(): Boolean {
// 具体实现取决于 具体 RN 封装
// 例如:调用 ReactInstanceManager 的 getCurrentActivity()?.hasBackStack()
return reactNavigationStack?.canGoBack() ?: false
}
}
改完测试ok.