Skip to content

Commit bc876fb

Browse files
alanleedevfacebook-github-bot
authored andcommitted
migrate deprecated onBackPressed() (#51096)
Summary: Pull Request resolved: #51096 **Problem:** `Activity.onBackPressed()` has been deprecated and with targetSdk 36, predictive back will be enforced and the API no longer called. We need to migrate to backward compatible AndroidX `OnBackPressedCallback`. - https://developer.android.com/about/versions/16/behavior-changes-16#predictive-back. **Solution:** `OnBackPressedCallback` is registered conditionally only if it is `targetSdk` 36 or greater. If the callback in enabled, `onBackPressed()` is not called and callback is used regardless of `android:enableOnBackInvokedCallback` property in <application> or <activity> set in AndroidManifest.xml. As a workaround callback is manually calling existing `onBackPressed()`. This is done rather than removing onBackPressed() completely and using only `OnBackPressedCallback` as we are not sure of the impact of removing the implementation entirely. Once we determine it is safe to do so then, we should remove the workaround and fully transition to `OnBackPressedCallback` * I also surveyed child classes extending ReactActivity for overridden `onPressedBack()` usage and found only one usage which will be handled later. NOTE: `ReactDelegate.onHostResume()` sets up the `DefaultHardwareBackBtnHandler` using `ReactActivity` (https://fburl.com/ul47tbeo) and will be called from JS `BackHanderl.exitApp` (https://fburl.com/code/a4l2pjsw). Calling `BackHanderl.exitApp` enables predictive back to work. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D74161428 fbshipit-source-id: 2e081ba6922b315e9d1746e83a41bab5277fa62e
1 parent fd21570 commit bc876fb

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
import android.content.res.Configuration;
1212
import android.os.Bundle;
1313
import android.view.KeyEvent;
14+
import androidx.activity.OnBackPressedCallback;
1415
import androidx.annotation.Nullable;
1516
import androidx.appcompat.app.AppCompatActivity;
1617
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
1718
import com.facebook.react.modules.core.PermissionAwareActivity;
1819
import com.facebook.react.modules.core.PermissionListener;
20+
import com.facebook.react.util.AndroidVersion;
1921
import org.jetbrains.annotations.NotNull;
2022

2123
/** Base Activity for React Native applications. */
@@ -24,6 +26,18 @@ public abstract class ReactActivity extends AppCompatActivity
2426

2527
private final ReactActivityDelegate mDelegate;
2628

29+
// Due to enforced predictive back on targetSdk 36, 'onBackPressed()' is disabled by default.
30+
// Using a workaround to trigger it manually.
31+
private final OnBackPressedCallback mBackPressedCallback =
32+
new OnBackPressedCallback(true) {
33+
@Override
34+
public void handleOnBackPressed() {
35+
setEnabled(false);
36+
onBackPressed();
37+
setEnabled(true);
38+
}
39+
};
40+
2741
protected ReactActivity() {
2842
mDelegate = createReactActivityDelegate();
2943
}
@@ -45,6 +59,9 @@ protected ReactActivityDelegate createReactActivityDelegate() {
4559
protected void onCreate(Bundle savedInstanceState) {
4660
super.onCreate(savedInstanceState);
4761
mDelegate.onCreate(savedInstanceState);
62+
if (AndroidVersion.isAtLeastTargetSdk36(this)) {
63+
getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback);
64+
}
4865
}
4966

5067
@Override
@@ -103,6 +120,9 @@ public void onBackPressed() {
103120

104121
@Override
105122
public void invokeDefaultOnBackPressed() {
123+
// Disabling callback so the fallback logic (finish activity) can run
124+
// as super.onBackPressed() will call all enabled callbacks in the dispatcher.
125+
mBackPressedCallback.setEnabled(false);
106126
super.onBackPressed();
107127
}
108128

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.util
9+
10+
import android.content.Context
11+
import android.os.Build
12+
13+
/** Helper class for checking Android version-related information. */
14+
internal object AndroidVersion {
15+
16+
/**
17+
* This is the version code for Android 16 (SDK Level 36). Delete it once we bump up the default
18+
* compile SDK version to 36.
19+
*/
20+
private const val VERSION_CODE_BAKLAVA: Int = 36
21+
22+
/**
23+
* This method is used to check if the current device is running Android 16 (SDK Level 36) or
24+
* higher and the app is targeting Android 16 (SDK Level 36) or higher.
25+
*/
26+
@JvmStatic
27+
fun isAtLeastTargetSdk36(context: Context): Boolean =
28+
Build.VERSION.SDK_INT >= VERSION_CODE_BAKLAVA &&
29+
context.applicationInfo.targetSdkVersion >= VERSION_CODE_BAKLAVA
30+
}

0 commit comments

Comments
 (0)