@react-native-firebase/messaging 25.1.0 → 26.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/RNFBMessaging.podspec +27 -8
  3. package/android/build.gradle +24 -0
  4. package/android/src/main/java/io/invertase/firebase/messaging/{ReactNativeFirebaseMessagingModule.java → NativeRNFBTurboMessaging.java} +143 -81
  5. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingPackage.java +1 -1
  6. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingReceiver.java +16 -0
  7. package/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingStoreImpl.java +50 -11
  8. package/android/src/main/java/io/invertase/firebase/messaging/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboMessagingSpec.java +151 -0
  9. package/android/src/main/java/io/invertase/firebase/messaging/generated/jni/CMakeLists.txt +36 -0
  10. package/android/src/main/java/io/invertase/firebase/messaging/generated/jni/RNFBMessagingTurboModules-generated.cpp +152 -0
  11. package/android/src/main/java/io/invertase/firebase/messaging/generated/jni/RNFBMessagingTurboModules.h +31 -0
  12. package/android/src/main/java/io/invertase/firebase/messaging/generated/jni/react/renderer/components/RNFBMessagingTurboModules/RNFBMessagingTurboModulesJSI-generated.cpp +161 -0
  13. package/android/src/main/java/io/invertase/firebase/messaging/generated/jni/react/renderer/components/RNFBMessagingTurboModules/RNFBMessagingTurboModulesJSI.h +356 -0
  14. package/app.plugin.js +1 -1
  15. package/dist/module/index.js +622 -7
  16. package/dist/module/index.js.map +1 -1
  17. package/dist/module/statics.js +1 -1
  18. package/dist/module/types/internal.js +4 -0
  19. package/dist/module/types/internal.js.map +1 -0
  20. package/dist/module/types/messaging.js +0 -15
  21. package/dist/module/types/messaging.js.map +1 -1
  22. package/dist/module/version.js +1 -1
  23. package/dist/typescript/lib/index.d.ts +182 -5
  24. package/dist/typescript/lib/index.d.ts.map +1 -1
  25. package/dist/typescript/lib/types/internal.d.ts +41 -0
  26. package/dist/typescript/lib/types/internal.d.ts.map +1 -0
  27. package/dist/typescript/lib/types/messaging.d.ts +7 -55
  28. package/dist/typescript/lib/types/messaging.d.ts.map +1 -1
  29. package/dist/typescript/lib/version.d.ts +1 -1
  30. package/ios/RNFBMessaging/RNFBMessaging+AppDelegate.h +24 -2
  31. package/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m +90 -12
  32. package/ios/RNFBMessaging/RNFBMessaging+FIRMessagingDelegate.h +8 -0
  33. package/ios/RNFBMessaging/RNFBMessaging+NSNotificationCenter.m +22 -4
  34. package/ios/RNFBMessaging/RNFBMessaging+UNUserNotificationCenter.m +31 -28
  35. package/ios/RNFBMessaging/RNFBMessagingModule.h +3 -2
  36. package/ios/RNFBMessaging/RNFBMessagingModule.mm +508 -0
  37. package/ios/RNFBMessaging/RNFBMessagingSerializer.h +8 -0
  38. package/ios/RNFBMessaging.xcodeproj/project.pbxproj +8 -8
  39. package/ios/generated/RCTAppDependencyProvider.h +25 -0
  40. package/ios/generated/RCTAppDependencyProvider.mm +55 -0
  41. package/ios/generated/RCTModulesConformingToProtocolsProvider.h +18 -0
  42. package/ios/generated/RCTModulesConformingToProtocolsProvider.mm +33 -0
  43. package/ios/generated/RCTThirdPartyComponentsProvider.h +16 -0
  44. package/ios/generated/RCTThirdPartyComponentsProvider.mm +23 -0
  45. package/ios/generated/RNFBMessagingTurboModules/RNFBMessagingTurboModules-generated.mm +184 -0
  46. package/ios/generated/RNFBMessagingTurboModules/RNFBMessagingTurboModules.h +222 -0
  47. package/ios/generated/RNFBMessagingTurboModulesJSI-generated.cpp +161 -0
  48. package/ios/generated/RNFBMessagingTurboModulesJSI.h +356 -0
  49. package/ios/generated/ReactAppDependencyProvider.podspec +34 -0
  50. package/lib/index.ts +821 -15
  51. package/lib/statics.ts +1 -1
  52. package/lib/types/internal.ts +59 -0
  53. package/lib/types/messaging.ts +7 -72
  54. package/lib/version.ts +1 -1
  55. package/package.json +30 -5
  56. package/plugin/build/android/setupFirebaseNotifationIcon.d.ts +3 -2
  57. package/plugin/build/android/setupFirebaseNotifationIcon.js +14 -7
  58. package/plugin/build/app.plugin.d.ts +2 -0
  59. package/plugin/build/app.plugin.js +6 -0
  60. package/plugin/build/index.d.ts +2 -1
  61. package/plugin/build/index.js +4 -4
  62. package/plugin/build/pluginConfig.d.ts +7 -0
  63. package/plugin/build/pluginConfig.js +2 -0
  64. package/plugin/src/android/setupFirebaseNotifationIcon.ts +19 -6
  65. package/plugin/src/app.plugin.ts +3 -0
  66. package/plugin/src/index.ts +5 -4
  67. package/plugin/src/pluginConfig.ts +8 -0
  68. package/plugin/tsconfig.tsbuildinfo +1 -1
  69. package/react-native.config.js +10 -0
  70. package/specs/NativeRNFBTurboMessaging.ts +46 -0
  71. package/typedoc.json +2 -19
  72. package/dist/module/modular.js +0 -396
  73. package/dist/module/modular.js.map +0 -1
  74. package/dist/module/namespaced.js +0 -415
  75. package/dist/module/namespaced.js.map +0 -1
  76. package/dist/typescript/lib/modular.d.ts +0 -255
  77. package/dist/typescript/lib/modular.d.ts.map +0 -1
  78. package/dist/typescript/lib/namespaced.d.ts +0 -12
  79. package/dist/typescript/lib/namespaced.d.ts.map +0 -1
  80. package/ios/RNFBMessaging/RNFBMessagingModule.m +0 -439
  81. package/lib/modular.ts +0 -455
  82. package/lib/namespaced.ts +0 -593
package/CHANGELOG.md CHANGED
@@ -3,6 +3,42 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [26.1.0](https://github.com/invertase/react-native-firebase/compare/v26.0.0...v26.1.0) (2026-08-03)
7
+
8
+ ### Features
9
+
10
+ - **ios:** add SPM dependency resolution support alongside CocoaPods ([#8933](https://github.com/invertase/react-native-firebase/issues/8933)) ([44a7a9a](https://github.com/invertase/react-native-firebase/commit/44a7a9ae7b404f412e9766c0417f1df8fa971a0b))
11
+ - **messaging:** make expo plugin configurable for notification icon and color ([#9132](https://github.com/invertase/react-native-firebase/issues/9132)) ([99af959](https://github.com/invertase/react-native-firebase/commit/99af9597b19bf22b78f82de2951e1b94004730cd)), closes [#8840](https://github.com/invertase/react-native-firebase/issues/8840)
12
+
13
+ ## [26.0.0](https://github.com/invertase/react-native-firebase/compare/v25.1.0...v26.0.0) (2026-07-29)
14
+
15
+ ### ⚠ BREAKING CHANGES
16
+
17
+ - **messaging, ios:** make APNs registration timeout independent of main queue
18
+ - **messaging:** messaging requires the React Native New Architecture.
19
+ - **app:** App/Core modules native bridge requires New Architecture.
20
+
21
+ Migrate RNFBAppModule and RNFBUtilsModule to Codegen TurboModules with
22
+ unified resolver, lazy Proxy wrapper, and committed generated artifacts.
23
+ Includes functions codegenConfig rename (NewArch-AD-7), test harness
24
+ overrides, architecture decisions, and validation workflow hardening.
25
+
26
+ ### Features
27
+
28
+ - **app:** migrate app modules to TurboModules incl general migration infra ([978168d](https://github.com/invertase/react-native-firebase/commit/978168dacecf4925d347d9757eff73ee43e1484f))
29
+ - **messaging:** migrate messaging to TurboModules ([e56c7f4](https://github.com/invertase/react-native-firebase/commit/e56c7f406920a21c07ccd1810b0315ec0953aeff))
30
+
31
+ ### Bug Fixes
32
+
33
+ - add ResultT codegen type alias ([ff2d68f](https://github.com/invertase/react-native-firebase/commit/ff2d68ff8f73092f8ba3c75e007049dd31be822f))
34
+ - emit messaging_notification_opened only for default notification action on iOS. ([#8945](https://github.com/invertase/react-native-firebase/issues/8945)) ([2aec61f](https://github.com/invertase/react-native-firebase/commit/2aec61fff6b888f18379b2ba12807fd9d163b8cc))
35
+ - **ios:** private codegen headers and bridging-safe AppCheck module ([266d7e1](https://github.com/invertase/react-native-firebase/commit/266d7e10020662bfd357d1795bc5f6cfde54f7b7))
36
+ - **ios:** set IPHONEOS_DEPLOYMENT_TARGET to 15.0, update platform support docs/conditionals ([#9108](https://github.com/invertase/react-native-firebase/issues/9108)) ([99d0899](https://github.com/invertase/react-native-firebase/commit/99d089908e3eec6155d73ecf05ff7274ad33c46e)), closes [#8882](https://github.com/invertase/react-native-firebase/issues/8882)
37
+ - **messaging, android:** ignore non-message broadcasts in messaging receiver ([#9105](https://github.com/invertase/react-native-firebase/issues/9105)) ([da17208](https://github.com/invertase/react-native-firebase/commit/da1720836622625acdfe8a5f0f870db688348c08)), closes [firebase-android-sdk#5410](https://github.com/invertase/firebase-android-sdk/issues/5410) [#8040](https://github.com/invertase/react-native-firebase/issues/8040)
38
+ - **messaging, android:** make max stored notifications configurable ([#9111](https://github.com/invertase/react-native-firebase/issues/9111)) ([dc5771f](https://github.com/invertase/react-native-firebase/commit/dc5771f75e599db362c2c9916490284734746ec0)), closes [#8771](https://github.com/invertase/react-native-firebase/issues/8771)
39
+ - **messaging, ios:** make APNs registration timeout independent of main queue ([4cbb19c](https://github.com/invertase/react-native-firebase/commit/4cbb19c68d082d2e632c8db134c79160d18aeb02))
40
+ - **messaging:** willPresentNotification custom notification to work alongside default notification ([#9094](https://github.com/invertase/react-native-firebase/issues/9094)) ([1bad118](https://github.com/invertase/react-native-firebase/commit/1bad118f85aadc600757255d1f9ed525b11d655b))
41
+
6
42
  ## [25.1.0](https://github.com/invertase/react-native-firebase/compare/v25.0.1...v25.1.0) (2026-06-25)
7
43
 
8
44
  **Note:** Version bump only for package @react-native-firebase/messaging
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require_relative '../app/firebase_spm'
2
3
  package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
3
4
  appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json')))
4
5
 
@@ -10,6 +11,7 @@ if coreVersionDetected != coreVersionRequired
10
11
  end
11
12
  firebase_ios_target = appPackage['sdkVersions']['ios']['iosTarget']
12
13
  firebase_macos_target = appPackage['sdkVersions']['ios']['macosTarget']
14
+ firebase_tvos_target = appPackage['sdkVersions']['ios']['tvosTarget']
13
15
 
14
16
  Pod::Spec.new do |s|
15
17
  s.name = "RNFBMessaging"
@@ -25,15 +27,28 @@ Pod::Spec.new do |s|
25
27
  s.social_media_url = 'http://twitter.com/invertaseio'
26
28
  s.ios.deployment_target = firebase_ios_target
27
29
  s.macos.deployment_target = firebase_macos_target
28
- s.source_files = 'ios/**/*.{h,m}'
30
+ s.tvos.deployment_target = firebase_tvos_target
31
+ s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}'
32
+ s.public_header_files = [
33
+ 'ios/RNFBMessaging/RNFBMessagingModule.h',
34
+ ]
35
+ s.private_header_files = [
36
+ 'ios/RNFBMessaging/RNFBMessaging+*.h',
37
+ 'ios/RNFBMessaging/RNFBMessagingSerializer.h',
38
+ 'ios/generated/**/*.h',
39
+ ]
40
+ s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*'
41
+
42
+ s.pod_target_xcconfig = {
43
+ 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/ios/generated/RNFBMessagingTurboModules" "$(PODS_TARGET_SRCROOT)/ios/generated"',
44
+ }
29
45
 
30
46
  s.dependency 'RNFBApp'
31
47
 
32
- # React Native dependencies
33
- if defined?(install_modules_dependencies()) != nil
34
- install_modules_dependencies(s);
35
- else
36
- s.dependency "React-Core"
48
+ install_modules_dependencies(s);
49
+
50
+ if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0')
51
+ raise "#{s.name} requires New Architecture. Enable New Architecture to use this module"
37
52
  end
38
53
 
39
54
  if defined?($FirebaseSDKVersion)
@@ -42,8 +57,12 @@ Pod::Spec.new do |s|
42
57
  end
43
58
 
44
59
  # Firebase dependencies
45
- s.dependency 'Firebase/Messaging', firebase_sdk_version
46
- s.dependency 'FirebaseCoreExtension'
60
+ # FirebaseCoreExtension is a transitive dependency of FirebaseMessaging in SPM,
61
+ # so it only needs to be declared explicitly for CocoaPods.
62
+ firebase_dependency(s, firebase_sdk_version,
63
+ ['FirebaseMessaging'],
64
+ ['Firebase/Messaging', 'FirebaseCoreExtension']
65
+ )
47
66
 
48
67
  if defined?($RNFirebaseAsStaticFramework)
49
68
  Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
@@ -130,6 +130,12 @@ android {
130
130
  targetCompatibility = JavaVersion.VERSION_11
131
131
  }
132
132
  }
133
+
134
+ sourceSets {
135
+ main {
136
+ java.excludes = ['**/generated/jni/**']
137
+ }
138
+ }
133
139
  }
134
140
 
135
141
  repositories {
@@ -147,3 +153,21 @@ ReactNative.shared.applyPackageVersion()
147
153
  ReactNative.shared.applyDefaultExcludes()
148
154
  ReactNative.module.applyAndroidVersions()
149
155
  ReactNative.module.applyReactNativeDependency("api")
156
+
157
+ def isNewArchitectureDisabled() {
158
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true"
159
+ }
160
+
161
+ if (isNewArchitectureDisabled()) {
162
+ def ANSI_RED = "\u001B[31m";
163
+ def ANSI_RESET = "\u001B[0m";
164
+
165
+ println("\n\n\n")
166
+ println(ANSI_RED + "**************************************************************************************************************")
167
+ println("\n\n\n")
168
+ println("New Architecture support is required for @react-native-firebase/messaging")
169
+ println("\n\n\n")
170
+ println("**************************************************************************************************************" + ANSI_RESET)
171
+ println("\n\n\n")
172
+ System.exit(1)
173
+ }
@@ -21,10 +21,10 @@ import android.app.Activity;
21
21
  import android.content.Intent;
22
22
  import android.util.Log;
23
23
  import androidx.core.app.NotificationManagerCompat;
24
+ import com.facebook.fbreact.specs.NativeRNFBTurboMessagingSpec;
24
25
  import com.facebook.react.bridge.ActivityEventListener;
25
26
  import com.facebook.react.bridge.Promise;
26
27
  import com.facebook.react.bridge.ReactApplicationContext;
27
- import com.facebook.react.bridge.ReactMethod;
28
28
  import com.facebook.react.bridge.ReadableMap;
29
29
  import com.facebook.react.bridge.WritableMap;
30
30
  import com.facebook.react.bridge.WritableNativeMap;
@@ -34,20 +34,29 @@ import com.google.firebase.messaging.FirebaseMessaging;
34
34
  import com.google.firebase.messaging.RemoteMessage;
35
35
  import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
36
36
  import io.invertase.firebase.common.ReactNativeFirebaseModule;
37
+ import io.invertase.firebase.common.TaskExecutorService;
37
38
  import java.util.HashMap;
38
39
  import java.util.Map;
40
+ import java.util.concurrent.ExecutorService;
41
+ import javax.annotation.Nullable;
39
42
 
40
- public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModule
43
+ public class NativeRNFBTurboMessaging extends NativeRNFBTurboMessagingSpec
41
44
  implements ActivityEventListener {
42
45
  private static final String TAG = "Messaging";
43
46
  ReadableMap initialNotification = null;
44
- private HashMap<String, Boolean> initialNotificationMap = new HashMap<>();
47
+ private final HashMap<String, Boolean> initialNotificationMap = new HashMap<>();
48
+ private final TaskExecutorService executorService;
45
49
 
46
- ReactNativeFirebaseMessagingModule(ReactApplicationContext reactContext) {
47
- super(reactContext, TAG);
50
+ public NativeRNFBTurboMessaging(ReactApplicationContext reactContext) {
51
+ super(reactContext);
52
+ executorService = new TaskExecutorService("NativeRNFBTurboMessaging");
48
53
  reactContext.addActivityEventListener(this);
49
54
  }
50
55
 
56
+ private ExecutorService getExecutor() {
57
+ return executorService.getExecutor();
58
+ }
59
+
51
60
  private WritableMap popRemoteMessageMapFromMessagingStore(String messageId) {
52
61
  ReactNativeFirebaseMessagingStore messagingStore =
53
62
  ReactNativeFirebaseMessagingStoreHelper.getInstance().getMessagingStore();
@@ -56,54 +65,110 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
56
65
  return remoteMessageMap;
57
66
  }
58
67
 
59
- @ReactMethod
68
+ @Override
69
+ protected Map<String, Object> getTypedExportedConstants() {
70
+ final Map<String, Object> constants = new HashMap<>();
71
+ constants.put("isAutoInitEnabled", FirebaseMessaging.getInstance().isAutoInitEnabled());
72
+ constants.put(
73
+ "isDeliveryMetricsExportToBigQueryEnabled",
74
+ FirebaseMessaging.getInstance().deliveryMetricsExportToBigQueryEnabled());
75
+ constants.put(
76
+ "isNotificationDelegationEnabled",
77
+ FirebaseMessaging.getInstance().isNotificationDelegationEnabled());
78
+ return constants;
79
+ }
80
+
81
+ @Override
82
+ public void getDidOpenSettingsForNotification(Promise promise) {
83
+ promise.resolve(false);
84
+ }
85
+
86
+ @Override
87
+ public void signalBackgroundMessageHandlerSet() {
88
+ // iOS-only; no-op on Android
89
+ }
90
+
91
+ @Override
92
+ public void completeNotificationProcessing() {
93
+ // iOS-only; no-op on Android
94
+ }
95
+
96
+ @Override
97
+ public void getAPNSToken(Promise promise) {
98
+ promise.resolve(null);
99
+ }
100
+
101
+ @Override
102
+ public void setAPNSToken(String token, @Nullable String type, Promise promise) {
103
+ promise.resolve(null);
104
+ }
105
+
106
+ @Override
107
+ public void getIsHeadless(Promise promise) {
108
+ promise.resolve(false);
109
+ }
110
+
111
+ @Override
112
+ public void requestPermission(ReadableMap permissions, Promise promise) {
113
+ promise.resolve(1);
114
+ }
115
+
116
+ @Override
117
+ public void registerForRemoteNotifications(Promise promise) {
118
+ promise.resolve(null);
119
+ }
120
+
121
+ @Override
122
+ public void unregisterForRemoteNotifications(Promise promise) {
123
+ promise.resolve(null);
124
+ }
125
+
126
+ @Override
60
127
  public void getInitialNotification(Promise promise) {
61
128
  if (initialNotification != null) {
62
129
  promise.resolve(initialNotification);
63
130
  initialNotification = null;
64
131
  return;
65
- } else {
66
- Activity activity = getCurrentActivity();
67
-
68
- if (activity != null) {
69
- Intent intent = activity.getIntent();
70
-
71
- if (intent != null && intent.getExtras() != null) {
72
- // messageId can be either one...
73
- String messageId = intent.getExtras().getString("google.message_id");
74
- if (messageId == null) messageId = intent.getExtras().getString("message_id");
75
-
76
- // only handle non-consumed initial notifications
77
- if (messageId != null && initialNotificationMap.get(messageId) == null) {
78
- WritableMap remoteMessageMap;
79
- RemoteMessage remoteMessage =
80
- ReactNativeFirebaseMessagingReceiver.notifications.get(messageId);
81
- if (remoteMessage == null) {
82
- remoteMessageMap = popRemoteMessageMapFromMessagingStore(messageId);
83
- } else {
84
- remoteMessageMap =
85
- ReactNativeFirebaseMessagingSerializer.remoteMessageToWritableMap(remoteMessage);
86
- }
87
- if (remoteMessageMap != null) {
88
- promise.resolve(remoteMessageMap);
89
- initialNotificationMap.put(messageId, true);
90
- return;
91
- }
132
+ }
133
+
134
+ Activity activity = getCurrentActivity();
135
+
136
+ if (activity != null) {
137
+ Intent intent = activity.getIntent();
138
+
139
+ if (intent != null && intent.getExtras() != null) {
140
+ String messageId = intent.getExtras().getString("google.message_id");
141
+ if (messageId == null) messageId = intent.getExtras().getString("message_id");
142
+
143
+ if (messageId != null && initialNotificationMap.get(messageId) == null) {
144
+ WritableMap remoteMessageMap;
145
+ RemoteMessage remoteMessage =
146
+ ReactNativeFirebaseMessagingReceiver.notifications.get(messageId);
147
+ if (remoteMessage == null) {
148
+ remoteMessageMap = popRemoteMessageMapFromMessagingStore(messageId);
149
+ } else {
150
+ remoteMessageMap =
151
+ ReactNativeFirebaseMessagingSerializer.remoteMessageToWritableMap(remoteMessage);
152
+ }
153
+ if (remoteMessageMap != null) {
154
+ promise.resolve(remoteMessageMap);
155
+ initialNotificationMap.put(messageId, true);
156
+ return;
92
157
  }
93
158
  }
94
- } else {
95
- Log.w(
96
- TAG,
97
- "Attempt to call getInitialNotification failed. The current activity is not ready, try"
98
- + " calling the method later in the React lifecycle.");
99
159
  }
160
+ } else {
161
+ Log.w(
162
+ TAG,
163
+ "Attempt to call getInitialNotification failed. The current activity is not ready, try"
164
+ + " calling the method later in the React lifecycle.");
100
165
  }
101
166
 
102
167
  promise.resolve(null);
103
168
  }
104
169
 
105
- @ReactMethod
106
- public void setAutoInitEnabled(Boolean enabled, Promise promise) {
170
+ @Override
171
+ public void setAutoInitEnabled(boolean enabled, Promise promise) {
107
172
  Tasks.call(
108
173
  getExecutor(),
109
174
  () -> {
@@ -115,31 +180,29 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
115
180
  if (task.isSuccessful()) {
116
181
  promise.resolve(FirebaseMessaging.getInstance().isAutoInitEnabled());
117
182
  } else {
118
- rejectPromiseWithExceptionMap(promise, task.getException());
183
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
184
+ promise, task.getException());
119
185
  }
120
186
  });
121
187
  }
122
188
 
123
- @ReactMethod
189
+ @Override
124
190
  public void isNotificationDelegationEnabled(Promise promise) {
125
191
  Tasks.call(
126
- getExecutor(),
127
- () -> {
128
- FirebaseMessaging.getInstance().isNotificationDelegationEnabled();
129
- return null;
130
- })
192
+ getExecutor(), () -> FirebaseMessaging.getInstance().isNotificationDelegationEnabled())
131
193
  .addOnCompleteListener(
132
194
  task -> {
133
195
  if (task.isSuccessful()) {
134
196
  promise.resolve(task.getResult());
135
197
  } else {
136
- rejectPromiseWithExceptionMap(promise, task.getException());
198
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
199
+ promise, task.getException());
137
200
  }
138
201
  });
139
202
  }
140
203
 
141
- @ReactMethod
142
- public void setNotificationDelegationEnabled(Boolean enabled, Promise promise) {
204
+ @Override
205
+ public void setNotificationDelegationEnabled(boolean enabled, Promise promise) {
143
206
  Tasks.call(
144
207
  getExecutor(),
145
208
  () -> {
@@ -151,12 +214,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
151
214
  if (task.isSuccessful()) {
152
215
  promise.resolve(FirebaseMessaging.getInstance().isNotificationDelegationEnabled());
153
216
  } else {
154
- rejectPromiseWithExceptionMap(promise, task.getException());
217
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
218
+ promise, task.getException());
155
219
  }
156
220
  });
157
221
  }
158
222
 
159
- @ReactMethod
223
+ @Override
160
224
  public void getToken(String appName, String senderId, Promise promise) {
161
225
  FirebaseMessaging messagingInstance =
162
226
  FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
@@ -166,12 +230,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
166
230
  if (task.isSuccessful()) {
167
231
  promise.resolve(task.getResult());
168
232
  } else {
169
- rejectPromiseWithExceptionMap(promise, task.getException());
233
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
234
+ promise, task.getException());
170
235
  }
171
236
  });
172
237
  }
173
238
 
174
- @ReactMethod
239
+ @Override
175
240
  public void deleteToken(String appName, String senderId, Promise promise) {
176
241
  FirebaseMessaging messagingInstance =
177
242
  FirebaseApp.getInstance(appName).get(FirebaseMessaging.class);
@@ -186,12 +251,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
186
251
  if (task.isSuccessful()) {
187
252
  promise.resolve(task.getResult());
188
253
  } else {
189
- rejectPromiseWithExceptionMap(promise, task.getException());
254
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
255
+ promise, task.getException());
190
256
  }
191
257
  });
192
258
  }
193
259
 
194
- @ReactMethod
260
+ @Override
195
261
  public void hasPermission(Promise promise) {
196
262
  Tasks.call(
197
263
  getExecutor(),
@@ -203,12 +269,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
203
269
  if (task.isSuccessful()) {
204
270
  promise.resolve(task.getResult() ? 1 : 0);
205
271
  } else {
206
- rejectPromiseWithExceptionMap(promise, task.getException());
272
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
273
+ promise, task.getException());
207
274
  }
208
275
  });
209
276
  }
210
277
 
211
- @ReactMethod
278
+ @Override
212
279
  public void sendMessage(ReadableMap remoteMessageMap, Promise promise) {
213
280
  Tasks.call(
214
281
  getExecutor(),
@@ -224,12 +291,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
224
291
  if (task.isSuccessful()) {
225
292
  promise.resolve(task.getResult());
226
293
  } else {
227
- rejectPromiseWithExceptionMap(promise, task.getException());
294
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
295
+ promise, task.getException());
228
296
  }
229
297
  });
230
298
  }
231
299
 
232
- @ReactMethod
300
+ @Override
233
301
  public void subscribeToTopic(String topic, Promise promise) {
234
302
  FirebaseMessaging.getInstance()
235
303
  .subscribeToTopic(topic)
@@ -238,12 +306,13 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
238
306
  if (task.isSuccessful()) {
239
307
  promise.resolve(task.getResult());
240
308
  } else {
241
- rejectPromiseWithExceptionMap(promise, task.getException());
309
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
310
+ promise, task.getException());
242
311
  }
243
312
  });
244
313
  }
245
314
 
246
- @ReactMethod
315
+ @Override
247
316
  public void unsubscribeFromTopic(String topic, Promise promise) {
248
317
  FirebaseMessaging.getInstance()
249
318
  .unsubscribeFromTopic(topic)
@@ -252,13 +321,14 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
252
321
  if (task.isSuccessful()) {
253
322
  promise.resolve(task.getResult());
254
323
  } else {
255
- rejectPromiseWithExceptionMap(promise, task.getException());
324
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
325
+ promise, task.getException());
256
326
  }
257
327
  });
258
328
  }
259
329
 
260
- @ReactMethod
261
- public void setDeliveryMetricsExportToBigQuery(Boolean enabled, Promise promise) {
330
+ @Override
331
+ public void setDeliveryMetricsExportToBigQuery(boolean enabled, Promise promise) {
262
332
  Tasks.call(
263
333
  getExecutor(),
264
334
  () -> {
@@ -271,24 +341,12 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
271
341
  promise.resolve(
272
342
  FirebaseMessaging.getInstance().deliveryMetricsExportToBigQueryEnabled());
273
343
  } else {
274
- rejectPromiseWithExceptionMap(promise, task.getException());
344
+ ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
345
+ promise, task.getException());
275
346
  }
276
347
  });
277
348
  }
278
349
 
279
- @Override
280
- public Map<String, Object> getConstants() {
281
- final Map<String, Object> constants = new HashMap<>();
282
- constants.put("isAutoInitEnabled", FirebaseMessaging.getInstance().isAutoInitEnabled());
283
- constants.put(
284
- "isDeliveryMetricsExportToBigQueryEnabled",
285
- FirebaseMessaging.getInstance().deliveryMetricsExportToBigQueryEnabled());
286
- constants.put(
287
- "isNotificationDelegationEnabled",
288
- FirebaseMessaging.getInstance().isNotificationDelegationEnabled());
289
- return constants;
290
- }
291
-
292
350
  @Override
293
351
  public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
294
352
  // noop
@@ -313,8 +371,6 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
313
371
  }
314
372
 
315
373
  if (remoteMessageMap != null) {
316
- // WritableNativeMap not be consumed twice. But it is resolved in future and in event
317
- // below. Make a copy - issue #5231
318
374
  WritableNativeMap newInitialNotification = new WritableNativeMap();
319
375
  newInitialNotification.merge(remoteMessageMap);
320
376
  initialNotification = newInitialNotification;
@@ -329,4 +385,10 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
329
385
  }
330
386
  }
331
387
  }
388
+
389
+ @Override
390
+ public void invalidate() {
391
+ super.invalidate();
392
+ executorService.shutdown();
393
+ }
332
394
  }
@@ -30,7 +30,7 @@ public class ReactNativeFirebaseMessagingPackage implements ReactPackage {
30
30
  @Override
31
31
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
32
32
  List<NativeModule> modules = new ArrayList<>();
33
- modules.add(new ReactNativeFirebaseMessagingModule(reactContext));
33
+ modules.add(new NativeRNFBTurboMessaging(reactContext));
34
34
  return modules;
35
35
  }
36
36
 
@@ -26,6 +26,22 @@ public class ReactNativeFirebaseMessagingReceiver extends BroadcastReceiver {
26
26
  Log.e(TAG, "broadcast intent received with no extras");
27
27
  return;
28
28
  }
29
+ // Mirror the routing guards of the official FirebaseMessagingService: the
30
+ // c2dm RECEIVE action also carries control broadcasts (deleted_messages,
31
+ // send_event, send_error) and non-message intents such as the wrapped
32
+ // NOTIFICATION_DISMISS analytics intent that FCM attaches as deleteIntent
33
+ // to notifications it displays itself. The official SDK routes those to
34
+ // dedicated callbacks and never surfaces them through onMessageReceived;
35
+ // without these guards they are emitted to JS as empty remote messages.
36
+ String messageType = intent.getStringExtra("message_type");
37
+ if (messageType != null && !"gcm".equals(messageType)) {
38
+ Log.d(TAG, "broadcast ignored, non-message type: " + messageType);
39
+ return;
40
+ }
41
+ if (intent.getStringExtra("google.message_id") == null) {
42
+ Log.d(TAG, "broadcast ignored, no google.message_id (not an FCM message)");
43
+ return;
44
+ }
29
45
  RemoteMessage remoteMessage = new RemoteMessage(intent.getExtras());
30
46
  ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
31
47