If you're maintaining a React Native Android application and recently upgraded your project to target SDK 36 (Android 16), you may encounter an unexpected navigation issue:
Pressing the Android system back button closes the app instead of navigating to the previous screen.
This can be particularly confusing when React Navigation is already configured correctly and the same navigation flow works perfectly on older Android target SDK versions.
This article explains what changed, how to identify the issue, the workaround I used, and what you should consider for a proper Android 16 migration.
The Problem
After upgrading the Android project from an older target SDK to:
targetSdkVersion = 36
the app started behaving differently when using the Android system back button.
For example, suppose the navigation stack is:
Home
↓
Products
↓
Product Details
When the user presses the Android system back button from Product Details, the expected behavior is:
Product Details
↓
Products
Instead, the application could close.
Interestingly, navigation using React Navigation itself continued to work:
navigation.goBack();
The issue was specifically related to the Android system back event.
Environment
The issue was observed in a React Native application with a setup similar to:
React Native
React Navigation
Android SDK 36
Target SDK 36
The important change was upgrading the Android target SDK to API level 36, corresponding to Android 16.
Why Does This Happen?
The important part of the migration is the Android back-navigation change.
Android has been moving away from the older:
onBackPressed()
mechanism toward the newer:
OnBackInvokedDispatcher
and predictive back navigation APIs.
With newer Android versions and target SDK requirements, applications need to properly participate in the newer back-navigation system.
This can expose compatibility issues in applications or libraries that still rely on the older back handling mechanism.
In a React Native application, the Android system back event eventually needs to be correctly propagated into the React Native / React Navigation layer.
If that doesn't happen, Android may interpret the back action as:
No navigation handler
↓
Finish current Activity
↓
App closes
instead of:
System Back
↓
React Native Back Handler
↓
React Navigation
↓
Previous screen
How I Identified the Problem
The first thing I checked was whether React Navigation itself was working.
Navigation from the application was working correctly:
navigation.navigate("ProductDetails");
and programmatic back navigation also worked:
navigation.goBack();
The problem only occurred when pressing the physical/system Android back button.
I also checked whether the application was closing directly from the Home screen.
That behavior is expected:
Home
↓
Android Back
↓
App exits
The actual problem was:
Home
↓
Product List
↓
Product Details
↓
Android Back
↓
App exits ❌
instead of:
Home
↓
Product List
↓
Product Details
↓
Android Back
↓
Product List ✅
This distinction is important when debugging Android back navigation.
The AndroidManifest Configuration
The Android application can control the behavior of the newer back system using:
android:enableOnBackInvokedCallback
For example:
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="false">
In my case, setting:
android:enableOnBackInvokedCallback="false"
worked as a temporary workaround.
After adding this configuration, the Android system back button once again started navigating to the previous React Navigation screen instead of immediately closing the application.
Why Does false Work?
Setting:
android:enableOnBackInvokedCallback="false"
essentially disables the application's participation in the newer OnBackInvokedDispatcher behavior.
This allows the application to continue using the older back handling path.
Conceptually:
Without the workaround
Android System Back
↓
OnBackInvokedDispatcher
↓
React Native / Navigation handler
↓
❌ Handler not properly triggered
↓
Activity finishes
↓
App closes
With the temporary workaround
Android System Back
↓
Legacy back handling
↓
React Native BackHandler
↓
React Navigation
↓
Previous screen
So the workaround doesn't really "fix" predictive back support.
It tells Android to avoid the newer callback behavior for this application.
Is enableOnBackInvokedCallback="false" the Permanent Fix?
Not necessarily.
This is an important distinction.
If your application is targeting Android 16, you should ideally investigate whether your React Native version and navigation dependencies properly support Android's newer back-navigation behavior.
Using:
android:enableOnBackInvokedCallback="false"
can be useful as a compatibility workaround while migrating, but it should not automatically be considered the final Android 16 solution.
The long-term goal should be:
Android 16
↓
Predictive Back
↓
OnBackInvokedDispatcher
↓
React Native
↓
React Navigation
working correctly.
Check Your React Native Version
Before adding application-level workarounds, check the React Native version:
npm list react-native
or:
yarn why react-native
Also check React Navigation:
npm list @react-navigation/native
For example:
react-native
@react-navigation/native
@react-navigation/native-stack
@react-navigation/bottom-tabs
Older combinations may have different levels of Android predictive-back support.
It's important to evaluate the complete dependency chain rather than changing only the AndroidManifest.
Check Your MainActivity
Also inspect your Android MainActivity.
A typical React Native application may have something similar to:
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "MyApp";
}
}
If your application has custom back handling, search the Android project for:
onBackPressed
For example:
grep -R "onBackPressed" android/
Also search for:
OnBackInvokedDispatcher
and:
OnBackInvokedCallback
This helps identify whether custom native code is interfering with the new Android back-navigation mechanism.
Check React Native BackHandler
React Native applications can listen for Android back events using:
import { BackHandler } from "react-native";
For example:
useEffect(() => {
const subscription = BackHandler.addEventListener(
"hardwareBackPress",
() => {
navigation.goBack();
return true;
}
);
return () => subscription.remove();
}, [navigation]);
However, don't add this globally just to hide the problem.
React Navigation normally handles Android back navigation for its navigation stack.
Adding multiple global BackHandler listeners can introduce new problems such as:
- Back event being consumed too early
- Incorrect navigation
- Screens being popped multiple times
- Modals not closing correctly
- Navigation stack becoming inconsistent
So first determine whether the underlying Android back event is reaching React Native correctly.
A Useful Debugging Test
You can temporarily add a BackHandler listener to determine whether React Native receives the system back event:
useEffect(() => {
const subscription = BackHandler.addEventListener(
"hardwareBackPress",
() => {
console.log("ANDROID BACK EVENT RECEIVED");
return false;
}
);
return () => subscription.remove();
}, []);
Then navigate to a screen and press the Android system back button.
If you see:
ANDROID BACK EVENT RECEIVED
then the event is reaching React Native.
If the app closes without the event reaching your JavaScript handler, the problem is likely further down in the Android back-dispatching path.
This is a useful way to separate:
Android back event problem
from:
React Navigation configuration problem
Don't Confuse Home Screen Behavior With a Bug
One important testing detail:
If the user is already on the root screen:
Home
pressing Android Back is normally expected to exit the application.
For example:
Home
↓
Android Back
↓
App closes
That alone isn't evidence of a problem.
The important test is:
Home
↓
Screen A
↓
Screen B
↓
Android Back
Expected:
Screen B
↓
Screen A
If instead:
Screen B
↓
App closes
then back navigation is not being handled correctly.
Testing Checklist After Target SDK 36 Upgrade
After upgrading to API 36, I recommend testing all of these scenarios.
1. Normal navigation
Home → List → Details
Press system Back.
Expected:
Details → List
2. Multiple navigation levels
Home → A → B → C
Press Back repeatedly.
Expected:
C → B → A → Home
3. Root screen
Home
Press Back.
Expected:
App exits
4. Modal
Open a modal and press Back.
Expected:
Modal closes
instead of:
App exits
5. Bottom tabs
Test:
Tab A → Tab B → Screen
and verify that system Back behaves consistently with your navigation design.
6. Authentication flow
Test:
Login → OTP → Home
and make sure Back doesn't allow users to incorrectly return to authentication screens.
7. Deep links
Test:
Deep Link → Details
and verify the back stack behaves as expected.
8. Android gesture navigation
Test using:
- 3-button navigation
- Gesture navigation
Predictive back behavior can differ from traditional button-based testing, so both should be tested.
Temporary Workaround
If your application is currently affected and you need to stabilize the release, one possible temporary configuration is:
<application
...
android:enableOnBackInvokedCallback="false">
After rebuilding the application:
cd android
./gradlew clean
cd ..
Then rebuild:
npx react-native run-android
or use your normal release build process.
For an Expo bare/prebuild project, make sure the generated Android configuration is also correctly reflected in the source configuration you use for builds, rather than relying on a manual change that can be overwritten.
Recommended Migration Approach
Instead of treating the manifest flag as the final solution, I recommend approaching the migration in this order:
1. Upgrade target SDK → 36
↓
2. Test system Back
↓
3. Check React Native version
↓
4. Check React Navigation versions
↓
5. Search for custom Android back handling
↓
6. Search for BackHandler overrides
↓
7. Test predictive back
↓
8. Update incompatible dependencies
↓
9. Use manifest workaround if required
↓
10. Remove workaround after proper migration
This approach makes it easier to identify the actual compatibility problem.
Important Takeaway
Upgrading:
targetSdkVersion
is not always just a build configuration change.
A target SDK upgrade can activate or expose new Android platform behavior.
For Android 16 / API 36, back navigation and predictive back behavior are especially important areas to test.
If your React Native app suddenly starts closing when the Android system back button is pressed after moving to target SDK 36, don't immediately assume that your React Navigation stack is broken.
First determine whether:
Android
↓
Back Dispatcher
↓
React Native
↓
React Navigation
is working correctly.
The following configuration can serve as a temporary compatibility workaround:
android:enableOnBackInvokedCallback="false"
but the preferred long-term solution is to ensure that the React Native and navigation stack properly supports Android's modern back-navigation APIs.
Final Checklist
Before releasing a target SDK 36 build, verify:
- [ ] Android system Back navigates correctly
- [ ] Root screen exits correctly
- [ ] Nested navigation works
- [ ] Modals handle Back correctly
- [ ] Bottom tabs behave correctly
- [ ] Authentication screens behave correctly
- [ ] Deep links create the expected back stack
- [ ] Gesture navigation works
- [ ] 3-button navigation works
- [ ] Predictive back behavior has been tested
- [ ] React Native version is compatible
- [ ] React Navigation dependencies are compatible
- [ ] Custom
BackHandlerlogic has been reviewed - [ ] Native
onBackPressed()implementations have been reviewed - [ ]
OnBackInvokedDispatcherusage has been reviewed - [ ] Any temporary
enableOnBackInvokedCallbackworkaround is documented
Conclusion
Android 16 introduces another step in the evolution of Android back navigation. For React Native applications, upgrading to target SDK 36 can expose problems where the system Back button no longer reaches the JavaScript navigation layer as expected.
If your app starts closing instead of navigating backward, investigate the new Android back-dispatching behavior before modifying your navigation stack.
A manifest-level workaround such as:
android:enableOnBackInvokedCallback="false"
may restore the previous behavior temporarily, but dependency compatibility and proper predictive-back support should be addressed as part of the complete migration.
Target SDK upgrades should always be followed by dedicated navigation regression testing—not just build and installation testing.
✍️ Written by Dainy Jose — React Native Mobile Application Developer with 3+ years of experience building cross-platform mobile apps using React Native (Expo, TypeScript, Redux).
Currently expanding backend knowledge through the MERN Stack (MongoDB, Express.js, React.js, Node.js) to create more efficient, full-stack mobile experiences.
💼 Tech Stack: React Native · TypeScript · Redux · Expo · Firebase · Node.js · Express.js · MongoDB · REST API · JWT · Jest · Google Maps · Razorpay · PayU · Agile · SDLC · Git · Bitbucket · Jira
Top comments (0)