@react-native-firebase/app 26.4.0 → 27.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 (242) hide show
  1. package/CHANGELOG.md +62 -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 +182 -59
  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 +143 -12
  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 -21
  58. package/dist/module/FirebaseApp.js +10 -0
  59. package/dist/module/FirebaseApp.js.map +1 -1
  60. package/dist/module/common/deeps.js +3 -0
  61. package/dist/module/common/deeps.js.map +1 -1
  62. package/dist/module/internal/FirebaseModule.js.map +1 -1
  63. package/dist/module/internal/RNFBNativeEventEmitter.js +12 -1
  64. package/dist/module/internal/RNFBNativeEventEmitter.js.map +1 -1
  65. package/dist/module/internal/SharedEventEmitter.js +3 -1
  66. package/dist/module/internal/SharedEventEmitter.js.map +1 -1
  67. package/dist/module/internal/index.js +1 -0
  68. package/dist/module/internal/index.js.map +1 -1
  69. package/dist/module/internal/registry/app.js +7 -1
  70. package/dist/module/internal/registry/app.js.map +1 -1
  71. package/dist/module/types/app.js.map +1 -1
  72. package/dist/module/types/internal.js +2 -0
  73. package/dist/module/version.js +1 -1
  74. package/dist/typescript/lib/FirebaseApp.d.ts +7 -0
  75. package/dist/typescript/lib/FirebaseApp.d.ts.map +1 -1
  76. package/dist/typescript/lib/common/deeps.d.ts.map +1 -1
  77. package/dist/typescript/lib/internal/FirebaseModule.d.ts +2 -3
  78. package/dist/typescript/lib/internal/FirebaseModule.d.ts.map +1 -1
  79. package/dist/typescript/lib/internal/NativeModules.d.ts +4 -1
  80. package/dist/typescript/lib/internal/NativeModules.d.ts.map +1 -1
  81. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts +2 -2
  82. package/dist/typescript/lib/internal/RNFBNativeEventEmitter.d.ts.map +1 -1
  83. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts +3 -3
  84. package/dist/typescript/lib/internal/SharedEventEmitter.d.ts.map +1 -1
  85. package/dist/typescript/lib/internal/index.d.ts +1 -0
  86. package/dist/typescript/lib/internal/index.d.ts.map +1 -1
  87. package/dist/typescript/lib/internal/registry/app.d.ts.map +1 -1
  88. package/dist/typescript/lib/types/app.d.ts +10 -3
  89. package/dist/typescript/lib/types/app.d.ts.map +1 -1
  90. package/dist/typescript/lib/types/internal.d.ts +12 -0
  91. package/dist/typescript/lib/types/internal.d.ts.map +1 -1
  92. package/dist/typescript/lib/version.d.ts +1 -1
  93. package/firebase-schema.json +4 -0
  94. package/firebase_spm.rb +552 -96
  95. package/ios/RNFBApp/RCTConvert+FIRApp.h +2 -5
  96. package/ios/RNFBApp/RCTConvert+FIRApp.m +11 -6
  97. package/ios/RNFBApp/RCTConvert+FIROptions.h +2 -5
  98. package/ios/RNFBApp/RCTConvert+FIROptions.m +11 -10
  99. package/ios/RNFBApp/RCTConvertFIRApp.swift +86 -0
  100. package/ios/RNFBApp/RCTConvertFIROptions.swift +259 -0
  101. package/ios/RNFBApp/RNFBAppCustomAuthDomains.swift +63 -0
  102. package/ios/RNFBApp/RNFBAppInitializeOptionsMapper.swift +113 -0
  103. package/ios/RNFBApp/RNFBAppLogLevelMapper.swift +53 -0
  104. package/ios/RNFBApp/RNFBAppModule+CustomAuthDomain.m +35 -0
  105. package/ios/RNFBApp/RNFBAppModule.h +6 -2
  106. package/ios/RNFBApp/RNFBAppModule.mm +65 -228
  107. package/ios/RNFBApp/RNFBAppModuleFirebase.swift +439 -0
  108. package/ios/RNFBApp/RNFBAppModuleImplementation.h +68 -0
  109. package/ios/RNFBApp/RNFBAppModuleImplementation.m +195 -0
  110. package/ios/RNFBApp/RNFBHandleMap.m +27 -56
  111. package/ios/RNFBApp/RNFBHandleMapStorage.swift +90 -0
  112. package/ios/RNFBApp/RNFBInitializeAppArguments.swift +82 -0
  113. package/ios/RNFBApp/RNFBJSON.m +22 -38
  114. package/ios/RNFBApp/RNFBJSONImplementation.swift +71 -0
  115. package/ios/RNFBApp/RNFBMeta.m +24 -26
  116. package/ios/RNFBApp/RNFBMetaStorage.swift +76 -0
  117. package/ios/RNFBApp/RNFBNullSentinelDecoding.swift +135 -0
  118. package/ios/RNFBApp/RNFBNullSentinelInterceptor.h +30 -3
  119. package/ios/RNFBApp/RNFBNullSentinelInterceptor.m +28 -5
  120. package/ios/RNFBApp/RNFBPreferences.m +22 -20
  121. package/ios/RNFBApp/RNFBPreferencesStorage.swift +101 -0
  122. package/ios/RNFBApp/RNFBRCTEventEmitter.m +36 -93
  123. package/ios/RNFBApp/RNFBRCTEventEmitterCore.swift +161 -0
  124. package/ios/RNFBApp/RNFBSharedUtils.h +2 -5
  125. package/ios/RNFBApp/RNFBSharedUtils.m +109 -198
  126. package/ios/RNFBApp/RNFBSharedUtilsConfig.swift +72 -0
  127. package/ios/RNFBApp/RNFBSharedUtilsFIRApp.swift +271 -0
  128. package/ios/RNFBApp/RNFBSharedUtilsFormatting.swift +59 -0
  129. package/ios/RNFBApp/RNFBSharedUtilsPromiseRejection.swift +88 -0
  130. package/ios/RNFBApp/RNFBUtilsHelpers.swift +116 -0
  131. package/ios/RNFBApp/RNFBUtilsModule+Foundation.m +44 -0
  132. package/ios/RNFBApp/RNFBUtilsModule+PhotoAssets.m +47 -0
  133. package/ios/RNFBApp/RNFBUtilsModule.h +11 -1
  134. package/ios/RNFBApp/RNFBUtilsModule.mm +10 -85
  135. package/ios/RNFBApp/RNFBUtilsModuleImplementation.h +32 -0
  136. package/ios/RNFBApp/RNFBUtilsModuleImplementation.m +56 -0
  137. package/ios/RNFBApp/RNFBVersion.m +1 -1
  138. package/ios/RNFBApp.xcodeproj/project.pbxproj +100 -0
  139. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FIRApp.m +171 -0
  140. package/ios/RNFBAppUnitTests/HostStubs/FirebaseCore/FirebaseCore.h +78 -0
  141. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FIRInstallations.m +7 -0
  142. package/ios/RNFBAppUnitTests/HostStubs/FirebaseInstallations/FirebaseInstallations.h +8 -0
  143. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppModuleHostStub.m +55 -0
  144. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.h +89 -0
  145. package/ios/RNFBAppUnitTests/HostStubs/RNFBAppTurboModules.mm +30 -0
  146. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.h +19 -0
  147. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridge.m +32 -0
  148. package/ios/RNFBAppUnitTests/HostStubs/React/RCTBridgeModule.h +19 -0
  149. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.h +28 -0
  150. package/ios/RNFBAppUnitTests/HostStubs/React/RCTConvert.m +23 -0
  151. package/ios/RNFBAppUnitTests/HostStubs/React/RCTEventEmitter.h +9 -0
  152. package/ios/RNFBAppUnitTests/HostStubs/React/RCTInvalidating.h +24 -0
  153. package/ios/RNFBAppUnitTests/HostStubs/React/RCTUtils.h +9 -0
  154. package/ios/RNFBAppUnitTests/HostStubs/module.modulemap +13 -0
  155. package/ios/RNFBAppUnitTests/RCTConvertFIRAppFacadeTests.m +61 -0
  156. package/ios/RNFBAppUnitTests/RCTConvertFIRAppTests.swift +73 -0
  157. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsFacadeTests.m +57 -0
  158. package/ios/RNFBAppUnitTests/RCTConvertFIROptionsTests.swift +243 -0
  159. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsFacadeTests.m +73 -0
  160. package/ios/RNFBAppUnitTests/RNFBAppCustomAuthDomainsTests.swift +70 -0
  161. package/ios/RNFBAppUnitTests/RNFBAppInitializeOptionsMapperTests.swift +190 -0
  162. package/ios/RNFBAppUnitTests/RNFBAppLogLevelFacadeTests.m +76 -0
  163. package/ios/RNFBAppUnitTests/RNFBAppLogLevelMapperTests.swift +59 -0
  164. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseFacadeTests.m +215 -0
  165. package/ios/RNFBAppUnitTests/RNFBAppModuleFirebaseTests.swift +430 -0
  166. package/ios/RNFBAppUnitTests/RNFBAppModuleLifecycleTests.m +206 -0
  167. package/ios/RNFBAppUnitTests/RNFBAppModuleShellTests.mm +367 -0
  168. package/ios/RNFBAppUnitTests/RNFBAppUnitTests.xcodeproj/project.pbxproj +355 -2
  169. package/ios/RNFBAppUnitTests/RNFBFirebaseAppClientTests.swift +165 -0
  170. package/ios/RNFBAppUnitTests/RNFBHandleMapStorageTests.swift +121 -0
  171. package/ios/RNFBAppUnitTests/RNFBInitializeAppArgumentsTests.swift +256 -0
  172. package/ios/RNFBAppUnitTests/RNFBJSONImplementationTests.swift +126 -0
  173. package/ios/RNFBAppUnitTests/RNFBJSONTests.m +172 -0
  174. package/ios/RNFBAppUnitTests/RNFBMetaStorageTests.swift +106 -0
  175. package/ios/RNFBAppUnitTests/RNFBMetaTests.m +65 -0
  176. package/ios/RNFBAppUnitTests/RNFBNullSentinelDecodingTests.swift +286 -0
  177. package/ios/RNFBAppUnitTests/RNFBNullSentinelInterceptorTests.m +312 -0
  178. package/ios/RNFBAppUnitTests/RNFBPreferencesStorageTests.swift +105 -0
  179. package/ios/RNFBAppUnitTests/RNFBPreferencesTests.m +110 -0
  180. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterCoreTests.swift +163 -0
  181. package/ios/RNFBAppUnitTests/RNFBRCTEventEmitterFacadeTests.m +141 -0
  182. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigFacadeTests.m +100 -0
  183. package/ios/RNFBAppUnitTests/RNFBSharedUtilsConfigTests.swift +234 -0
  184. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppFacadeTests.m +145 -0
  185. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFIRAppTests.swift +173 -0
  186. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingFacadeTests.m +38 -0
  187. package/ios/RNFBAppUnitTests/RNFBSharedUtilsFormattingTests.swift +82 -0
  188. package/ios/RNFBAppUnitTests/RNFBSharedUtilsNullSentinelTests.m +35 -0
  189. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionFacadeTests.m +107 -0
  190. package/ios/RNFBAppUnitTests/RNFBSharedUtilsPromiseRejectionTests.swift +133 -0
  191. package/ios/RNFBAppUnitTests/RNFBUtilsHelpersTests.swift +144 -0
  192. package/ios/RNFBAppUnitTests/RNFBUtilsModuleFacadeTests.m +72 -0
  193. package/ios/RNFBAppUnitTests/RNFBUtilsModuleShellTests.mm +282 -0
  194. package/ios/RNFBFirebase/Package.swift +53 -0
  195. package/ios/RNFBFirebase/Sources/RNFBFirebase/RNFBFirebase.swift +285 -0
  196. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/Public/.gitkeep +0 -0
  197. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/RNFBFirebaseBridge.m +169 -0
  198. package/ios/RNFBFirebase/Sources/RNFBFirebaseBridge/include/RNFBFirebaseBridge.h +52 -0
  199. package/ios/RNFBFirebaseUnitTests/RNFBAppDynamicFacadeTests.swift +240 -0
  200. package/{android/src/main/java/io/invertase/firebase/common/RNFBHandleCollisionException.java → ios/RNFBFirebaseUnitTests/RNFBFirebaseClientImport.swift} +23 -14
  201. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/project.pbxproj +588 -0
  202. package/ios/RNFBFirebaseUnitTests/RNFBFirebaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBFirebaseUnitTests.xcscheme +83 -0
  203. package/ios_config.sh +50 -22
  204. package/lib/FirebaseApp.ts +10 -0
  205. package/lib/common/deeps.ts +3 -0
  206. package/lib/internal/FirebaseModule.ts +6 -3
  207. package/lib/internal/NativeModules.ts +4 -1
  208. package/lib/internal/RNFBNativeEventEmitter.ts +14 -5
  209. package/lib/internal/SharedEventEmitter.ts +5 -1
  210. package/lib/internal/index.ts +1 -0
  211. package/lib/internal/react-native-vendor-emitter.d.ts +11 -0
  212. package/lib/internal/registry/app.ts +7 -1
  213. package/lib/types/app.ts +10 -3
  214. package/lib/types/internal.ts +19 -0
  215. package/lib/version.ts +1 -1
  216. package/package.json +8 -8
  217. package/plugin/build/ios/appDelegate.js +2 -2
  218. package/plugin/build/ios/podfile.js +16 -16
  219. package/plugin/build/pluginConfig.d.ts +4 -2
  220. package/plugin/src/ios/appDelegate.ts +2 -2
  221. package/plugin/src/ios/podfile.ts +20 -23
  222. package/plugin/src/pluginConfig.ts +4 -2
  223. package/android/src/main/java/io/invertase/firebase/common/RNFBHandleMap.java +0 -150
  224. package/android/src/main/java/io/invertase/firebase/common/TaskExecutorService.java +0 -148
  225. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +0 -62
  226. package/android/src/main/java/io/invertase/firebase/common/UniversalFirebasePreferences.java +0 -91
  227. package/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java +0 -224
  228. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseApp.java +0 -46
  229. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +0 -49
  230. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppRegistrar.java +0 -35
  231. package/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +0 -192
  232. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEvent.java +0 -53
  233. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseEventEmitter.java +0 -606
  234. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseJSON.java +0 -109
  235. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseMeta.java +0 -101
  236. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebaseModule.java +0 -146
  237. package/android/src/reactnative/java/io/invertase/firebase/common/ReactNativeFirebasePreferences.java +0 -96
  238. package/android/src/reactnative/java/io/invertase/firebase/common/SharedUtils.java +0 -441
  239. package/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +0 -223
  240. package/android/src/test/java/io/invertase/firebase/common/RNFBHandleMapTest.java +0 -275
  241. package/android/src/test/java/io/invertase/firebase/common/ReactNativeFirebaseJSONTest.java +0 -108
  242. package/android/src/test/java/io/invertase/firebase/common/TaskExecutorServiceTest.java +0 -97
@@ -0,0 +1,219 @@
1
+ package io.invertase.firebase.utils
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.app.Activity
21
+ import android.app.Dialog
22
+ import android.content.Context
23
+ import android.content.IntentSender
24
+ import android.os.Build
25
+ import android.os.Environment
26
+ import android.provider.Settings
27
+ import android.util.Log
28
+ import com.facebook.fbreact.specs.NativeRNFBTurboUtilsSpec
29
+ import com.facebook.react.bridge.Arguments
30
+ import com.facebook.react.bridge.Promise
31
+ import com.facebook.react.bridge.ReactApplicationContext
32
+ import com.facebook.react.bridge.UiThreadUtil
33
+ import com.facebook.react.bridge.WritableMap
34
+ import com.google.android.gms.common.ConnectionResult
35
+ import com.google.android.gms.common.GoogleApiAvailability
36
+ import io.invertase.firebase.app.ReactNativeFirebaseApp
37
+ import java.util.HashMap
38
+
39
+ open class NativeRNFBTurboUtils(
40
+ reactContext: ReactApplicationContext?,
41
+ ) : NativeRNFBTurboUtilsSpec(reactContext) {
42
+ override fun androidGetPlayServicesStatus(promise: Promise?) {
43
+ nullableAsPlatformType<Promise>(promise).resolve(playServicesStatusMap)
44
+ }
45
+
46
+ override fun androidPromptForPlayServices(promise: Promise?) {
47
+ val status = isGooglePlayServicesAvailable()
48
+ val gapi = GoogleApiAvailability.getInstance()
49
+
50
+ if (status != ConnectionResult.SUCCESS && gapi.isUserResolvableError(status)) {
51
+ val activity: Activity? = getCurrentActivity()
52
+ if (activity != null) {
53
+ nullableAsPlatformType<Dialog>(gapi.getErrorDialog(activity, status, status)).show()
54
+ }
55
+ }
56
+ nullableAsPlatformType<Promise>(promise).resolve(null)
57
+ }
58
+
59
+ override fun androidResolutionForPlayServices(promise: Promise?) {
60
+ val status = isGooglePlayServicesAvailable()
61
+ val connectionResult = ConnectionResult(status)
62
+
63
+ if (!connectionResult.isSuccess && connectionResult.hasResolution()) {
64
+ val activity: Activity? = getCurrentActivity()
65
+ if (activity != null) {
66
+ try {
67
+ connectionResult.startResolutionForResult(activity, status)
68
+ } catch (error: IntentSender.SendIntentException) {
69
+ Log.d(TAG, "resolutionForPlayServices", error)
70
+ }
71
+ }
72
+ }
73
+ nullableAsPlatformType<Promise>(promise).resolve(null)
74
+ }
75
+
76
+ override fun androidMakePlayServicesAvailable(promise: Promise?) {
77
+ val status = isGooglePlayServicesAvailable()
78
+
79
+ if (status != ConnectionResult.SUCCESS) {
80
+ UiThreadUtil.runOnUiThread {
81
+ val activity: Activity? = getCurrentActivity()
82
+ if (activity != null) {
83
+ GoogleApiAvailability
84
+ .getInstance()
85
+ .makeGooglePlayServicesAvailable(activity)
86
+ .addOnCompleteListener { task ->
87
+ if (task.isSuccessful) {
88
+ nullableAsPlatformType<Promise>(promise).resolve(null)
89
+ } else if (task.isCanceled) {
90
+ nullableAsPlatformType<Promise>(promise).reject(
91
+ "play-services-update-canceled",
92
+ "Play Services update was canceled by the user",
93
+ )
94
+ } else {
95
+ val error = task.exception
96
+ nullableAsPlatformType<Promise>(promise).reject(
97
+ "play-services-update-failed",
98
+ if (error != null) error.message else "Unknown error",
99
+ error,
100
+ )
101
+ }
102
+ }
103
+ } else {
104
+ nullableAsPlatformType<Promise>(promise).resolve(null)
105
+ }
106
+ }
107
+ } else {
108
+ nullableAsPlatformType<Promise>(promise).resolve(null)
109
+ }
110
+ }
111
+
112
+ protected override fun getTypedExportedConstants(): MutableMap<String, Any> {
113
+ val constants: MutableMap<String, Any> = HashMap()
114
+
115
+ constants["isRunningInTestLab"] = isRunningInTestLab()
116
+
117
+ val context = reactApplicationContext
118
+ val appVersion = getAppVersionName(context)
119
+ if (appVersion != null && appVersion.isNotEmpty()) {
120
+ constants["appVersion"] = appVersion
121
+ }
122
+
123
+ constants[KEY_MAIN_BUNDLE] = ""
124
+ constants[KEY_LIBRARY_DIRECTORY] = context.filesDir.absolutePath
125
+ constants[KEY_TEMP_DIRECTORY] = context.cacheDir.absolutePath
126
+ constants[KEY_CACHE_DIRECTORY] = context.cacheDir.absolutePath
127
+
128
+ val externalDirectory = context.getExternalFilesDir(null)
129
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && externalDirectory != null) {
130
+ constants[KEY_DOCUMENT_DIRECTORY] = externalDirectory.absolutePath
131
+ }
132
+
133
+ if (!constants.containsKey(KEY_DOCUMENT_DIRECTORY)) {
134
+ constants[KEY_DOCUMENT_DIRECTORY] = context.filesDir.absolutePath
135
+ }
136
+
137
+ val picturesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
138
+ constants[KEY_PICS_DIRECTORY] =
139
+ if (picturesDirectory != null) picturesDirectory.absolutePath else ""
140
+
141
+ val moviesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
142
+ constants[KEY_MOVIES_DIRECTORY] =
143
+ if (moviesDirectory != null) moviesDirectory.absolutePath else ""
144
+
145
+ val externalStorageDirectory = Environment.getExternalStorageDirectory()
146
+ if (externalStorageDirectory != null) {
147
+ constants[KEY_EXT_STORAGE_DIRECTORY] = externalStorageDirectory.absolutePath
148
+ }
149
+
150
+ if (externalDirectory != null) {
151
+ constants[KEY_EXTERNAL_DIRECTORY] = externalDirectory.absolutePath
152
+ }
153
+
154
+ return constants
155
+ }
156
+
157
+ private fun isGooglePlayServicesAvailable(): Int {
158
+ val gapi = GoogleApiAvailability.getInstance()
159
+ return gapi.isGooglePlayServicesAvailable(reactApplicationContext)
160
+ }
161
+
162
+ private val playServicesStatusMap: WritableMap
163
+ get() {
164
+ val result = Arguments.createMap()
165
+ val gapi = GoogleApiAvailability.getInstance()
166
+
167
+ val status = gapi.isGooglePlayServicesAvailable(reactApplicationContext)
168
+ result.putInt("status", status)
169
+
170
+ if (status == ConnectionResult.SUCCESS) {
171
+ result.putBoolean("isAvailable", true)
172
+ } else {
173
+ result.putBoolean("isAvailable", false)
174
+ result.putString("error", gapi.getErrorString(status))
175
+ result.putBoolean("isUserResolvableError", gapi.isUserResolvableError(status))
176
+ result.putBoolean("hasResolution", ConnectionResult(status).hasResolution())
177
+ }
178
+
179
+ return result
180
+ }
181
+
182
+ companion object {
183
+ private const val TAG = "Utils"
184
+ private const val KEY_MAIN_BUNDLE = "MAIN_BUNDLE"
185
+ private const val KEY_DOCUMENT_DIRECTORY = "DOCUMENT_DIRECTORY"
186
+ private const val KEY_LIBRARY_DIRECTORY = "LIBRARY_DIRECTORY"
187
+ private const val KEY_EXTERNAL_DIRECTORY = "EXTERNAL_DIRECTORY"
188
+ private const val KEY_EXT_STORAGE_DIRECTORY = "EXTERNAL_STORAGE_DIRECTORY"
189
+ private const val KEY_PICS_DIRECTORY = "PICTURES_DIRECTORY"
190
+ private const val KEY_MOVIES_DIRECTORY = "MOVIES_DIRECTORY"
191
+ private const val KEY_TEMP_DIRECTORY = "TEMP_DIRECTORY"
192
+ private const val KEY_CACHE_DIRECTORY = "CACHES_DIRECTORY"
193
+ private const val FIREBASE_TEST_LAB = "firebase.test.lab"
194
+
195
+ private fun isRunningInTestLab(): Boolean {
196
+ val testLabSetting =
197
+ Settings.System.getString(
198
+ ReactNativeFirebaseApp.getApplicationContext().contentResolver,
199
+ FIREBASE_TEST_LAB,
200
+ )
201
+
202
+ return "true" == testLabSetting
203
+ }
204
+
205
+ private fun getAppVersionName(context: Context): String? =
206
+ try {
207
+ @Suppress("DEPRECATION")
208
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
209
+ packageInfo.versionName
210
+ } catch (error: Exception) {
211
+ // Optional metadata: prefer omit over crashing on null context / unexpected PM failures.
212
+ Log.d(TAG, "getAppVersionName", error)
213
+ null
214
+ }
215
+
216
+ @Suppress("UNCHECKED_CAST")
217
+ private fun <T> nullableAsPlatformType(value: T?): T = value as T
218
+ }
219
+ }
@@ -0,0 +1,9 @@
1
+ package expo.core;
2
+
3
+ /**
4
+ * Test-source-only classpath marker that makes the default SharedUtils detector see Expo. Isolated
5
+ * class loaders in SharedUtilsJavaCompatibilityTest explicitly hide it for non-Expo cases.
6
+ */
7
+ public final class ModuleRegistry {
8
+ private ModuleRegistry() {}
9
+ }
@@ -20,10 +20,16 @@ package io.invertase.firebase.app;
20
20
  import static org.junit.Assert.assertEquals;
21
21
  import static org.junit.Assert.assertFalse;
22
22
  import static org.junit.Assert.assertNull;
23
+ import static org.junit.Assert.assertSame;
24
+ import static org.junit.Assert.assertThrows;
23
25
  import static org.junit.Assert.assertTrue;
26
+ import static org.mockito.ArgumentMatchers.any;
27
+ import static org.mockito.ArgumentMatchers.anyMap;
28
+ import static org.mockito.ArgumentMatchers.eq;
24
29
  import static org.mockito.Mockito.mock;
25
30
  import static org.mockito.Mockito.mockStatic;
26
31
  import static org.mockito.Mockito.verify;
32
+ import static org.mockito.Mockito.verifyNoInteractions;
27
33
  import static org.mockito.Mockito.when;
28
34
 
29
35
  import android.app.Application;
@@ -41,16 +47,18 @@ import com.google.firebase.FirebaseOptions;
41
47
  import io.invertase.firebase.common.RCTConvertFirebase;
42
48
  import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
43
49
  import io.invertase.firebase.common.ReactNativeFirebaseJSON;
44
- import io.invertase.firebase.common.ReactNativeFirebaseMeta;
45
50
  import io.invertase.firebase.common.ReactNativeFirebasePreferences;
51
+ import io.invertase.firebase.interfaces.NativeEvent;
46
52
  import java.lang.ref.WeakReference;
47
53
  import java.lang.reflect.Constructor;
48
54
  import java.lang.reflect.Field;
49
55
  import java.lang.reflect.Method;
56
+ import java.lang.reflect.Modifier;
57
+ import java.lang.reflect.ParameterizedType;
50
58
  import java.util.Collections;
51
- import java.util.HashMap;
52
59
  import java.util.List;
53
60
  import java.util.Map;
61
+ import java.util.concurrent.ConcurrentHashMap;
54
62
  import org.junit.Before;
55
63
  import org.junit.Test;
56
64
  import org.junit.runner.RunWith;
@@ -96,10 +104,57 @@ public class NativeRNFBTurboAppTest {
96
104
  when(reactContext.hasActiveReactInstance()).thenReturn(true);
97
105
  when(reactHost.getCurrentReactContext()).thenReturn(reactContext);
98
106
 
107
+ ReactNativeFirebaseApp.setApplicationContext(application);
99
108
  NativeRNFBTurboApp.authDomains.clear();
109
+ ReactNativeFirebasePreferences.getSharedInstance().clearAll();
100
110
  resetEmitterSharedInstance();
101
111
  }
102
112
 
113
+ @Test
114
+ public void javaAbi_preservesClassConstructorAndStaticAuthDomainSurface() throws Exception {
115
+ assertTrue(Modifier.isPublic(NativeRNFBTurboApp.class.getModifiers()));
116
+ assertFalse(Modifier.isFinal(NativeRNFBTurboApp.class.getModifiers()));
117
+ assertEquals(
118
+ com.facebook.fbreact.specs.NativeRNFBTurboAppSpec.class,
119
+ NativeRNFBTurboApp.class.getSuperclass());
120
+ assertTrue(
121
+ com.facebook.react.bridge.LifecycleEventListener.class.isAssignableFrom(
122
+ NativeRNFBTurboApp.class));
123
+
124
+ Constructor<NativeRNFBTurboApp> constructor =
125
+ NativeRNFBTurboApp.class.getDeclaredConstructor(ReactApplicationContext.class);
126
+ // Kotlin cannot emit package-private. Protected is the closest JVM visibility: it preserves
127
+ // construction from same-package Java (as every `new` in this class proves) without making the
128
+ // constructor public; the internal companion invoke serves same-module Kotlin registration.
129
+ assertTrue(Modifier.isProtected(constructor.getModifiers()));
130
+ assertFalse(Modifier.isPublic(constructor.getModifiers()));
131
+
132
+ Field field = NativeRNFBTurboApp.class.getDeclaredField("authDomains");
133
+ assertTrue(Modifier.isPublic(field.getModifiers()));
134
+ assertTrue(Modifier.isStatic(field.getModifiers()));
135
+ assertTrue(Modifier.isFinal(field.getModifiers()));
136
+ assertEquals(Map.class, field.getType());
137
+ ParameterizedType fieldType = (ParameterizedType) field.getGenericType();
138
+ assertEquals(String.class, fieldType.getActualTypeArguments()[0]);
139
+ assertEquals(String.class, fieldType.getActualTypeArguments()[1]);
140
+ assertTrue(field.get(null) instanceof ConcurrentHashMap);
141
+ assertSame(NativeRNFBTurboApp.authDomains, field.get(null));
142
+
143
+ Method configure =
144
+ NativeRNFBTurboApp.class.getDeclaredMethod(
145
+ "configureAuthDomain", String.class, String.class);
146
+ assertTrue(Modifier.isPublic(configure.getModifiers()));
147
+ assertTrue(Modifier.isStatic(configure.getModifiers()));
148
+ assertEquals(void.class, configure.getReturnType());
149
+ }
150
+
151
+ @Test
152
+ public void javaNullCalls_doNotGainKotlinBoundaryChecks() {
153
+ NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
154
+ module.addListener(null);
155
+ module.setLogLevel(null);
156
+ }
157
+
103
158
  @Test
104
159
  public void initialize_registersLifecycleListenerAndAttachesEmitter() throws Exception {
105
160
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
@@ -141,21 +196,14 @@ public class NativeRNFBTurboAppTest {
141
196
  @Test
142
197
  public void getTypedExportedConstants_includesAppsAndRawJson() throws Exception {
143
198
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
144
- Map<String, Object> appMap = new HashMap<>();
145
- appMap.put("name", "[DEFAULT]");
199
+ FirebaseOptions options = mock(FirebaseOptions.class);
200
+ when(firebaseApp.getName()).thenReturn("[DEFAULT]");
201
+ when(firebaseApp.getOptions()).thenReturn(options);
146
202
 
147
- try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class);
148
- MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class);
149
- MockedStatic<ReactNativeFirebaseJSON> jsonStatic =
150
- mockStatic(ReactNativeFirebaseJSON.class)) {
203
+ try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class)) {
151
204
  firebaseApps
152
205
  .when(() -> FirebaseApp.getApps(reactContext))
153
206
  .thenReturn(Collections.singletonList(firebaseApp));
154
- convert.when(() -> RCTConvertFirebase.firebaseAppToMap(firebaseApp)).thenReturn(appMap);
155
-
156
- ReactNativeFirebaseJSON json = mock(ReactNativeFirebaseJSON.class);
157
- jsonStatic.when(ReactNativeFirebaseJSON::getSharedInstance).thenReturn(json);
158
- when(json.getRawJSON()).thenReturn("{}");
159
207
 
160
208
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
161
209
  Method method = NativeRNFBTurboApp.class.getDeclaredMethod("getTypedExportedConstants");
@@ -163,12 +211,16 @@ public class NativeRNFBTurboAppTest {
163
211
  @SuppressWarnings("unchecked")
164
212
  Map<String, Object> constants = (Map<String, Object>) method.invoke(module);
165
213
 
166
- assertEquals("{}", constants.get("FIREBASE_RAW_JSON"));
214
+ assertEquals(
215
+ ReactNativeFirebaseJSON.getSharedInstance().getRawJSON(),
216
+ constants.get("FIREBASE_RAW_JSON"));
167
217
  @SuppressWarnings("unchecked")
168
218
  List<Map<String, Object>> apps =
169
219
  (List<Map<String, Object>>) constants.get("NATIVE_FIREBASE_APPS");
170
220
  assertEquals(1, apps.size());
171
- assertEquals("[DEFAULT]", apps.get(0).get("name"));
221
+ @SuppressWarnings("unchecked")
222
+ Map<String, Object> appConfig = (Map<String, Object>) apps.get(0).get("appConfig");
223
+ assertEquals("[DEFAULT]", appConfig.get("name"));
172
224
  }
173
225
  }
174
226
 
@@ -178,24 +230,33 @@ public class NativeRNFBTurboAppTest {
178
230
  ReadableMap appConfig = mock(ReadableMap.class);
179
231
  Promise promise = mock(Promise.class);
180
232
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
181
- WritableMap writableMap = mock(WritableMap.class);
233
+ FirebaseOptions firebaseOptions = mock(FirebaseOptions.class);
182
234
 
183
235
  when(appConfig.getString("name")).thenReturn("secondary");
236
+ when(options.getString("apiKey")).thenReturn("api-key");
237
+ when(options.getString("appId")).thenReturn("app-id");
184
238
  when(options.getString("authDomain")).thenReturn("example.firebaseapp.com");
239
+ when(firebaseApp.getName()).thenReturn("secondary");
240
+ when(firebaseApp.getOptions()).thenReturn(firebaseOptions);
185
241
 
186
- try (MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class)) {
187
- convert
188
- .when(() -> RCTConvertFirebase.readableMapToFirebaseApp(options, appConfig, reactContext))
242
+ try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class);
243
+ MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
244
+ firebaseApps
245
+ .when(
246
+ () ->
247
+ FirebaseApp.initializeApp(
248
+ eq(reactContext), any(FirebaseOptions.class), eq("secondary")))
189
249
  .thenReturn(firebaseApp);
190
- convert
191
- .when(() -> RCTConvertFirebase.firebaseAppToWritableMap(firebaseApp))
192
- .thenReturn(writableMap);
193
-
194
250
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
195
251
  module.initializeApp(options, appConfig, promise);
196
252
 
197
253
  assertEquals("example.firebaseapp.com", NativeRNFBTurboApp.authDomains.get("secondary"));
198
- verify(promise).resolve(writableMap);
254
+ firebaseApps.verify(
255
+ () ->
256
+ FirebaseApp.initializeApp(
257
+ eq(reactContext), any(FirebaseOptions.class), eq("secondary")));
258
+ arguments.verify(() -> Arguments.makeNativeMap(anyMap()));
259
+ verify(promise).resolve(null);
199
260
  }
200
261
  }
201
262
 
@@ -207,6 +268,15 @@ public class NativeRNFBTurboAppTest {
207
268
  assertFalse(NativeRNFBTurboApp.authDomains.containsKey("secondary"));
208
269
  }
209
270
 
271
+ @Test
272
+ public void configureAuthDomain_preservesConcurrentHashMapNullKeyFailures() {
273
+ assertThrows(
274
+ NullPointerException.class,
275
+ () -> NativeRNFBTurboApp.configureAuthDomain(null, "example.firebaseapp.com"));
276
+ assertThrows(
277
+ NullPointerException.class, () -> NativeRNFBTurboApp.configureAuthDomain(null, null));
278
+ }
279
+
210
280
  @Test
211
281
  public void firebaseAppToMap_includesOnlyConfiguredAuthDomain() {
212
282
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
@@ -233,11 +303,18 @@ public class NativeRNFBTurboAppTest {
233
303
  public void setAutomaticDataCollectionEnabled_delegatesToFirebaseApp() {
234
304
  FirebaseApp firebaseApp = mock(FirebaseApp.class);
235
305
  try (MockedStatic<FirebaseApp> firebaseApps = mockStatic(FirebaseApp.class)) {
236
- firebaseApps.when(() -> FirebaseApp.getInstance("secondary")).thenReturn(firebaseApp);
306
+ firebaseApps
307
+ .when(() -> FirebaseApp.getInstance((String) null))
308
+ .thenAnswer(
309
+ invocation -> {
310
+ assertNull(invocation.getArgument(0));
311
+ return firebaseApp;
312
+ });
237
313
 
238
314
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
239
- module.setAutomaticDataCollectionEnabled("secondary", true);
315
+ module.setAutomaticDataCollectionEnabled(null, true);
240
316
 
317
+ firebaseApps.verify(() -> FirebaseApp.getInstance((String) null));
241
318
  verify(firebaseApp).setDataCollectionDefaultEnabled(true);
242
319
  }
243
320
  }
@@ -269,6 +346,22 @@ public class NativeRNFBTurboAppTest {
269
346
  module.deleteApp("missing", promise);
270
347
 
271
348
  verify(promise).resolve(null);
349
+
350
+ RuntimeException fromFirebase = new RuntimeException("from FirebaseApp.getInstance");
351
+ firebaseApps
352
+ .when(() -> FirebaseApp.getInstance((String) null))
353
+ .thenAnswer(
354
+ invocation -> {
355
+ assertNull(invocation.getArgument(0));
356
+ throw fromFirebase;
357
+ });
358
+ Promise nullNamePromise = mock(Promise.class);
359
+
360
+ assertSame(
361
+ fromFirebase,
362
+ assertThrows(RuntimeException.class, () -> module.deleteApp(null, nullNamePromise)));
363
+ firebaseApps.verify(() -> FirebaseApp.getInstance((String) null));
364
+ verifyNoInteractions(nullNamePromise);
272
365
  }
273
366
  }
274
367
 
@@ -298,18 +391,39 @@ public class NativeRNFBTurboAppTest {
298
391
  }
299
392
 
300
393
  @Test
301
- public void eventsPing_sendsEventAndResolvesBody() {
394
+ public void eventsPing_sendsEventAndResolvesBody() throws Exception {
302
395
  ReadableMap body = mock(ReadableMap.class);
303
- WritableMap writable = mock(WritableMap.class);
396
+ WritableMap eventWritable = mock(WritableMap.class);
397
+ WritableMap resolvedWritable = mock(WritableMap.class);
398
+ WritableMap nullNameWritable = mock(WritableMap.class);
304
399
  Promise promise = mock(Promise.class);
305
400
 
306
- try (MockedStatic<RCTConvertFirebase> convert = mockStatic(RCTConvertFirebase.class)) {
307
- convert.when(() -> RCTConvertFirebase.readableMapToWritableMap(body)).thenReturn(writable);
401
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
402
+ arguments
403
+ .when(Arguments::createMap)
404
+ .thenReturn(eventWritable, resolvedWritable, nullNameWritable);
308
405
 
309
406
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
310
407
  module.eventsPing("ping_event", body, promise);
408
+ ShadowLooper.idleMainLooper();
311
409
 
312
- verify(promise).resolve(writable);
410
+ verify(eventWritable).merge(body);
411
+ verify(resolvedWritable).merge(body);
412
+ verify(promise).resolve(resolvedWritable);
413
+ @SuppressWarnings("unchecked")
414
+ List<NativeEvent> queuedEvents =
415
+ (List<NativeEvent>)
416
+ getEmitterField("queuedEvents")
417
+ .get(ReactNativeFirebaseEventEmitter.getSharedInstance());
418
+ assertEquals(1, queuedEvents.size());
419
+ assertEquals("ping_event", queuedEvents.get(0).getEventName());
420
+ assertSame(eventWritable, queuedEvents.get(0).getEventBody());
421
+
422
+ Promise nullNamePromise = mock(Promise.class);
423
+ assertThrows(
424
+ NullPointerException.class, () -> module.eventsPing(null, body, nullNamePromise));
425
+ verify(nullNameWritable).merge(body);
426
+ verifyNoInteractions(nullNamePromise);
313
427
  }
314
428
  }
315
429
 
@@ -341,12 +455,9 @@ public class NativeRNFBTurboAppTest {
341
455
  public void metaGetAll_resolvesMetaSingleton() {
342
456
  Promise promise = mock(Promise.class);
343
457
  WritableMap all = mock(WritableMap.class);
344
- ReactNativeFirebaseMeta meta = mock(ReactNativeFirebaseMeta.class);
345
- when(meta.getAll()).thenReturn(all);
346
458
 
347
- try (MockedStatic<ReactNativeFirebaseMeta> metaStatic =
348
- mockStatic(ReactNativeFirebaseMeta.class)) {
349
- metaStatic.when(ReactNativeFirebaseMeta::getSharedInstance).thenReturn(meta);
459
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
460
+ arguments.when(Arguments::createMap).thenReturn(all);
350
461
 
351
462
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
352
463
  module.metaGetAll(promise);
@@ -358,12 +469,9 @@ public class NativeRNFBTurboAppTest {
358
469
  public void jsonGetAll_resolvesJsonSingleton() {
359
470
  Promise promise = mock(Promise.class);
360
471
  WritableMap all = mock(WritableMap.class);
361
- ReactNativeFirebaseJSON json = mock(ReactNativeFirebaseJSON.class);
362
- when(json.getAll()).thenReturn(all);
363
472
 
364
- try (MockedStatic<ReactNativeFirebaseJSON> jsonStatic =
365
- mockStatic(ReactNativeFirebaseJSON.class)) {
366
- jsonStatic.when(ReactNativeFirebaseJSON::getSharedInstance).thenReturn(json);
473
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
474
+ arguments.when(Arguments::createMap).thenReturn(all);
367
475
 
368
476
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
369
477
  module.jsonGetAll(promise);
@@ -373,28 +481,37 @@ public class NativeRNFBTurboAppTest {
373
481
 
374
482
  @Test
375
483
  public void preferencesSettersAndGetters_delegateToPreferencesSingleton() {
376
- Promise promise = mock(Promise.class);
484
+ Promise boolPromise = mock(Promise.class);
485
+ Promise stringPromise = mock(Promise.class);
486
+ Promise getPromise = mock(Promise.class);
487
+ Promise clearPromise = mock(Promise.class);
377
488
  WritableMap all = mock(WritableMap.class);
378
- ReactNativeFirebasePreferences prefs = mock(ReactNativeFirebasePreferences.class);
379
- when(prefs.getAll()).thenReturn(all);
380
489
 
381
- try (MockedStatic<ReactNativeFirebasePreferences> prefsStatic =
382
- mockStatic(ReactNativeFirebasePreferences.class)) {
383
- prefsStatic.when(ReactNativeFirebasePreferences::getSharedInstance).thenReturn(prefs);
490
+ try (MockedStatic<Arguments> arguments = mockStatic(Arguments.class)) {
491
+ arguments.when(Arguments::createMap).thenReturn(all);
384
492
 
385
493
  NativeRNFBTurboApp module = new NativeRNFBTurboApp(reactContext);
386
- module.preferencesSetBool("k", true, promise);
387
- verify(prefs).setBooleanValue("k", true);
388
- verify(promise).resolve(null);
389
-
390
- module.preferencesSetString("k", "v", promise);
391
- verify(prefs).setStringValue("k", "v");
392
-
393
- module.preferencesGetAll(promise);
394
- verify(promise).resolve(all);
395
-
396
- module.preferencesClearAll(promise);
397
- verify(prefs).clearAll();
494
+ module.preferencesSetBool("bool", true, boolPromise);
495
+ assertTrue(ReactNativeFirebasePreferences.getSharedInstance().getBooleanValue("bool", false));
496
+ verify(boolPromise).resolve(null);
497
+
498
+ assertThrows(
499
+ NullPointerException.class, () -> module.preferencesSetBool("nullPromise", true, null));
500
+ assertTrue(
501
+ ReactNativeFirebasePreferences.getSharedInstance().getBooleanValue("nullPromise", false));
502
+
503
+ module.preferencesSetString("string", "v", stringPromise);
504
+ assertEquals(
505
+ "v", ReactNativeFirebasePreferences.getSharedInstance().getStringValue("string", null));
506
+ verify(stringPromise).resolve(null);
507
+
508
+ module.preferencesGetAll(getPromise);
509
+ verify(getPromise).resolve(all);
510
+
511
+ module.preferencesClearAll(clearPromise);
512
+ assertFalse(ReactNativeFirebasePreferences.getSharedInstance().contains("bool"));
513
+ assertFalse(ReactNativeFirebasePreferences.getSharedInstance().contains("string"));
514
+ verify(clearPromise).resolve(null);
398
515
  }
399
516
  }
400
517
 
@@ -414,6 +531,12 @@ public class NativeRNFBTurboAppTest {
414
531
  shared.set(null, fresh);
415
532
  }
416
533
 
534
+ private static Field getEmitterField(String name) throws Exception {
535
+ Field field = ReactNativeFirebaseEventEmitter.class.getDeclaredField(name);
536
+ field.setAccessible(true);
537
+ return field;
538
+ }
539
+
417
540
  @SuppressWarnings("unchecked")
418
541
  private static ReactContext attachedContext() throws Exception {
419
542
  ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
@@ -0,0 +1,70 @@
1
+ package com.google.firebase.platforminfo;
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 static org.junit.Assert.assertEquals;
20
+ import static org.junit.Assert.assertFalse;
21
+ import static org.junit.Assert.assertTrue;
22
+
23
+ import com.google.firebase.components.Component;
24
+ import com.google.firebase.components.ComponentRegistrar;
25
+ import io.invertase.firebase.app.ReactNativeFirebaseAppInitProvider;
26
+ import io.invertase.firebase.app.ReactNativeFirebaseAppRegistrar;
27
+ import io.invertase.firebase.app.ReactNativeFirebaseVersion;
28
+ import io.invertase.firebase.common.ReactNativeFirebaseInitProvider;
29
+ import java.lang.reflect.Constructor;
30
+ import java.lang.reflect.Modifier;
31
+ import java.util.List;
32
+ import org.junit.Test;
33
+
34
+ public class ReactNativeFirebaseAppComponentsJavaCompatibilityTest {
35
+ @Test
36
+ public void initProviderPreservesManifestReflectionAbi() throws Exception {
37
+ Class<ReactNativeFirebaseAppInitProvider> providerClass =
38
+ ReactNativeFirebaseAppInitProvider.class;
39
+
40
+ assertTrue(Modifier.isPublic(providerClass.getModifiers()));
41
+ assertFalse(Modifier.isFinal(providerClass.getModifiers()));
42
+ assertEquals(ReactNativeFirebaseInitProvider.class, providerClass.getSuperclass());
43
+
44
+ Constructor<ReactNativeFirebaseAppInitProvider> constructor =
45
+ providerClass.getDeclaredConstructor();
46
+ assertTrue(Modifier.isPublic(constructor.getModifiers()));
47
+ assertEquals(providerClass, constructor.newInstance().getClass());
48
+ }
49
+
50
+ @Test
51
+ public void registrarPreservesReflectionAndJavaGenericAbi() throws Exception {
52
+ Class<ReactNativeFirebaseAppRegistrar> registrarClass = ReactNativeFirebaseAppRegistrar.class;
53
+
54
+ assertTrue(Modifier.isPublic(registrarClass.getModifiers()));
55
+ assertFalse(Modifier.isFinal(registrarClass.getModifiers()));
56
+ assertTrue(ComponentRegistrar.class.isAssignableFrom(registrarClass));
57
+
58
+ Constructor<ReactNativeFirebaseAppRegistrar> constructor =
59
+ registrarClass.getDeclaredConstructor();
60
+ assertTrue(Modifier.isPublic(constructor.getModifiers()));
61
+
62
+ ReactNativeFirebaseAppRegistrar registrar = constructor.newInstance();
63
+ List<Component<?>> components = registrar.getComponents();
64
+ assertEquals(1, components.size());
65
+
66
+ LibraryVersion version = (LibraryVersion) components.get(0).getFactory().create(null);
67
+ assertEquals("react-native-firebase", version.getLibraryName());
68
+ assertEquals(ReactNativeFirebaseVersion.VERSION, version.getVersion());
69
+ }
70
+ }