@react-native-firebase/analytics 23.8.8 → 24.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 (51) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +24 -0
  3. package/RNFBAnalytics.podspec +2 -1
  4. package/android/src/reactnative/java/io/invertase/firebase/analytics/ReactNativeFirebaseAnalyticsModule.java +48 -4
  5. package/app.plugin.js +1 -0
  6. package/dist/module/modular.js +15 -3
  7. package/dist/module/modular.js.map +1 -1
  8. package/dist/module/namespaced.js +5 -4
  9. package/dist/module/namespaced.js.map +1 -1
  10. package/dist/module/structs.js +4 -3
  11. package/dist/module/structs.js.map +1 -1
  12. package/dist/module/types/analytics.js.map +1 -1
  13. package/dist/module/types/internal.js +4 -0
  14. package/dist/module/types/internal.js.map +1 -0
  15. package/dist/module/version.js +1 -1
  16. package/dist/typescript/lib/modular.d.ts +8 -3
  17. package/dist/typescript/lib/modular.d.ts.map +1 -1
  18. package/dist/typescript/lib/namespaced.d.ts +1 -0
  19. package/dist/typescript/lib/namespaced.d.ts.map +1 -1
  20. package/dist/typescript/lib/structs.d.ts +58 -2
  21. package/dist/typescript/lib/structs.d.ts.map +1 -1
  22. package/dist/typescript/lib/types/analytics.d.ts +2 -1
  23. package/dist/typescript/lib/types/analytics.d.ts.map +1 -1
  24. package/dist/typescript/lib/types/internal.d.ts +39 -0
  25. package/dist/typescript/lib/types/internal.d.ts.map +1 -0
  26. package/dist/typescript/lib/version.d.ts +1 -1
  27. package/ios/RNFBAnalytics/RNFBAnalyticsLogTransaction.swift +74 -0
  28. package/ios/RNFBAnalytics/RNFBAnalyticsModule.m +71 -3
  29. package/ios/RNFBAnalytics.xcodeproj/project.pbxproj +6 -0
  30. package/lib/modular.ts +17 -3
  31. package/lib/namespaced.ts +18 -7
  32. package/lib/structs.ts +3 -2
  33. package/lib/types/analytics.ts +2 -1
  34. package/lib/types/internal.ts +62 -0
  35. package/lib/version.ts +1 -1
  36. package/package.json +16 -5
  37. package/plugin/build/index.d.ts +4 -0
  38. package/plugin/build/index.js +16 -0
  39. package/plugin/build/ios/index.d.ts +2 -0
  40. package/plugin/build/ios/index.js +6 -0
  41. package/plugin/build/ios/podfile.d.ts +6 -0
  42. package/plugin/build/ios/podfile.js +45 -0
  43. package/plugin/build/pluginConfig.d.ts +10 -0
  44. package/plugin/build/pluginConfig.js +2 -0
  45. package/plugin/src/index.ts +18 -0
  46. package/plugin/src/ios/index.ts +6 -0
  47. package/plugin/src/ios/podfile.ts +72 -0
  48. package/plugin/src/pluginConfig.ts +11 -0
  49. package/plugin/tsconfig.json +9 -0
  50. package/plugin/tsconfig.tsbuildinfo +1 -0
  51. package/typedoc.json +48 -0
@@ -0,0 +1,39 @@
1
+ import type { Analytics } from './analytics';
2
+ /**
3
+ * Native Analytics module interface (RNFBAnalyticsModule).
4
+ * Matches the methods exposed by the native iOS/Android bridge.
5
+ * logTransaction and initiateOnDeviceConversionMeasurement* are iOS-only.
6
+ */
7
+ export interface RNFBAnalyticsModule {
8
+ logEvent(name: string, params?: Record<string, unknown>): Promise<void>;
9
+ setUserId(userId: string | null): Promise<void>;
10
+ setUserProperty(key: string, value: string | null): Promise<void>;
11
+ setUserProperties(properties: Record<string, string | number | boolean | null>): Promise<void>;
12
+ setDefaultEventParameters(params?: Record<string, unknown> | null): Promise<void>;
13
+ setConsent(consent: Record<string, unknown>): Promise<void>;
14
+ setAnalyticsCollectionEnabled(enabled: boolean): Promise<void>;
15
+ resetAnalyticsData(): Promise<void>;
16
+ setSessionTimeoutDuration(milliseconds?: number): Promise<void>;
17
+ getAppInstanceId(): Promise<string | null>;
18
+ getSessionId(): Promise<number | null>;
19
+ /** iOS only (StoreKit 2). Not present on Android native. */
20
+ logTransaction(transactionId: string): Promise<void>;
21
+ /** iOS only. */
22
+ initiateOnDeviceConversionMeasurementWithEmailAddress?(emailAddress: string): Promise<void>;
23
+ /** iOS only. */
24
+ initiateOnDeviceConversionMeasurementWithHashedEmailAddress?(hashedEmailAddress: string): Promise<void>;
25
+ /** iOS only. */
26
+ initiateOnDeviceConversionMeasurementWithPhoneNumber?(phoneNumber: string): Promise<void>;
27
+ /** iOS only. */
28
+ initiateOnDeviceConversionMeasurementWithHashedPhoneNumber?(hashedPhoneNumber: string): Promise<void>;
29
+ }
30
+ declare module '@react-native-firebase/app/dist/module/internal/NativeModules' {
31
+ interface ReactNativeFirebaseNativeModules {
32
+ RNFBAnalyticsModule: RNFBAnalyticsModule;
33
+ }
34
+ }
35
+ /** Analytics instance with native module typed for modular API (e.g. logTransaction). */
36
+ export interface AnalyticsInternal extends Analytics {
37
+ readonly native: RNFBAnalyticsModule;
38
+ }
39
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../../../lib/types/internal.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/F,yBAAyB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,yBAAyB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,4DAA4D;IAC5D,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,gBAAgB;IAChB,qDAAqD,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,gBAAgB;IAChB,2DAA2D,CAAC,CAC1D,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,gBAAgB;IAChB,oDAAoD,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,gBAAgB;IAChB,0DAA0D,CAAC,CACzD,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,OAAO,QAAQ,+DAA+D,CAAC;IAC7E,UAAU,gCAAgC;QACxC,mBAAmB,EAAE,mBAAmB,CAAC;KAC1C;CACF;AAED,yFAAyF;AACzF,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;CACtC"}
@@ -1,2 +1,2 @@
1
- export declare const version = "23.8.8";
1
+ export declare const version = "24.1.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ import Foundation
19
+ import FirebaseAnalytics
20
+ import StoreKit
21
+
22
+ /// Swift wrapper for logging a verified StoreKit 2 transaction to Firebase Analytics.
23
+ /// Accessible from Objective-C; necessary because StoreKit 2 and Analytics.logTransaction use Swift async APIs.
24
+ /// Call from ObjC only when @available(iOS 15.0, *) (see RNFBFunctionsStreamHandler pattern).
25
+ @available(iOS 15.0, macOS 12.0, *)
26
+ @objcMembers public class RNFBAnalyticsLogTransaction: NSObject {
27
+
28
+ private static let kCode = "firebase_analytics"
29
+ private var logTask: Task<Void, Never>?
30
+
31
+ /// Resolve/reject types matching RCTPromiseResolveBlock / RCTPromiseRejectBlock for React Native bridge.
32
+ @objc public func logTransaction(
33
+ transactionId: String,
34
+ resolve: @escaping (Any?) -> Void,
35
+ reject: @escaping (String, String, NSError?) -> Void
36
+ ) {
37
+ logTask = Task {
38
+ await performLogTransaction(transactionId: transactionId, resolve: resolve, reject: reject)
39
+ logTask = nil
40
+ }
41
+ }
42
+
43
+ private func performLogTransaction(
44
+ transactionId: String,
45
+ resolve: @escaping (Any?) -> Void,
46
+ reject: @escaping (String, String, NSError?) -> Void
47
+ ) async {
48
+ guard let id = UInt64(transactionId) else {
49
+ await MainActor.run { reject(Self.kCode, "Invalid transactionId", nil) }
50
+ return
51
+ }
52
+
53
+ var foundTransaction: StoreKit.Transaction?
54
+ for await result in StoreKit.Transaction.all {
55
+ switch result {
56
+ case let .verified(transaction):
57
+ if transaction.id == id {
58
+ foundTransaction = transaction
59
+ break
60
+ }
61
+ case .unverified:
62
+ continue
63
+ }
64
+ }
65
+
66
+ guard let transaction = foundTransaction else {
67
+ await MainActor.run { reject(Self.kCode, "Transaction not found", nil) }
68
+ return
69
+ }
70
+
71
+ Analytics.logTransaction(transaction)
72
+ await MainActor.run { resolve(NSNull()) }
73
+ }
74
+ }
@@ -18,9 +18,38 @@
18
18
  #import <Firebase/Firebase.h>
19
19
  #import <React/RCTUtils.h>
20
20
 
21
+ #if __has_include(<RNFBAnalytics/RNFBAnalytics-Swift.h>)
22
+ // This import will work in situations where `use_frameworks!` is in use
23
+ #import <RNFBAnalytics/RNFBAnalytics-Swift.h>
24
+ #elif __has_include("RNFBAnalytics-Swift.h")
25
+ // If `use_frameworks!` is not in use (for example, while using pre-built
26
+ // react-native core) then header imports based on frameworks assumptions fail.
27
+ // So, if frameworks are not available, fall back to importing the header directly, it
28
+ // should be findable from a header search path pointing to the build
29
+ // directory. See firebase-ios-sdk#12611 for more context.
30
+ #import "RNFBAnalytics-Swift.h"
31
+ #endif
21
32
  #import <RNFBApp/RNFBSharedUtils.h>
22
33
  #import "RNFBAnalyticsModule.h"
23
34
 
35
+ /** GA4 parameters that must be sent as integer NSNumber values (not doubles from JS). */
36
+ static NSArray<NSString *> *RNFBAnalyticsLongNumericParameterKeys(void) {
37
+ static NSArray<NSString *> *keys;
38
+ static dispatch_once_t onceToken;
39
+ dispatch_once(&onceToken, ^{
40
+ keys = @[
41
+ kFIRParameterQuantity,
42
+ kFIRParameterIndex,
43
+ kFIRParameterLevel,
44
+ kFIRParameterNumberOfNights,
45
+ kFIRParameterNumberOfPassengers,
46
+ kFIRParameterNumberOfRooms,
47
+ kFIRParameterScore,
48
+ ];
49
+ });
50
+ return keys;
51
+ }
52
+
24
53
  @implementation RNFBAnalyticsModule
25
54
  #pragma mark -
26
55
  #pragma mark Module Setup
@@ -212,6 +241,18 @@ RCT_EXPORT_METHOD(initiateOnDeviceConversionMeasurementWithHashedPhoneNumber
212
241
  return resolve([NSNull null]);
213
242
  }
214
243
 
244
+ RCT_EXPORT_METHOD(logTransaction
245
+ : (NSString *)transactionId resolver
246
+ : (RCTPromiseResolveBlock)resolve rejecter
247
+ : (RCTPromiseRejectBlock)reject) {
248
+ if (@available(iOS 15.0, macOS 12.0, *)) {
249
+ RNFBAnalyticsLogTransaction *handler = [[RNFBAnalyticsLogTransaction alloc] init];
250
+ [handler logTransactionWithTransactionId:transactionId resolve:resolve reject:reject];
251
+ } else {
252
+ reject(@"firebase_analytics", @"logTransaction() is only supported on iOS 15.0 or newer", nil);
253
+ }
254
+ }
255
+
215
256
  RCT_EXPORT_METHOD(setConsent
216
257
  : (NSDictionary *)consentSettings resolver
217
258
  : (RCTPromiseResolveBlock)resolve rejecter
@@ -245,13 +286,13 @@ RCT_EXPORT_METHOD(setConsent
245
286
  [(NSArray *)newParams[kFIRParameterItems]
246
287
  enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
247
288
  NSMutableDictionary *item = [obj mutableCopy];
248
- if (item[kFIRParameterQuantity]) {
249
- item[kFIRParameterQuantity] = @([item[kFIRParameterQuantity] integerValue]);
250
- }
289
+ [self rnfb_coerceLongNumericParametersInMutableDictionary:item];
251
290
  [newItems addObject:[item copy]];
252
291
  }];
253
292
  newParams[kFIRParameterItems] = [newItems copy];
254
293
  }
294
+ [self rnfb_coerceLongNumericParametersInMutableDictionary:newParams];
295
+ [self rnfb_coerceSuccessParameterInMutableDictionary:newParams];
255
296
  NSNumber *extendSession = [newParams valueForKey:kFIRParameterExtendSession];
256
297
  if ([extendSession isEqualToNumber:@1]) {
257
298
  newParams[kFIRParameterExtendSession] = @YES;
@@ -259,6 +300,33 @@ RCT_EXPORT_METHOD(setConsent
259
300
  return [newParams copy];
260
301
  }
261
302
 
303
+ - (void)rnfb_coerceLongNumericParametersInMutableDictionary:(NSMutableDictionary *)dict {
304
+ for (NSString *key in RNFBAnalyticsLongNumericParameterKeys()) {
305
+ id value = dict[key];
306
+ if (value != nil && value != [NSNull null]) {
307
+ dict[key] = @([value integerValue]);
308
+ }
309
+ }
310
+ }
311
+
312
+ - (void)rnfb_coerceSuccessParameterInMutableDictionary:(NSMutableDictionary *)dict {
313
+ id value = dict[kFIRParameterSuccess];
314
+ if (value == nil || value == [NSNull null]) {
315
+ return;
316
+ }
317
+ int success = 0;
318
+ if ([value isKindOfClass:[NSString class]]) {
319
+ NSString *lower = [(NSString *)value lowercaseString];
320
+ if ([lower isEqualToString:@"true"] || [lower isEqualToString:@"yes"] ||
321
+ [lower isEqualToString:@"1"]) {
322
+ success = 1;
323
+ }
324
+ } else {
325
+ success = [value boolValue] ? 1 : 0;
326
+ }
327
+ dict[kFIRParameterSuccess] = @(success);
328
+ }
329
+
262
330
  /// Converts null values received over the bridge from NSNull to nil
263
331
  /// @param value Nullable string value
264
332
  - (NSString *)convertNSNullToNil:(NSString *)value {
@@ -8,6 +8,7 @@
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
10
  2744B98621F45429004F8E3F /* RNFBAnalyticsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAnalyticsModule.m */; };
11
+ 2744B99021F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */; };
11
12
  /* End PBXBuildFile section */
12
13
 
13
14
  /* Begin PBXCopyFilesBuildPhase section */
@@ -26,6 +27,7 @@
26
27
  2744B98221F45429004F8E3F /* libRNFBAnalytics.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBAnalytics.a; sourceTree = BUILT_PRODUCTS_DIR; };
27
28
  2744B98421F45429004F8E3F /* RNFBAnalyticsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAnalyticsModule.h; path = RNFBAnalytics/RNFBAnalyticsModule.h; sourceTree = SOURCE_ROOT; };
28
29
  2744B98521F45429004F8E3F /* RNFBAnalyticsModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAnalyticsModule.m; path = RNFBAnalytics/RNFBAnalyticsModule.m; sourceTree = SOURCE_ROOT; };
30
+ 2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAnalyticsLogTransaction.swift; path = RNFBAnalytics/RNFBAnalyticsLogTransaction.swift; sourceTree = SOURCE_ROOT; };
29
31
  /* End PBXFileReference section */
30
32
 
31
33
  /* Begin PBXFrameworksBuildPhase section */
@@ -54,6 +56,7 @@
54
56
  2744B98C21F45C64004F8E3F /* common */,
55
57
  2744B98421F45429004F8E3F /* RNFBAnalyticsModule.h */,
56
58
  2744B98521F45429004F8E3F /* RNFBAnalyticsModule.m */,
59
+ 2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */,
57
60
  );
58
61
  path = RNFBAnalytics;
59
62
  sourceTree = "<group>";
@@ -125,6 +128,7 @@
125
128
  buildActionMask = 2147483647;
126
129
  files = (
127
130
  2744B98621F45429004F8E3F /* RNFBAnalyticsModule.m in Sources */,
131
+ 2744B99021F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift in Sources */,
128
132
  );
129
133
  runOnlyForDeploymentPostprocessing = 0;
130
134
  };
@@ -166,6 +170,7 @@
166
170
  PRODUCT_NAME = "$(TARGET_NAME)";
167
171
  SDKROOT = iphoneos;
168
172
  SKIP_INSTALL = YES;
173
+ SWIFT_VERSION = 5.0;
169
174
  TARGETED_DEVICE_FAMILY = "1,2";
170
175
  };
171
176
  name = Debug;
@@ -200,6 +205,7 @@
200
205
  PRODUCT_NAME = "$(TARGET_NAME)";
201
206
  SDKROOT = iphoneos;
202
207
  SKIP_INSTALL = YES;
208
+ SWIFT_VERSION = 5.0;
203
209
  TARGETED_DEVICE_FAMILY = "1,2";
204
210
  VALIDATE_PRODUCT = YES;
205
211
  };
package/lib/modular.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/dist/module/common';
2
2
  import { getApp } from '@react-native-firebase/app';
3
3
  import type { Analytics } from './types/analytics';
4
+ import type { AnalyticsInternal } from './types/internal';
4
5
  import { Platform } from 'react-native';
5
6
  import type { ReactNativeFirebase } from '@react-native-firebase/app';
6
7
  import type {
@@ -416,6 +417,18 @@ export function logEvent(
416
417
  return analytics.logEvent.call(analytics, name, params, options, MODULAR_DEPRECATION_ARG);
417
418
  }
418
419
 
420
+ /** Logs verified in-app purchase events in Google Analytics for Firebase
421
+ * after a purchase is successful.
422
+ * Modular API only; iOS only (StoreKit 2). Throws on Android and web before reaching native.
423
+ */
424
+ export function logTransaction(analytics: Analytics, transaction_id: string): Promise<void> {
425
+ if (Platform.OS !== 'ios') {
426
+ return Promise.reject(new Error('logTransaction is only available on iOS'));
427
+ }
428
+
429
+ return (analytics as AnalyticsInternal).native.logTransaction(transaction_id);
430
+ }
431
+
419
432
  /**
420
433
  * If true, allows the device to collect analytical data and send it to Firebase. Useful for GDPR.
421
434
  */
@@ -935,10 +948,10 @@ export function initiateOnDeviceConversionMeasurementWithEmailAddress(
935
948
  * start privacy-sensitive on-device conversion management.
936
949
  * This is iOS-only.
937
950
  * This is a no-op if you do not include '$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true' in your Podfile
951
+ * {@link https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3#use-hashed-credentials}
938
952
  *
939
953
  * @param analytics Analytics instance.
940
954
  * @param hashedEmailAddress sha256-hashed of normalized email address, properly formatted complete with domain name e.g, 'user@example.com'
941
- * @link https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3#use-hashed-credentials
942
955
  */
943
956
  export function initiateOnDeviceConversionMeasurementWithHashedEmailAddress(
944
957
  analytics: Analytics,
@@ -975,10 +988,10 @@ export function initiateOnDeviceConversionMeasurementWithPhoneNumber(
975
988
  * start privacy-sensitive on-device conversion management.
976
989
  * This is iOS-only.
977
990
  * This is a no-op if you do not include '$RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion = true' in your Podfile
991
+ * {@link https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3#use-hashed-credentials}
978
992
  *
979
993
  * @param analytics Analytics instance.
980
994
  * @param hashedPhoneNumber sha256-hashed of normalized phone number in E.164 format - that is a leading + sign, then up to 15 digits, no dashes or spaces.
981
- * @link https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3#use-hashed-credentials
982
995
  */
983
996
  export function initiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
984
997
  analytics: Analytics,
@@ -1018,9 +1031,10 @@ export function setConsent(analytics: Analytics, consentSettings: ConsentSetting
1018
1031
  /**
1019
1032
  * Configures Firebase Analytics to use custom gtag or dataLayer names.
1020
1033
  * Intended to be used if gtag.js script has been installed on this page independently of Firebase Analytics, and is using non-default names for either the gtag function or for dataLayer. Must be called before calling `getAnalytics()` or it won't have any effect. Web only.
1021
- * @param {SettingsOptions} options - See SettingsOptions.
1034
+ * @param {SettingsOptions} _options - See SettingsOptions - currently unused.
1022
1035
  * @returns {void}
1023
1036
  */
1037
+
1024
1038
  export function settings(_options: SettingsOptions): void {
1025
1039
  // Returns nothing until Web implemented.
1026
1040
  }
package/lib/namespaced.ts CHANGED
@@ -34,6 +34,8 @@ import {
34
34
  getFirebaseRoot,
35
35
  } from '@react-native-firebase/app/dist/module/internal';
36
36
 
37
+ import './types/internal';
38
+
37
39
  // Internal types are now available through module declarations in app package
38
40
  import { setReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule';
39
41
  import { isBoolean } from '@react-native-firebase/app/dist/module/common';
@@ -122,7 +124,7 @@ const namespace = 'analytics';
122
124
 
123
125
  const nativeModuleName = 'RNFBAnalyticsModule';
124
126
 
125
- class FirebaseAnalyticsModule extends FirebaseModule {
127
+ class FirebaseAnalyticsModule extends FirebaseModule<typeof nativeModuleName> {
126
128
  logEvent(
127
129
  name: string,
128
130
  params: { [key: string]: any } = {},
@@ -800,7 +802,10 @@ class FirebaseAnalyticsModule extends FirebaseModule {
800
802
  return Promise.resolve();
801
803
  }
802
804
 
803
- return this.native.initiateOnDeviceConversionMeasurementWithEmailAddress(emailAddress);
805
+ return (
806
+ this.native.initiateOnDeviceConversionMeasurementWithEmailAddress?.(emailAddress) ??
807
+ Promise.resolve()
808
+ );
804
809
  }
805
810
 
806
811
  initiateOnDeviceConversionMeasurementWithHashedEmailAddress(
@@ -816,8 +821,10 @@ class FirebaseAnalyticsModule extends FirebaseModule {
816
821
  return Promise.resolve();
817
822
  }
818
823
 
819
- return this.native.initiateOnDeviceConversionMeasurementWithHashedEmailAddress(
820
- hashedEmailAddress,
824
+ return (
825
+ this.native.initiateOnDeviceConversionMeasurementWithHashedEmailAddress?.(
826
+ hashedEmailAddress,
827
+ ) ?? Promise.resolve()
821
828
  );
822
829
  }
823
830
 
@@ -832,7 +839,10 @@ class FirebaseAnalyticsModule extends FirebaseModule {
832
839
  return Promise.resolve();
833
840
  }
834
841
 
835
- return this.native.initiateOnDeviceConversionMeasurementWithPhoneNumber(phoneNumber);
842
+ return (
843
+ this.native.initiateOnDeviceConversionMeasurementWithPhoneNumber?.(phoneNumber) ??
844
+ Promise.resolve()
845
+ );
836
846
  }
837
847
 
838
848
  initiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
@@ -854,8 +864,9 @@ class FirebaseAnalyticsModule extends FirebaseModule {
854
864
  return Promise.resolve();
855
865
  }
856
866
 
857
- return this.native.initiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
858
- hashedPhoneNumber,
867
+ return (
868
+ this.native.initiateOnDeviceConversionMeasurementWithHashedPhoneNumber?.(hashedPhoneNumber) ??
869
+ Promise.resolve()
859
870
  );
860
871
  }
861
872
  }
package/lib/structs.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { object, string, number, array, optional, define, type } from 'superstruct';
17
+ import { object, string, number, boolean, array, optional, define, type } from 'superstruct';
18
18
 
19
19
  const ShortDate = define(
20
20
  'ShortDate',
@@ -36,6 +36,7 @@ const Item = type({
36
36
  item_variant: optional(string()),
37
37
  quantity: optional(number()),
38
38
  price: optional(number()),
39
+ index: optional(number()),
39
40
  });
40
41
 
41
42
  export const ScreenView = type({
@@ -104,7 +105,7 @@ export const JoinGroup = object({
104
105
 
105
106
  export const LevelEnd = object({
106
107
  level: number(),
107
- success: optional(string()),
108
+ success: optional(boolean()),
108
109
  });
109
110
 
110
111
  export const LevelStart = object({
@@ -282,7 +282,7 @@ export interface LevelEndEventParameters {
282
282
  /**
283
283
  * The result of an operation.
284
284
  */
285
- success?: string;
285
+ success?: boolean;
286
286
  }
287
287
 
288
288
  export interface LevelStartEventParameters {
@@ -939,6 +939,7 @@ export interface Analytics extends ReactNativeFirebase.FirebaseModule {
939
939
  logShare(object: ShareEventParameters): Promise<void>;
940
940
  logSignUp(object: SignUpEventParameters): Promise<void>;
941
941
  logSpendVirtualCurrency(object: SpendVirtualCurrencyEventParameters): Promise<void>;
942
+ logTransaction(transaction_id: string): Promise<void>;
942
943
  logTutorialBegin(): Promise<void>;
943
944
  logTutorialComplete(): Promise<void>;
944
945
  logUnlockAchievement(object: UnlockAchievementEventParameters): Promise<void>;
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ import type { Analytics } from './analytics';
19
+
20
+ /**
21
+ * Native Analytics module interface (RNFBAnalyticsModule).
22
+ * Matches the methods exposed by the native iOS/Android bridge.
23
+ * logTransaction and initiateOnDeviceConversionMeasurement* are iOS-only.
24
+ */
25
+ export interface RNFBAnalyticsModule {
26
+ logEvent(name: string, params?: Record<string, unknown>): Promise<void>;
27
+ setUserId(userId: string | null): Promise<void>;
28
+ setUserProperty(key: string, value: string | null): Promise<void>;
29
+ setUserProperties(properties: Record<string, string | number | boolean | null>): Promise<void>;
30
+ setDefaultEventParameters(params?: Record<string, unknown> | null): Promise<void>;
31
+ setConsent(consent: Record<string, unknown>): Promise<void>;
32
+ setAnalyticsCollectionEnabled(enabled: boolean): Promise<void>;
33
+ resetAnalyticsData(): Promise<void>;
34
+ setSessionTimeoutDuration(milliseconds?: number): Promise<void>;
35
+ getAppInstanceId(): Promise<string | null>;
36
+ getSessionId(): Promise<number | null>;
37
+ /** iOS only (StoreKit 2). Not present on Android native. */
38
+ logTransaction(transactionId: string): Promise<void>;
39
+ /** iOS only. */
40
+ initiateOnDeviceConversionMeasurementWithEmailAddress?(emailAddress: string): Promise<void>;
41
+ /** iOS only. */
42
+ initiateOnDeviceConversionMeasurementWithHashedEmailAddress?(
43
+ hashedEmailAddress: string,
44
+ ): Promise<void>;
45
+ /** iOS only. */
46
+ initiateOnDeviceConversionMeasurementWithPhoneNumber?(phoneNumber: string): Promise<void>;
47
+ /** iOS only. */
48
+ initiateOnDeviceConversionMeasurementWithHashedPhoneNumber?(
49
+ hashedPhoneNumber: string,
50
+ ): Promise<void>;
51
+ }
52
+
53
+ declare module '@react-native-firebase/app/dist/module/internal/NativeModules' {
54
+ interface ReactNativeFirebaseNativeModules {
55
+ RNFBAnalyticsModule: RNFBAnalyticsModule;
56
+ }
57
+ }
58
+
59
+ /** Analytics instance with native module typed for modular API (e.g. logTransaction). */
60
+ export interface AnalyticsInternal extends Analytics {
61
+ readonly native: RNFBAnalyticsModule;
62
+ }
package/lib/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '23.8.8';
2
+ export const version = '24.1.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/analytics",
3
- "version": "23.8.8",
3
+ "version": "24.1.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - The analytics module provides out of the box support with Google Analytics for Firebase. Integration with the Android & iOS allows for in-depth analytical insight reporting, such as device information, location, user actions and more.",
6
6
  "main": "./dist/module/index.js",
@@ -8,8 +8,10 @@
8
8
  "scripts": {
9
9
  "build": "genversion --esm --semi lib/version.ts",
10
10
  "build:clean": "rimraf android/build && rimraf ios/build",
11
+ "build:plugin": "rimraf plugin/build && tsc --build plugin",
12
+ "lint:plugin": "eslint \"plugin/src/**/*.{ts,js}\"",
11
13
  "compile": "bob build",
12
- "prepare": "yarn run build && yarn compile"
14
+ "prepare": "yarn run build && yarn run build:plugin && yarn compile"
13
15
  },
14
16
  "repository": {
15
17
  "type": "git",
@@ -23,7 +25,8 @@
23
25
  "analytics"
24
26
  ],
25
27
  "peerDependencies": {
26
- "@react-native-firebase/app": "23.8.8"
28
+ "@react-native-firebase/app": "24.1.0",
29
+ "expo": ">=47.0.0"
27
30
  },
28
31
  "publishConfig": {
29
32
  "access": "public",
@@ -33,7 +36,14 @@
33
36
  "superstruct": "^2.0.2"
34
37
  },
35
38
  "devDependencies": {
36
- "react-native-builder-bob": "^0.40.17"
39
+ "expo": "^55.0.5",
40
+ "react-native-builder-bob": "^0.40.17",
41
+ "typescript": "^5.9.3"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "expo": {
45
+ "optional": true
46
+ }
37
47
  },
38
48
  "exports": {
39
49
  ".": {
@@ -41,6 +51,7 @@
41
51
  "types": "./dist/typescript/lib/index.d.ts",
42
52
  "default": "./dist/module/index.js"
43
53
  },
54
+ "./app.plugin.js": "./app.plugin.js",
44
55
  "./package.json": "./package.json"
45
56
  },
46
57
  "react-native-builder-bob": {
@@ -65,5 +76,5 @@
65
76
  "node_modules/",
66
77
  "dist/"
67
78
  ],
68
- "gitHead": "d17b898bee0be82259fc1b88f46106a927bf81aa"
79
+ "gitHead": "804a51fd265453f2385adb0ac96a6abf992c0316"
69
80
  }
@@ -0,0 +1,4 @@
1
+ import { ConfigPlugin } from '@expo/config-plugins';
2
+ import { PluginConfigType } from './pluginConfig';
3
+ declare const _default: ConfigPlugin<PluginConfigType>;
4
+ export default _default;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("@expo/config-plugins");
4
+ const ios_1 = require("./ios");
5
+ /**
6
+ * A config plugin for configuring `@react-native-firebase/analytics`
7
+ */
8
+ const withRnFirebaseAnalytics = (config, props) => {
9
+ return (0, config_plugins_1.withPlugins)(config, [
10
+ // iOS
11
+ [ios_1.withIosWithoutAdIdSupport, props],
12
+ [ios_1.withIosGoogleAppMeasurementOnDeviceConversion, props],
13
+ ]);
14
+ };
15
+ const pak = require('../../package.json');
16
+ exports.default = (0, config_plugins_1.createRunOncePlugin)(withRnFirebaseAnalytics, pak.name, pak.version);
@@ -0,0 +1,2 @@
1
+ import { withIosWithoutAdIdSupport, withIosGoogleAppMeasurementOnDeviceConversion } from './podfile';
2
+ export { withIosWithoutAdIdSupport, withIosGoogleAppMeasurementOnDeviceConversion };
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withIosGoogleAppMeasurementOnDeviceConversion = exports.withIosWithoutAdIdSupport = void 0;
4
+ const podfile_1 = require("./podfile");
5
+ Object.defineProperty(exports, "withIosWithoutAdIdSupport", { enumerable: true, get: function () { return podfile_1.withIosWithoutAdIdSupport; } });
6
+ Object.defineProperty(exports, "withIosGoogleAppMeasurementOnDeviceConversion", { enumerable: true, get: function () { return podfile_1.withIosGoogleAppMeasurementOnDeviceConversion; } });
@@ -0,0 +1,6 @@
1
+ import { ConfigPlugin } from '@expo/config-plugins';
2
+ import { PluginConfigType } from '../pluginConfig';
3
+ export declare function setAnalyticsPodfileWithoutAdIdSupport(src: string, enabled?: boolean): string;
4
+ export declare function setAnalyticsPodfileGoogleAppMeasurementOnDeviceConversion(src: string, enabled?: boolean): string;
5
+ export declare const withIosGoogleAppMeasurementOnDeviceConversion: ConfigPlugin<PluginConfigType>;
6
+ export declare const withIosWithoutAdIdSupport: ConfigPlugin<PluginConfigType>;