-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Issue
🔥 [Android] OOM Crash due to excessive notification storage in SharedPreferences (ReactNativeFirebaseMessagingStoreImpl)
We are encountering java.lang.OutOfMemoryError on Android devices.
The root cause is that ReactNativeFirebaseMessagingStoreImpl stores up to 100 notifications in SharedPreferences by default.
When the app receives many notifications with large payloads, the SharedPreferences file becomes too large. Since SharedPreferences loads the entire file into memory, this leads to OOM crashes, especially on devices with limited heap memory.
Stack Trace:
java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 425280 free bytes and 415KB until OOM...
at java.util.HashMap.newNode(HashMap.java:1907)
at java.util.HashMap.putVal(HashMap.java:636)
at java.util.HashMap.putMapEntries(HashMap.java:521)
at java.util.HashMap.<init>(HashMap.java:491)
at android.app.SharedPreferencesImpl$EditorImpl.commitToMemory(SharedPreferencesImpl.java:539)
at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:486)
at io.invertase.firebase.common.UniversalFirebasePreferences.setStringValue(UniversalFirebasePreferences.java:66)
at io.invertase.firebase.messaging.ReactNativeFirebaseMessagingStoreImpl.storeFirebaseMessage(ReactNativeFirebaseMessagingStoreImpl.java:43)Analysis:
The ReactNativeFirebaseMessagingStoreImpl.java has a constant MAX_SIZE_NOTIFICATIONS = 100.
Every time a notification is received (whether in foreground or background), it is stored in SharedPreferences.
If the notification data is large, storing 100 entries can easily exceed the available heap size during the SharedPreferences load/commit process.
Proposed Solution & Fix:
We have successfully patched the library locally with the following changes:
- Reduce the default limit: 100 seems excessive. We reduced it to 20.
- Make it configurable: Added support for
rn_firebase_messaging_max_stored_notificationsinAndroidManifest.xml. - Safety Cap: Even if configured higher, we capped the limit at 100 to prevent OOM.
- Improve cleanup logic: Changed
iftowhileloop to aggressively clean up excess notifications.
Example Patch Code:
// In ReactNativeFirebaseMessagingStoreImpl.java
private static int MAX_SIZE_NOTIFICATIONS = 20; // Default reduced to 20
private static boolean isInitialized = false;
private int getMaxNotificationSize() {
if (isInitialized) return MAX_SIZE_NOTIFICATIONS;
try {
Context context = ReactNativeFirebaseApp.getApplicationContext();
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
if (appInfo.metaData != null) {
int configValue = appInfo.metaData.getInt("rn_firebase_messaging_max_stored_notifications", 20);
// Safety cap: never exceed 100 to prevent OOM
MAX_SIZE_NOTIFICATIONS = Math.min(configValue, 100);
}
} catch (Exception e) {
// Ignore
}
isInitialized = true;
return MAX_SIZE_NOTIFICATIONS;
}
@Override
public void storeFirebaseMessage(RemoteMessage remoteMessage) {
// ...
// check and remove old notifications message
List<String> allNotificationList = convertToArray(notifications);
// Changed 'if' to 'while' for aggressive cleanup
while (allNotificationList.size() > getMaxNotificationSize()) {
String firstRemoteMessageId = allNotificationList.get(0);
preferences.remove(firstRemoteMessageId);
notifications = removeRemoteMessage(firstRemoteMessageId, notifications);
allNotificationList.remove(0);
}
// ...
}Project Files
Javascript
Click To Expand
package.json:
{
"dependencies": {
"react-native": "0.81.5",
"@react-native-firebase/app": "21.7.1",
"@react-native-firebase/messaging": "21.7.1"
}
}firebase.json for react-native-firebase v6:
# N/AiOS
Click To Expand
ios/Podfile:
- I'm not using Pods
- I'm using Pods and my Podfile looks like:
# N/AAppDelegate.m:
// N/AAndroid
Click To Expand
Have you converted to AndroidX?
- my application is an AndroidX application?
- I am using
android/gradle.settingsjetifier=truefor Android compatibility? - I am using the NPM package
jetifierfor react-native compatibility?
android/build.gradle:
// N/Aandroid/app/build.gradle:
// N/Aandroid/settings.gradle:
// N/AMainApplication.java:
// N/AAndroidManifest.xml:
<!-- We added this configuration to solve the issue -->
<meta-data
android:name="rn_firebase_messaging_max_stored_notifications"
android:value="20" />Environment
Click To Expand
react-native info output:
System:
OS: macOS
Binaries:
Node: 20.x
Yarn: N/A
npm: 10.x
Watchman: Yes
SDKs:
iOS SDK:
Platforms: iOS
Android SDK:
API Levels: 34
IDEs:
Android Studio: Yes
Xcode: Yes
Languages:
Java: 17
Python: N/A
npmPackages:
@react-native-community/cli: Not Found
react: 18.3.1
react-native: 0.81.5
- Platform that you're experiencing the issue on:
- iOS
- Android
- iOS but have not tested behavior on Android
- Android but have not tested behavior on iOS
- Both
react-native-firebaseversion you're using that has this issue:21.7.1
Firebasemodule(s) you're using that has the issue:Messaging
- Are you using
TypeScript?Y