@react-native-firebase/app 26.3.3 → 27.0.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 (283) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +10 -27
  3. package/RNFBApp.podspec +13 -5
  4. package/android/build.gradle +3 -0
  5. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.kt +29 -0
  6. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.kt +146 -0
  7. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.kt +156 -0
  8. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.kt +44 -0
  9. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.kt +100 -0
  10. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.kt +250 -0
  11. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.kt +64 -0
  12. package/android/src/reactnative/java/io/invertase/firebase/app/{ReactNativeFirebaseAppInitProvider.java → ReactNativeFirebaseAppInitProvider.kt} +3 -4
  13. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.kt +47 -0
  14. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.kt +33 -0
  15. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +1 -1
  16. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.kt +185 -0
  17. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.kt +35 -0
  18. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.kt +662 -0
  19. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.kt +103 -0
  20. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.kt +96 -0
  21. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.kt +140 -0
  22. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.kt +109 -0
  23. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.kt +451 -0
  24. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{ContextProvider.java → ContextProvider.kt} +8 -8
  25. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeError.java → NativeError.kt} +8 -8
  26. package/android/src/reactnative/java/io/invertase/firebase/interfaces/{NativeEvent.java → NativeEvent.kt} +6 -6
  27. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.kt +219 -0
  28. package/android/src/test/java/expo/core/ModuleRegistry.java +9 -0
  29. package/android/src/test/java/io/invertase/firebase/app/NativeRNFBTurboAppTest.java +208 -60
  30. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppComponentsJavaCompatibilityTest.java +70 -0
  31. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppJavaCompatibilityTest.java +60 -0
  32. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackageTest.java +165 -0
  33. package/android/src/test/java/io/invertase/firebase/app/ReactNativeFirebaseAppTest.kt +167 -0
  34. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseJavaCompatibilityTest.java +112 -0
  35. package/android/src/test/java/io/invertase/firebase/common/RCTConvertFirebaseTest.kt +317 -0
  36. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.kt +309 -0
  37. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterJavaCompatibilityTest.java +176 -0
  38. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitterTest.java +144 -13
  39. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseEventTest.kt +61 -0
  40. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONJavaCompatibilityTest.java +85 -0
  41. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.kt +296 -0
  42. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaJavaCompatibilityTest.java +67 -0
  43. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseMetaTest.kt +246 -0
  44. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseModuleTest.kt +254 -0
  45. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesJavaCompatibilityTest.java +87 -0
  46. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebasePreferencesTest.kt +260 -0
  47. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsJavaCompatibilityTest.java +255 -0
  48. package/android/src/test/java/io/invertase/firebase/common/SharedUtilsTest.kt +674 -0
  49. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.kt +290 -0
  50. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebaseModuleJavaCompatibilityTest.java +178 -0
  51. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesJavaCompatibilityTest.java +99 -0
  52. package/android/src/test/java/io/invertase/firebase/common/UniversalFirebasePreferencesTest.kt +217 -0
  53. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleJavaCompatibilityTest.java +176 -0
  54. package/android/src/test/java/io/invertase/firebase/commoncompat/ReactNativeFirebaseModuleKotlinCompatibilityTest.kt +52 -0
  55. package/android/src/test/java/io/invertase/firebase/interfaces/InterfacesJavaCompatibilityTest.java +144 -0
  56. package/android/src/test/java/io/invertase/firebase/interfaces/NativeEventTest.kt +56 -0
  57. package/android/src/test/java/io/invertase/firebase/utils/NativeRNFBTurboUtilsTest.java +517 -23
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/Base64.js +13 -21
  61. package/dist/module/common/Base64.js.map +1 -1
  62. package/dist/module/common/deeps.js +3 -0
  63. package/dist/module/common/deeps.js.map +1 -1
  64. package/dist/module/common/index.js +17 -9
  65. package/dist/module/common/index.js.map +1 -1
  66. package/dist/module/internal/FirebaseModule.js.map +1 -1
  67. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  68. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  69. package/dist/module/internal/SharedEventEmitter.js +3 -1
  70. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  71. package/dist/module/internal/asyncStorage.js +7 -11
  72. package/dist/module/internal/asyncStorage.js.map +1 -1
  73. package/dist/module/internal/index.js +1 -0
  74. package/dist/module/internal/index.js.map +1 -1
  75. package/dist/module/internal/logger.js +44 -40
  76. package/dist/module/internal/logger.js.map +1 -1
  77. package/dist/module/internal/nativeModuleAndroidIos.js +2 -29
  78. package/dist/module/internal/nativeModuleAndroidIos.js.map +1 -1
  79. package/dist/module/internal/nativeModuleDebug.js +74 -0
  80. package/dist/module/internal/nativeModuleDebug.js.map +1 -0
  81. package/dist/module/internal/nativeModuleWeb.js +9 -29
  82. package/dist/module/internal/nativeModuleWeb.js.map +1 -1
  83. package/dist/module/internal/registry/app.js +8 -2
  84. package/dist/module/internal/registry/app.js.map +1 -1
  85. package/dist/module/internal/registry/modular.js +2 -2
  86. package/dist/module/internal/registry/modular.js.map +1 -1
  87. package/dist/module/internal/registry/nativeModule.js +3 -3
  88. package/dist/module/internal/registry/nativeModule.js.map +1 -1
  89. package/dist/module/internal/web/RNFBAppModule.js +16 -15
  90. package/dist/module/internal/web/RNFBAppModule.js.map +1 -1
  91. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  92. package/dist/module/internal/web/memidb/lib/FakeEventTarget.js.map +1 -1
  93. package/dist/module/types/app.js.map +1 -1
  94. package/dist/module/types/internal.js +2 -0
  95. package/dist/module/version.js +1 -1
  96. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  97. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  98. package/dist/typescript/lib/common/Base64.d.ts.map +1 -1
  99. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  100. package/dist/typescript/lib/common/index.d.ts.map +1 -1
  101. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  102. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  103. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  104. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  105. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  106. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  107. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  108. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  109. package/dist/typescript/lib/internal/asyncStorage.d.ts.map +1 -1
  110. package/dist/typescript/lib/internal/index.d.ts +1 -0
  111. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  112. package/dist/typescript/lib/internal/logger.d.ts.map +1 -1
  113. package/dist/typescript/lib/internal/nativeModuleAndroidIos.d.ts.map +1 -1
  114. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts +2 -0
  115. package/dist/typescript/lib/internal/nativeModuleDebug.d.ts.map +1 -0
  116. package/dist/typescript/lib/internal/nativeModuleWeb.d.ts.map +1 -1
  117. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  118. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts +7 -7
  119. package/dist/typescript/lib/internal/web/RNFBAppModule.d.ts.map +1 -1
  120. package/dist/typescript/lib/types/app.d.ts +10 -3
  121. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  122. package/dist/typescript/lib/types/internal.d.ts +12 -0
  123. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  124. package/dist/typescript/lib/version.d.ts +1 -1
  125. package/firebase-schema.json +5 -1
  126. package/firebase_spm.rb +552 -96
  127. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  128. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  129. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  130. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  131. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  132. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  133. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  134. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  135. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  136. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  137. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  138. package/ios/RNFBApp/RNFBAppModule.mm +67 -204
  139. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  140. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  141. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  142. package/ios/RNFBApp/RNFBHandleMap.h +73 -0
  143. package/ios/RNFBApp/RNFBHandleMap.m +87 -0
  144. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  145. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  146. package/ios/RNFBApp/RNFBJSON.m +22 -38
  147. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  148. package/ios/RNFBApp/RNFBMeta.m +24 -26
  149. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  150. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  151. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  152. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  153. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  154. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  155. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  156. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  157. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  158. package/ios/RNFBApp/RNFBSharedUtils.m +109 -197
  159. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  160. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  161. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  162. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  163. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  164. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  165. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  166. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  167. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  168. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  169. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  170. package/ios/RNFBApp/RNFBVersion.m +1 -1
  171. package/ios/RNFBApp.xcodeproj/project.pbxproj +106 -0
  172. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  173. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  174. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  175. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  176. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  177. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  178. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  179. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  180. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  181. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  182. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  183. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  184. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  185. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  186. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  187. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  188. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  189. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  190. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  191. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  192. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  193. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  194. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  195. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  196. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  197. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  198. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  199. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  200. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  201. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +590 -0
  202. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAppUnitTests.xcscheme +69 -0
  203. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  204. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  205. package/ios/RNFBAppUnitTests/RNFBHandleMapTests.m +238 -0
  206. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  207. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  208. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  209. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  210. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  211. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  212. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  213. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  214. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  215. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  216. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  217. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  218. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  219. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  220. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  221. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  222. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  223. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  224. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  225. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  226. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  227. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  228. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  229. package/ios/RNFBFirebase/Package.swift +53 -0
  230. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  231. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  232. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  233. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  234. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  235. package/{android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +22 -17
  236. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  237. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  238. package/ios_config.sh +50 -22
  239. package/lib/FirebaseApp.ts +10 -0
  240. package/lib/common/Base64.ts +10 -16
  241. package/lib/common/deeps.ts +3 -0
  242. package/lib/common/index.ts +20 -9
  243. package/lib/internal/FirebaseModule.ts +6 -3
  244. package/lib/internal/NativeModules.ts +4 -1
  245. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  246. package/lib/internal/SharedEventEmitter.ts +5 -1
  247. package/lib/internal/asyncStorage.ts +7 -11
  248. package/lib/internal/index.ts +1 -0
  249. package/lib/internal/logger.ts +53 -43
  250. package/lib/internal/nativeModuleAndroidIos.ts +2 -40
  251. package/lib/internal/nativeModuleDebug.ts +97 -0
  252. package/lib/internal/nativeModuleWeb.ts +10 -40
  253. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  254. package/lib/internal/registry/app.ts +8 -2
  255. package/lib/internal/registry/modular.ts +2 -2
  256. package/lib/internal/registry/nativeModule.ts +3 -3
  257. package/lib/internal/web/RNFBAppModule.ts +16 -15
  258. package/lib/internal/web/memidb/lib/FakeEventTarget.js +3 -1
  259. package/lib/types/app.ts +10 -3
  260. package/lib/types/internal.ts +19 -0
  261. package/lib/version.ts +1 -1
  262. package/package.json +9 -8
  263. package/plugin/build/ios/appDelegate.js +19 -9
  264. package/plugin/build/ios/podfile.js +16 -16
  265. package/plugin/build/pluginConfig.d.ts +4 -2
  266. package/plugin/src/ios/appDelegate.ts +45 -15
  267. package/plugin/src/ios/podfile.ts +20 -23
  268. package/plugin/src/pluginConfig.ts +4 -2
  269. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -124
  270. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  271. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  272. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -222
  273. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  274. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  275. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -191
  276. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  277. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  278. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -107
  279. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  280. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  281. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  282. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  283. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
package/CHANGELOG.md CHANGED
@@ -3,6 +3,81 @@
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
+ ## [27.0.0](https://github.com/invertase/react-native-firebase/compare/v26.4.0...v27.0.0) (2026-10-19)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ - **ios:** drop CocoaPods Firebase matrix; SPM-only
11
+ - **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13
12
+ - **ml:** remove discontinued @react-native-firebase/ml package
13
+ - **app, ios:** initializeApp now reads automaticDataCollectionEnabled as a
14
+ boolean. Previously any non-nil value (including JS false) enabled collection
15
+ via pointer cast; false, 0, null, and absent now disable it. See
16
+ docs/migrating-to-v27.mdx.
17
+
18
+ ### Features
19
+
20
+ - **app, sdk:** bump Firebase Android 35, Apple 13, and JS 13 ([0ca03d1](https://github.com/invertase/react-native-firebase/commit/0ca03d11b0c271fb37cfbee8a0c3074a21969f0b))
21
+ - **app, sdk:** bump Firebase Android SDK to 34.19.0 ([ca054bc](https://github.com/invertase/react-native-firebase/commit/ca054bc2fdcb298575f1e7412aa8b02540d53def))
22
+ - **app, sdk:** bump Firebase iOS SDK to 12.19.0 ([95dca6a](https://github.com/invertase/react-native-firebase/commit/95dca6a4eeb849bc2910946e1477694635bee6b7))
23
+ - **app, sdk:** bump Firebase JS SDK to 12.18.0 ([5e2617d](https://github.com/invertase/react-native-firebase/commit/5e2617dcddfd55f10f441f2e9d83fe7b4681470e))
24
+ - **app, sdk:** bump Firebase JS SDK to 12.19.0 ([34d0318](https://github.com/invertase/react-native-firebase/commit/34d031849146527ab9b9ee3ba4fbd207bdab0803))
25
+ - **messaging:** add messaging_installation_id_enabled firebase.json opt-in ([e9c9741](https://github.com/invertase/react-native-firebase/commit/e9c9741a65a76cc102d2d27ff675c453fd506243))
26
+ - **ml:** remove discontinued @react-native-firebase/ml package ([58622b1](https://github.com/invertase/react-native-firebase/commit/58622b1a24a32008fd33ff56346cceb4f71bc29f))
27
+
28
+ ### Bug Fixes
29
+
30
+ - **app, android:** bind nullable recent-task fields before use ([bed8c71](https://github.com/invertase/react-native-firebase/commit/bed8c71313cd3c0bf60bf9a9d86417ae550ec98f))
31
+ - **app, android:** harden RecentTaskInfo null and JSON parse ([908400b](https://github.com/invertase/react-native-firebase/commit/908400b230cfd5d7d4406da9bb350332d6bc8c4c))
32
+ - **app, expo:** match scene-based AppDelegate for Expo SDK 58 config plugin ([dce165d](https://github.com/invertase/react-native-firebase/commit/dce165d7283a30060c5b08066cf5841d9247105a))
33
+ - **app, ios:** clarify SPM static linkage error when use_frameworks is absent ([cdf99cd](https://github.com/invertase/react-native-firebase/commit/cdf99cde79d46be737b671096e1cc3af7a14f58f))
34
+ - **app, ios:** import ObjC NullSentinelDecoder in SharedUtils ([9a565c8](https://github.com/invertase/react-native-firebase/commit/9a565c879edc11c18b5c7ffca92c7f22e2b639e7))
35
+ - **app, ios:** pin SPM Firebase SDK and retain Measurement ObjC categories ([7e271af](https://github.com/invertase/react-native-firebase/commit/7e271afecab65ef150140056171265e9c9ca621c))
36
+ - **app, ios:** read automaticDataCollectionEnabled as a boolean ([cc18140](https://github.com/invertase/react-native-firebase/commit/cc181400e465895bdb012eff881209315adaed70))
37
+ - **app, ios:** tighten the dynamic Firebase probe and import guard ([cac843c](https://github.com/invertase/react-native-firebase/commit/cac843c09156237751274073c67b6105fa7b4188))
38
+ - **app, storage:** link Photos framework on tvOS ([56f5c1f](https://github.com/invertase/react-native-firebase/commit/56f5c1fcf83bc89d8cd80f019696e13bc96578dd))
39
+ - **app, tests:** ignore iOS host stubs in TurboModule spec parity lookup ([e2f515d](https://github.com/invertase/react-native-firebase/commit/e2f515da36a180d16d6f6002886c17f6fd511749))
40
+ - **app,database:** resolve platform native module when bundlers apply package exports ([959d91f](https://github.com/invertase/react-native-firebase/commit/959d91fc79d7155d1d9a08e1f836789e6e6d6156))
41
+ - **app:** import e2e native module resolver via internal barrel ([93f51ff](https://github.com/invertase/react-native-firebase/commit/93f51fff8b2b4f1355bc213f5f98fbbf7986c7e0))
42
+ - **app:** reject unsafe deepSet path segments ([ec3ac24](https://github.com/invertase/react-native-firebase/commit/ec3ac2455b30cfabc501845364623d9ab55e7193))
43
+ - **app:** restore vendor EventEmitter for RN macOS 0.78 ([6b13c9d](https://github.com/invertase/react-native-firebase/commit/6b13c9d468abde5b5acc990e43a3d3fd6c7a140e))
44
+ - **app:** seed automaticDataCollectionEnabled from the native initializeApp result ([5d187f9](https://github.com/invertase/react-native-firebase/commit/5d187f9271f183ccac4d7b70e233a4ccd2145fd0))
45
+ - **app:** stop evaluating firebase.json content as Ruby/Python source in ios_config.sh ([d333ab3](https://github.com/invertase/react-native-firebase/commit/d333ab39a83454606d9ede4aa4a3c031a63cf898))
46
+ - **app:** swizzle null sentinels after codegen converters load ([bcff184](https://github.com/invertase/react-native-firebase/commit/bcff18471b187bda0476c8bbc76e4c216de58ec2))
47
+ - **ci:** unblock Yarn hardened CI and Xcode 27 iOS archive ([9c63630](https://github.com/invertase/react-native-firebase/commit/9c636307e9f87e106e802f5d39d2be32ef2cecdb))
48
+ - **e2e:** skip watchman watch-del when a sibling Metro owns the root ([7695132](https://github.com/invertase/react-native-firebase/commit/769513224d0e6f9bb6fb2a98c578411a5016615d))
49
+
50
+ ### Continuous Integration
51
+
52
+ - **ios:** drop CocoaPods Firebase matrix; SPM-only ([89e270f](https://github.com/invertase/react-native-firebase/commit/89e270f3d1f4c1f3c22e32ca539ebe3da30dbd7e))
53
+
54
+ ## [26.4.0](https://github.com/invertase/react-native-firebase/compare/v26.3.3...v26.4.0) (2026-09-05)
55
+
56
+ ### Features
57
+
58
+ - **app:** add RNFBHandleMap for thread-safe handle registries ([d28edd5](https://github.com/invertase/react-native-firebase/commit/d28edd579281da523b626934e89a14dd38dd3ed8))
59
+
60
+ ### Bug Fixes
61
+
62
+ - **app, android:** clear stale custom auth domains ([ccde348](https://github.com/invertase/react-native-firebase/commit/ccde3483511efd1c54bcc4676bd02893f28e9014))
63
+ - **app, android:** discard tasks posted to shut-down transactional executors ([de98eaa](https://github.com/invertase/react-native-firebase/commit/de98eaa9ff0484eeb9e00ec99d5228067611a4f3))
64
+ - **app, expo:** add missing Firebase imports ([7d6f19c](https://github.com/invertase/react-native-firebase/commit/7d6f19c5ba513c5880dd401e225ce19d550e27df))
65
+ - **app, ios:** clear stale custom auth domains ([d747981](https://github.com/invertase/react-native-firebase/commit/d7479818e52f4b4df84bba53c53345942b80af85))
66
+ - **app:** handle empty Android Firebase JSON ([5c48832](https://github.com/invertase/react-native-firebase/commit/5c48832f70a62c1061448a723f1e6a193e09c74a))
67
+ - **app:** isolate native routing keys ([fd13a7a](https://github.com/invertase/react-native-firebase/commit/fd13a7adf84791ce1c1c4ce38a1728a86ae9c6c0))
68
+ - **app:** make debug native proxies behavior-safe ([6caff3c](https://github.com/invertase/react-native-firebase/commit/6caff3cfc706133d132a2762b355c65979631555))
69
+ - **app:** parse data URL payloads completely ([eb5d54e](https://github.com/invertase/react-native-firebase/commit/eb5d54e8bdbd6748e6c024b26f19bf63b764d5bb))
70
+ - **app:** preserve empty memory storage values ([41ac6bc](https://github.com/invertase/react-native-firebase/commit/41ac6bc2f1113a6412e23dd171752f6e5762c335))
71
+ - **app:** preserve memidb event listeners ([c8648a6](https://github.com/invertase/react-native-firebase/commit/c8648a622533afd2f2a94ed36c3acd57c611a2b2))
72
+ - **app:** preserve web Promise contracts ([36c586e](https://github.com/invertase/react-native-firebase/commit/36c586ea908a2faaebf1d40846497bde096a779c))
73
+ - **app:** reject FileReader startup failures ([08319ae](https://github.com/invertase/react-native-firebase/commit/08319aed8191ab823a506b3166c18b8ef02853ac))
74
+ - **app:** retain global logger configuration ([23aeb7b](https://github.com/invertase/react-native-firebase/commit/23aeb7bb5fe60f9421ba81b3f88c859dfd6d3d49))
75
+ - **app:** support arbitrary web storage keys ([c2c9f42](https://github.com/invertase/react-native-firebase/commit/c2c9f4261464bf56c3e6521f54448dbe4649392f))
76
+ - **app:** support prototype-named apps ([0ed7a0f](https://github.com/invertase/react-native-firebase/commit/0ed7a0fd7c99c894e2b94fd3de733dfa43096af2))
77
+ - **auth, ios:** look up customAuthDomains with JS app name ([9873f61](https://github.com/invertase/react-native-firebase/commit/9873f618a972c3324ec05b9e30f5aaefa7ab163b))
78
+ - **database:** use RNFBHandleMap for transaction and query maps ([8adba4c](https://github.com/invertase/react-native-firebase/commit/8adba4cb88dffec2442ea0fe37738d1080d0a185))
79
+ - **messaging, android:** support disabled notification storage ([afaba0b](https://github.com/invertase/react-native-firebase/commit/afaba0b3862b65a2bd83bbbfebfae3ac576811fd))
80
+
6
81
  ## [26.3.3](https://github.com/invertase/react-native-firebase/compare/v26.3.2...v26.3.3) (2026-09-01)
7
82
 
8
83
  ### Bug Fixes
package/README.md CHANGED
@@ -36,40 +36,23 @@ yarn add @react-native-firebase/app
36
36
 
37
37
  - [Utils](https://rnfirebase.io/app/utils)
38
38
 
39
- ## iOS Dependency Resolution: SPM vs CocoaPods
39
+ ## iOS Dependency Resolution (SPM-only)
40
40
 
41
- React Native 0.75 and newer use Swift Package Manager by default to resolve
42
- Firebase iOS SDK dependencies. SPM requires dynamic linkage:
41
+ Firebase Apple SDK 13+ is distributed **only** via Swift Package Manager.
42
+ React Native Firebase requires React Native 0.75+ (`spm_dependency`) and
43
+ dynamic linkage:
43
44
 
44
45
  ```ruby
45
46
  use_frameworks! :linkage => :dynamic
46
47
  ```
47
48
 
48
- To use CocoaPods instead, add this before any target block in your Podfile:
49
+ `$RNFirebaseDisableSPM = true` and Expo `ios.disableSPM: true` /
50
+ `disableSPM: true` **fail** `pod install` / prebuild — CocoaPods Firebase is
51
+ no longer available. Remove those flags and stay on SPM + dynamic frameworks.
49
52
 
50
- ```ruby
51
- $RNFirebaseDisableSPM = true
52
- ```
53
-
54
- Expo projects can set the same flag through the config plugin, which adds it
55
- to the generated Podfile during prebuild:
56
-
57
- ```json
58
- [
59
- "@react-native-firebase/app",
60
- {
61
- "ios": {
62
- "disableSPM": true
63
- }
64
- }
65
- ]
66
- ```
67
-
68
- CocoaPods mode supports static or dynamic linkage. React Native versions older
69
- than 0.75 fall back to CocoaPods automatically.
70
-
71
- See the [iOS SPM guide](https://rnfirebase.io/ios-spm) for Xcode 26 setup,
72
- Expo configuration, framework-embedding fallback, and troubleshooting.
53
+ See [iOS SPM Support](https://rnfirebase.io/ios-spm) and
54
+ [Migrating to v27](https://rnfirebase.io/migrating-to-v27) for setup,
55
+ Expo configuration, and troubleshooting.
73
56
 
74
57
  ## License
75
58
 
package/RNFBApp.podspec CHANGED
@@ -23,9 +23,15 @@ Pod::Spec.new do |s|
23
23
  s.macos.deployment_target = firebase_macos_target
24
24
  s.tvos.deployment_target = firebase_tvos_target
25
25
  s.cocoapods_version = '>= 1.12.0'
26
- s.source_files = "ios/**/*.{h,m,mm,cpp}"
26
+ s.swift_version = '5.10'
27
+ s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
27
28
  s.private_header_files = "ios/**/*.h"
28
- s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*'
29
+ # CocoaPods FileList uses FNM_PATHNAME: `ios/*UnitTests/**` does not match nested
30
+ # paths like `ios/RNFBAppUnitTests/HostStubs/**` (those would compile into the pod).
31
+ # CocoaPods FileList uses FNM_PATHNAME: a trailing `/**` alone does not match
32
+ # nested files (same reason UnitTests use `/**/*`). Exclude the CI-only local
33
+ # SPM package so its sources are never compiled into the RNFBApp pod.
34
+ s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*', 'ios/*UnitTests/**/*', 'ios/RNFBFirebase/**/*'
29
35
 
30
36
  # Fail fast for old architecture users, but safely in case the variable goes away
31
37
  # completely in future react-native versions
@@ -42,15 +48,17 @@ Pod::Spec.new do |s|
42
48
  "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
43
49
  }
44
50
 
45
- # RNFBUtilsModule.mm uses PHAsset (Photos.framework) to resolve local asset paths.
51
+ # RNFBUtilsModule+PhotoAssets.m uses PHAsset (Photos.framework) to resolve local asset paths.
46
52
  # Not declaring this explicitly used to work by luck (CocoaPods normally relies on
47
53
  # this declaration -- not Clang autolinking -- to populate OTHER_LDFLAGS), but with
48
54
  # use_frameworks! each pod is a standalone dynamic framework that must resolve its
49
55
  # own symbols at its own link step, so the missing declaration now surfaces as
50
- # "Undefined symbols ... _OBJC_CLASS_$_PHAsset". iOS/macOS only -- PhotoKit doesn't
51
- # exist on tvOS.
56
+ # "Undefined symbols ... _OBJC_CLASS_$_PHAsset". PhotoKit is available on
57
+ # tvOS 10+, and this .m file emits no Clang autolink record, so tvOS needs
58
+ # the same explicit link.
52
59
  s.ios.frameworks = 'Photos'
53
60
  s.osx.frameworks = 'Photos'
61
+ s.tvos.frameworks = 'Photos'
54
62
 
55
63
  # React Native dependencies
56
64
  if defined?(install_modules_dependencies()) != nil
@@ -14,6 +14,7 @@ buildscript {
14
14
 
15
15
  dependencies {
16
16
  classpath("com.android.tools.build:gradle:8.4.0")
17
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.findProperty('kotlinVersion') ?: '2.4.0'}")
17
18
  }
18
19
  }
19
20
  }
@@ -22,6 +23,8 @@ plugins {
22
23
  id "io.invertase.gradle.build" version "1.5"
23
24
  }
24
25
 
26
+ apply plugin: "org.jetbrains.kotlin.android"
27
+
25
28
  def packageJson = PackageJson.getForProject(project)
26
29
  def firebaseBomVersion = packageJson['sdkVersions']['android']['firebase']
27
30
  def playServicesAuthVersion = packageJson['sdkVersions']['android']['playServicesAuth']
@@ -0,0 +1,29 @@
1
+ package io.invertase.firebase.common
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ /**
21
+ * Thrown when [RNFBHandleMap.put] is asked to register an id that is already occupied.
22
+ *
23
+ * This remains a checked Java-visible exception ([Exception], not [RuntimeException]) so callers
24
+ * must handle collisions explicitly. There is no upsert: replace an existing registration with
25
+ * [RNFBHandleMap.take] then [RNFBHandleMap.put].
26
+ */
27
+ open class RNFBHandleCollisionException(
28
+ id: Any?,
29
+ ) : Exception("Handle id already registered: $id")
@@ -0,0 +1,146 @@
1
+ package io.invertase.firebase.common
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import java.util.function.Predicate
21
+
22
+ /**
23
+ * Thread-safe id → handle registry. The lock only moves pointers; this class never invokes methods
24
+ * on stored values (no SDK `cancel`/`remove`). Callers [take] or [takeAll], then act on the returned
25
+ * object(s) outside the lock.
26
+ *
27
+ * [put] is unique: an occupied id throws [RNFBHandleCollisionException]. There is no upsert. Use
28
+ * [putIfAbsent] (first wins), [putIfAbsentOrSame] (first wins or same instance), or [putReplacing]
29
+ * (last wins) for atomic upsert. Replace at the call site with `take` then `put` only when neither
30
+ * helper fits.
31
+ *
32
+ * **Do not lock on the map or on a [RNFBHandleMap] instance.** Callers that synchronize on `this`
33
+ * (or on the internal map) can deadlock with the dedicated monitor. Android uses a private [lock]
34
+ * object; never expose it and never `synchronized(this)` around these methods.
35
+ */
36
+ open class RNFBHandleMap<K, V> {
37
+ private val lock = Any()
38
+ private val map = HashMap<K, V>()
39
+
40
+ /**
41
+ * Registers [handle] under [id].
42
+ *
43
+ * @throws RNFBHandleCollisionException if [id] is already occupied
44
+ */
45
+ @Throws(RNFBHandleCollisionException::class)
46
+ open fun put(
47
+ id: K,
48
+ handle: V,
49
+ ) {
50
+ synchronized(lock) {
51
+ if (map.containsKey(id)) {
52
+ throw RNFBHandleCollisionException(id)
53
+ }
54
+ map[id] = handle
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Stores [handle] under [id] only when the id is free (first wins).
60
+ *
61
+ * @return `true` if stored, `false` if [id] was already occupied
62
+ */
63
+ open fun putIfAbsent(
64
+ id: K,
65
+ handle: V,
66
+ ): Boolean =
67
+ synchronized(lock) {
68
+ if (map.containsKey(id)) {
69
+ false
70
+ } else {
71
+ map[id] = handle
72
+ true
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Under one lock: stores [handle] when the id is free, or returns `true` when the existing mapping
78
+ * is the same instance (`===`). Returns `false` when occupied by a different handle.
79
+ */
80
+ open fun putIfAbsentOrSame(
81
+ id: K,
82
+ handle: V,
83
+ ): Boolean =
84
+ synchronized(lock) {
85
+ if (!map.containsKey(id)) {
86
+ map[id] = handle
87
+ true
88
+ } else {
89
+ map[id] === handle
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Atomically replaces the mapping for [id] (last wins). Returns the previous handle, or `null` if
95
+ * the id was free.
96
+ */
97
+ open fun putReplacing(
98
+ id: K,
99
+ handle: V,
100
+ ): V? = synchronized(lock) { map.put(id, handle) }
101
+
102
+ /**
103
+ * Peeks at the handle for [id] without removing it (for emit while still registered).
104
+ *
105
+ * @return the handle, or `null` if absent
106
+ */
107
+ open fun get(id: K): V? = synchronized(lock) { map[id] }
108
+
109
+ /**
110
+ * Removes and returns the handle for [id].
111
+ *
112
+ * @return the handle, or `null` if absent
113
+ */
114
+ open fun take(id: K): V? = synchronized(lock) { map.remove(id) }
115
+
116
+ /**
117
+ * When [id] is mapped and [shouldTake] accepts the handle, removes and returns it; otherwise
118
+ * returns `null` and leaves the map unchanged. Lookup, predicate, and removal run under one lock —
119
+ * use for check-and-take that must not race with concurrent [put] / [take] on the same id.
120
+ *
121
+ * The predicate runs under this map's lock; keep it lightweight (no SDK cancel/remove).
122
+ */
123
+ open fun takeIf(
124
+ id: K,
125
+ shouldTake: Predicate<V>,
126
+ ): V? =
127
+ synchronized(lock) {
128
+ val value = map[id]
129
+ if (value != null && shouldTake.test(value)) {
130
+ map.remove(id)
131
+ } else {
132
+ null
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Snapshot of current values, then clear. Cancel/remove each returned object after this method
138
+ * returns, not under this map's lock.
139
+ */
140
+ open fun takeAll(): List<V> =
141
+ synchronized(lock) {
142
+ val values = ArrayList(map.values)
143
+ map.clear()
144
+ values
145
+ }
146
+ }
@@ -0,0 +1,156 @@
1
+ package io.invertase.firebase.common
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import java.util.concurrent.ExecutorService
21
+ import java.util.concurrent.LinkedBlockingQueue
22
+ import java.util.concurrent.RejectedExecutionException
23
+ import java.util.concurrent.RejectedExecutionHandler
24
+ import java.util.concurrent.SynchronousQueue
25
+ import java.util.concurrent.ThreadPoolExecutor
26
+ import java.util.concurrent.TimeUnit
27
+
28
+ open class TaskExecutorService(
29
+ private val name: String,
30
+ ) {
31
+ private val maximumPoolSize: Int
32
+ private val keepAliveSeconds: Int
33
+
34
+ init {
35
+ val json = ReactNativeFirebaseJSON.getSharedInstance()
36
+ maximumPoolSize = json.getIntValue(MAXIMUM_POOL_SIZE_KEY, 1)
37
+ keepAliveSeconds = json.getIntValue(KEEP_ALIVE_SECONDS_KEY, 3)
38
+ }
39
+
40
+ open fun getExecutor(): ExecutorService {
41
+ val isTransactional = maximumPoolSize <= 1
42
+ return getExecutor(isTransactional, "")
43
+ }
44
+
45
+ open fun getTransactionalExecutor(): ExecutorService = getExecutor(true, "")
46
+
47
+ open fun getTransactionalExecutor(identifier: String): ExecutorService {
48
+ val executorIdentifier = if (maximumPoolSize != 0) identifier else ""
49
+ return getExecutor(true, executorIdentifier)
50
+ }
51
+
52
+ open fun getExecutor(
53
+ isTransactional: Boolean,
54
+ identifier: String,
55
+ ): ExecutorService {
56
+ val executorName = getExecutorName(isTransactional, identifier)
57
+ synchronized(executors) {
58
+ val existingExecutor = executors[executorName]
59
+ if (existingExecutor == null) {
60
+ val newExecutor = getNewExecutor(isTransactional)
61
+ executors[executorName] = newExecutor
62
+ return newExecutor
63
+ }
64
+ return existingExecutor
65
+ }
66
+ }
67
+
68
+ private fun getNewExecutor(isTransactional: Boolean): ExecutorService {
69
+ if (isTransactional) {
70
+ // A bare Executors.newSingleThreadExecutor() has no rejection handler, so a
71
+ // play-services Task completing after shutdown() (module invalidation racing
72
+ // in-flight work, e.g. App Check attestation or Auth network calls finishing
73
+ // while the React instance is torn down) posts to the dead executor and
74
+ // crashes the process with an uncaught RejectedExecutionException. Use an
75
+ // equivalent single-thread pool that discards work arriving after shutdown.
76
+ return ThreadPoolExecutor(
77
+ 1,
78
+ 1,
79
+ 0L,
80
+ TimeUnit.MILLISECONDS,
81
+ LinkedBlockingQueue(),
82
+ ).apply { rejectedExecutionHandler = discardAfterShutdown }
83
+ }
84
+
85
+ return ThreadPoolExecutor(
86
+ 0,
87
+ maximumPoolSize,
88
+ keepAliveSeconds.toLong(),
89
+ TimeUnit.SECONDS,
90
+ SynchronousQueue(),
91
+ ).apply { rejectedExecutionHandler = executeInFallback }
92
+ }
93
+
94
+ private val executeInFallback =
95
+ RejectedExecutionHandler { runnable, executor ->
96
+ // isShutdown() remains true through the terminating and terminated states,
97
+ // so it is the only check needed to detect work arriving after shutdown.
98
+ if (executor.isShutdown) {
99
+ return@RejectedExecutionHandler
100
+ }
101
+ val fallbackExecutor = getTransactionalExecutor()
102
+ fallbackExecutor.execute(runnable)
103
+ }
104
+
105
+ open fun getExecutorName(
106
+ isTransactional: Boolean,
107
+ identifier: String,
108
+ ): String =
109
+ if (isTransactional) {
110
+ "${name}TransactionalExecutor$identifier"
111
+ } else {
112
+ "${name}Executor$identifier"
113
+ }
114
+
115
+ open fun shutdown() {
116
+ synchronized(executors) {
117
+ val existingExecutorNames = ArrayList(executors.keys)
118
+ for (executorName in existingExecutorNames) {
119
+ if (!executorName.startsWith(name)) {
120
+ executors.remove(executorName)
121
+ } else {
122
+ removeExecutor(executorName)
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ open fun removeExecutor(executorName: String) {
129
+ synchronized(executors) {
130
+ val existingExecutor = executors[executorName]
131
+ if (existingExecutor != null) {
132
+ existingExecutor.shutdownNow()
133
+ executors.remove(executorName)
134
+ }
135
+ }
136
+ }
137
+
138
+ private companion object {
139
+ private const val MAXIMUM_POOL_SIZE_KEY = "android_task_executor_maximum_pool_size"
140
+ private const val KEEP_ALIVE_SECONDS_KEY = "android_task_executor_keep_alive_seconds"
141
+
142
+ private val executors = HashMap<String, ExecutorService>()
143
+
144
+ private val discardAfterShutdown =
145
+ RejectedExecutionHandler { runnable, executor ->
146
+ // isShutdown() remains true through the terminating and terminated states,
147
+ // so it is the only check needed to detect work arriving after shutdown.
148
+ if (executor.isShutdown) {
149
+ return@RejectedExecutionHandler
150
+ }
151
+ // Unreachable with an unbounded queue, but preserve AbortPolicy semantics
152
+ // for any rejection that is not caused by shutdown.
153
+ throw RejectedExecutionException("Task $runnable rejected from $executor")
154
+ }
155
+ }
156
+ }
@@ -0,0 +1,44 @@
1
+ package io.invertase.firebase.common
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import android.content.Context
20
+ import java.util.HashMap
21
+ import java.util.concurrent.ExecutorService
22
+ import javax.annotation.OverridingMethodsMustInvokeSuper
23
+
24
+ open class UniversalFirebaseModule(
25
+ private val context: Context?,
26
+ private val serviceName: String?,
27
+ ) {
28
+ private val executorService: TaskExecutorService = TaskExecutorService(getName())
29
+
30
+ open fun getContext(): Context? = context
31
+
32
+ open fun getApplicationContext(): Context? = getContext()!!.applicationContext
33
+
34
+ open fun getExecutor(): ExecutorService = executorService.getExecutor()
35
+
36
+ open fun getName(): String = "Universal${serviceName}Module"
37
+
38
+ @OverridingMethodsMustInvokeSuper
39
+ open fun onTearDown() {
40
+ executorService.shutdown()
41
+ }
42
+
43
+ open fun getConstants(): Map<String, Any> = HashMap()
44
+ }
@@ -0,0 +1,100 @@
1
+ package io.invertase.firebase.common
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import android.content.Context
21
+ import android.content.SharedPreferences
22
+ import io.invertase.firebase.app.ReactNativeFirebaseApp
23
+
24
+ open class UniversalFirebasePreferences {
25
+ private var preferences: SharedPreferences? = null
26
+
27
+ open fun contains(key: String?): Boolean = getPreferences().contains(key)
28
+
29
+ open fun setBooleanValue(
30
+ key: String?,
31
+ value: Boolean,
32
+ ) {
33
+ getPreferences().edit().putBoolean(key, value).apply()
34
+ }
35
+
36
+ open fun getBooleanValue(
37
+ key: String?,
38
+ defaultValue: Boolean,
39
+ ): Boolean = getPreferences().getBoolean(key, defaultValue)
40
+
41
+ open fun setIntValue(
42
+ key: String?,
43
+ value: Int,
44
+ ) {
45
+ getPreferences().edit().putInt(key, value).apply()
46
+ }
47
+
48
+ open fun getIntValue(
49
+ key: String?,
50
+ defaultValue: Int,
51
+ ): Int = getPreferences().getInt(key, defaultValue)
52
+
53
+ open fun setLongValue(
54
+ key: String?,
55
+ value: Long,
56
+ ) {
57
+ getPreferences().edit().putLong(key, value).apply()
58
+ }
59
+
60
+ open fun getLongValue(
61
+ key: String?,
62
+ defaultValue: Long,
63
+ ): Long = getPreferences().getLong(key, defaultValue)
64
+
65
+ open fun setStringValue(
66
+ key: String?,
67
+ value: String?,
68
+ ) {
69
+ getPreferences().edit().putString(key, value).apply()
70
+ }
71
+
72
+ open fun getStringValue(
73
+ key: String?,
74
+ defaultValue: String?,
75
+ ): String? = getPreferences().getString(key, defaultValue)
76
+
77
+ open fun clearAll() {
78
+ getPreferences().edit().clear().apply()
79
+ }
80
+
81
+ // The caller is responsible for calling apply() or commit() on the returned editor.
82
+ open fun remove(key: String?): SharedPreferences.Editor = getPreferences().edit().remove(key)
83
+
84
+ private fun getPreferences(): SharedPreferences {
85
+ if (preferences == null) {
86
+ preferences =
87
+ ReactNativeFirebaseApp
88
+ .getApplicationContext()
89
+ .getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE)
90
+ }
91
+ return preferences!!
92
+ }
93
+
94
+ companion object {
95
+ private const val PREFERENCES_FILE = "io.invertase.firebase"
96
+ private val sharedInstance = UniversalFirebasePreferences()
97
+
98
+ @JvmStatic fun getSharedInstance(): UniversalFirebasePreferences = sharedInstance
99
+ }
100
+ }