@react-native-firebase/analytics 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.
- package/CHANGELOG.md +22 -0
- package/RNFBAnalytics.podspec +49 -2
- package/android/src/main/java/io/invertase/firebase/analytics/UniversalFirebaseAnalyticsModule.java +17 -15
- package/android/src/reactnative/java/io/invertase/firebase/analytics/NativeRNFBTurboAnalytics.java +4 -3
- package/dist/module/index.js +26 -11
- package/dist/module/index.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/module/web/api.js +42 -19
- package/dist/module/web/api.js.map +1 -1
- package/dist/typescript/lib/index.d.ts +2 -2
- package/dist/typescript/lib/index.d.ts.map +1 -1
- package/dist/typescript/lib/version.d.ts +1 -1
- package/dist/typescript/lib/web/api.d.ts +4 -1
- package/dist/typescript/lib/web/api.d.ts.map +1 -1
- package/ios/RNFBAnalytics/RNFBAnalyticsConsentSettingsMapper.swift +98 -0
- package/ios/RNFBAnalytics/RNFBAnalyticsHelper.h +111 -0
- package/ios/RNFBAnalytics/RNFBAnalyticsHelper.m +338 -0
- package/ios/RNFBAnalytics/RNFBAnalyticsJavascriptParamsCleaner.swift +167 -0
- package/ios/RNFBAnalytics/RNFBAnalyticsLogTransaction.swift +2 -2
- package/ios/RNFBAnalytics/RNFBAnalyticsModule.mm +32 -251
- package/ios/RNFBAnalytics.xcodeproj/project.pbxproj +16 -2
- package/ios/RNFBAnalyticsUnitTests/HostStubs/Firebase/FIRAnalyticsHostStub.m +304 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/Firebase/Firebase.h +71 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/RNFBAnalytics/RNFBAnalyticsLogTransactionHostStub.h +20 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/RNFBAnalytics/RNFBAnalyticsLogTransactionHostStub.m +43 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/RNFBApp/RNFBSharedUtils.h +21 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/RNFBApp/RNFBSharedUtilsHostStub.m +26 -0
- package/ios/RNFBAnalyticsUnitTests/HostStubs/React/RCTBridgeModule.h +10 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsConsentSettingsMapperHostStubTests.m +62 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsConsentSettingsMapperTests.swift +91 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsHelperHostStubTests.m +542 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsJavascriptParamsCleanerHostStubTests.m +59 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsJavascriptParamsCleanerTests.swift +205 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsNullSentinelDecodeTests.m +111 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsUnitTests.xcodeproj/project.pbxproj +302 -0
- package/ios/RNFBAnalyticsUnitTests/RNFBAnalyticsUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBAnalyticsUnitTests.xcscheme +69 -0
- package/lib/index.ts +38 -10
- package/lib/version.ts +1 -1
- package/lib/web/api.ts +51 -19
- package/package.json +5 -4
|
@@ -0,0 +1,167 @@
|
|
|
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
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Foundation-friendly Analytics JS param helpers previously inlined in
|
|
21
|
+
* `RNFBAnalyticsModule.mm`.
|
|
22
|
+
*
|
|
23
|
+
* Pre-port contracts:
|
|
24
|
+
* - NSNull over the bridge → nil (`convertNSNullToNil`)
|
|
25
|
+
* - 64 hex chars → 32-byte `Data` or nil (`dataFromSHA256HexString`)
|
|
26
|
+
* - Long-numeric GA4 keys coerced via `integerValue`
|
|
27
|
+
* - `success` string/bool coercion to 0/1 `NSNumber`
|
|
28
|
+
* - `extend_session` `@1` → `@YES`
|
|
29
|
+
*
|
|
30
|
+
* Parameter key strings match Firebase Analytics `kFIRParameter*` values
|
|
31
|
+
* (Foundation-only so unit tests do not link the Analytics SDK).
|
|
32
|
+
*/
|
|
33
|
+
@objc(RNFBAnalyticsJavascriptParamsCleaner)
|
|
34
|
+
public final class RNFBAnalyticsJavascriptParamsCleaner: NSObject {
|
|
35
|
+
// MARK: - Firebase Analytics parameter key strings (kFIRParameter*)
|
|
36
|
+
|
|
37
|
+
private static let parameterQuantity = "quantity"
|
|
38
|
+
private static let parameterIndex = "index"
|
|
39
|
+
private static let parameterLevel = "level"
|
|
40
|
+
private static let parameterNumberOfNights = "number_of_nights"
|
|
41
|
+
private static let parameterNumberOfPassengers = "number_of_passengers"
|
|
42
|
+
private static let parameterNumberOfRooms = "number_of_rooms"
|
|
43
|
+
private static let parameterScore = "score"
|
|
44
|
+
private static let parameterItems = "items"
|
|
45
|
+
private static let parameterSuccess = "success"
|
|
46
|
+
private static let parameterExtendSession = "extend_session"
|
|
47
|
+
|
|
48
|
+
/// Same keys as pre-port `RNFBAnalyticsLongNumericParameterKeys`.
|
|
49
|
+
@objc public static var longNumericParameterKeys: [String] {
|
|
50
|
+
[
|
|
51
|
+
parameterQuantity,
|
|
52
|
+
parameterIndex,
|
|
53
|
+
parameterLevel,
|
|
54
|
+
parameterNumberOfNights,
|
|
55
|
+
parameterNumberOfPassengers,
|
|
56
|
+
parameterNumberOfRooms,
|
|
57
|
+
parameterScore,
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// MARK: - NSNull bridge
|
|
62
|
+
|
|
63
|
+
/// Converts null values received over the bridge from NSNull to nil.
|
|
64
|
+
@objc(convertNSNullToNil:)
|
|
65
|
+
public static func convertNSNullToNil(_ value: Any?) -> String? {
|
|
66
|
+
// Pre-port: `[value isEqual:[NSNull null]] ? nil : value`
|
|
67
|
+
if let value, (value as AnyObject).isEqual(NSNull()) {
|
|
68
|
+
return nil
|
|
69
|
+
}
|
|
70
|
+
return value as? String
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// MARK: - SHA-256 hex
|
|
74
|
+
|
|
75
|
+
private static func hexDigit(_ character: unichar) -> Int {
|
|
76
|
+
if character >= 0x30 && character <= 0x39 {
|
|
77
|
+
return Int(character) - 0x30
|
|
78
|
+
}
|
|
79
|
+
if character >= 0x61 && character <= 0x66 {
|
|
80
|
+
return Int(character) - 0x61 + 10
|
|
81
|
+
}
|
|
82
|
+
if character >= 0x41 && character <= 0x46 {
|
|
83
|
+
return Int(character) - 0x41 + 10
|
|
84
|
+
}
|
|
85
|
+
return -1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// 64 hex characters → 32-byte `Data`, or nil when length/hex is invalid.
|
|
89
|
+
@objc(dataFromSHA256HexString:)
|
|
90
|
+
public static func dataFromSHA256HexString(_ hexString: String?) -> Data? {
|
|
91
|
+
guard let hexString, (hexString as NSString).length == 64 else {
|
|
92
|
+
return nil
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
var bytes = [UInt8](repeating: 0, count: 32)
|
|
96
|
+
let nsString = hexString as NSString
|
|
97
|
+
for i in 0..<32 {
|
|
98
|
+
let high = hexDigit(nsString.character(at: i * 2))
|
|
99
|
+
let low = hexDigit(nsString.character(at: i * 2 + 1))
|
|
100
|
+
if high < 0 || low < 0 {
|
|
101
|
+
return nil
|
|
102
|
+
}
|
|
103
|
+
bytes[i] = UInt8((high << 4) | low)
|
|
104
|
+
}
|
|
105
|
+
return Data(bytes)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: - JS params cleaning
|
|
109
|
+
|
|
110
|
+
@objc(cleanJavascriptParams:)
|
|
111
|
+
public static func cleanJavascriptParams(_ params: NSDictionary?) -> NSDictionary? {
|
|
112
|
+
guard let params else {
|
|
113
|
+
return nil
|
|
114
|
+
}
|
|
115
|
+
let newParams = NSMutableDictionary(dictionary: params)
|
|
116
|
+
|
|
117
|
+
if newParams[parameterItems] != nil {
|
|
118
|
+
let newItems = NSMutableArray()
|
|
119
|
+
let items = newParams[parameterItems] as! NSArray
|
|
120
|
+
items.enumerateObjects { obj, _, _ in
|
|
121
|
+
let item = (obj as AnyObject).mutableCopy() as! NSMutableDictionary
|
|
122
|
+
coerceLongNumericParameters(in: item)
|
|
123
|
+
newItems.add(item.copy())
|
|
124
|
+
}
|
|
125
|
+
newParams[parameterItems] = newItems.copy()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
coerceLongNumericParameters(in: newParams)
|
|
129
|
+
coerceSuccessParameter(in: newParams)
|
|
130
|
+
|
|
131
|
+
if let extendSession = newParams.value(forKey: parameterExtendSession) as? NSNumber,
|
|
132
|
+
extendSession.isEqual(to: NSNumber(value: 1))
|
|
133
|
+
{
|
|
134
|
+
newParams[parameterExtendSession] = NSNumber(value: true)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return newParams.copy() as? NSDictionary
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private static func coerceLongNumericParameters(in dict: NSMutableDictionary) {
|
|
141
|
+
for key in longNumericParameterKeys {
|
|
142
|
+
guard let value = dict[key], !(value is NSNull) else {
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
// Pre-port: `dict[key] = @([value integerValue]);`
|
|
146
|
+
dict[key] = NSNumber(value: (value as AnyObject).integerValue)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private static func coerceSuccessParameter(in dict: NSMutableDictionary) {
|
|
151
|
+
guard let value = dict[parameterSuccess], !(value is NSNull) else {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
var success = 0
|
|
156
|
+
if let string = value as? String {
|
|
157
|
+
let lower = string.lowercased()
|
|
158
|
+
if lower == "true" || lower == "yes" || lower == "1" {
|
|
159
|
+
success = 1
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
// Pre-port: `success = [value boolValue] ? 1 : 0;`
|
|
163
|
+
success = (value as AnyObject).boolValue ? 1 : 0
|
|
164
|
+
}
|
|
165
|
+
dict[parameterSuccess] = NSNumber(value: success)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -51,12 +51,12 @@ import StoreKit
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
var foundTransaction: StoreKit.Transaction?
|
|
54
|
-
for await result in StoreKit.Transaction.all {
|
|
54
|
+
transactionSearch: for await result in StoreKit.Transaction.all {
|
|
55
55
|
switch result {
|
|
56
56
|
case let .verified(transaction):
|
|
57
57
|
if transaction.id == id {
|
|
58
58
|
foundTransaction = transaction
|
|
59
|
-
break
|
|
59
|
+
break transactionSearch
|
|
60
60
|
}
|
|
61
61
|
case .unverified:
|
|
62
62
|
continue
|
|
@@ -15,48 +15,14 @@
|
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@import FirebaseCore;
|
|
25
|
-
@import FirebaseAnalytics;
|
|
26
|
-
#endif
|
|
27
|
-
#import <React/RCTUtils.h>
|
|
28
|
-
|
|
29
|
-
#if __has_include(<RNFBAnalytics/RNFBAnalytics-Swift.h>)
|
|
30
|
-
// This import will work in situations where `use_frameworks!` is in use
|
|
31
|
-
#import <RNFBAnalytics/RNFBAnalytics-Swift.h>
|
|
32
|
-
#elif __has_include("RNFBAnalytics-Swift.h")
|
|
33
|
-
// If `use_frameworks!` is not in use (for example, while using pre-built
|
|
34
|
-
// react-native core) then header imports based on frameworks assumptions fail.
|
|
35
|
-
// So, if frameworks are not available, fall back to importing the header directly, it
|
|
36
|
-
// should be findable from a header search path pointing to the build
|
|
37
|
-
// directory. See firebase-ios-sdk#12611 for more context.
|
|
38
|
-
#import "RNFBAnalytics-Swift.h"
|
|
39
|
-
#endif
|
|
40
|
-
#import <RNFBApp/RNFBSharedUtils.h>
|
|
18
|
+
// This module intentionally has no Firebase imports and no `*-Swift.h` —
|
|
19
|
+
// see RNFBAnalyticsHelper.h. Every Firebase Analytics SDK call (and the
|
|
20
|
+
// Swift param cleaner / consent mapper / log-transaction types) is routed
|
|
21
|
+
// through the plain Objective-C RNFBAnalyticsHelper class instead, which
|
|
22
|
+
// can safely `@import` FirebaseAnalytics / import the generated Swift
|
|
23
|
+
// interface because it compiles as ObjC, not ObjC++.
|
|
41
24
|
#import "RNFBAnalyticsModule.h"
|
|
42
|
-
|
|
43
|
-
/** GA4 parameters that must be sent as integer NSNumber values (not doubles from JS). */
|
|
44
|
-
static NSArray<NSString *> *RNFBAnalyticsLongNumericParameterKeys(void) {
|
|
45
|
-
static NSArray<NSString *> *keys;
|
|
46
|
-
static dispatch_once_t onceToken;
|
|
47
|
-
dispatch_once(&onceToken, ^{
|
|
48
|
-
keys = @[
|
|
49
|
-
kFIRParameterQuantity,
|
|
50
|
-
kFIRParameterIndex,
|
|
51
|
-
kFIRParameterLevel,
|
|
52
|
-
kFIRParameterNumberOfNights,
|
|
53
|
-
kFIRParameterNumberOfPassengers,
|
|
54
|
-
kFIRParameterNumberOfRooms,
|
|
55
|
-
kFIRParameterScore,
|
|
56
|
-
];
|
|
57
|
-
});
|
|
58
|
-
return keys;
|
|
59
|
-
}
|
|
25
|
+
#import "RNFBAnalyticsHelper.h"
|
|
60
26
|
|
|
61
27
|
@implementation RNFBAnalyticsModule
|
|
62
28
|
#pragma mark -
|
|
@@ -80,286 +46,101 @@ RCT_EXPORT_MODULE(NativeRNFBTurboAnalytics)
|
|
|
80
46
|
params:(NSDictionary *)params
|
|
81
47
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
82
48
|
reject:(RCTPromiseRejectBlock)reject {
|
|
83
|
-
|
|
84
|
-
[FIRAnalytics logEventWithName:name parameters:[self cleanJavascriptParams:params]];
|
|
85
|
-
} @catch (NSException *exception) {
|
|
86
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return resolve([NSNull null]);
|
|
49
|
+
[RNFBAnalyticsHelper logEvent:name params:params resolve:resolve reject:reject];
|
|
90
50
|
}
|
|
91
51
|
|
|
92
52
|
- (void)setAnalyticsCollectionEnabled:(BOOL)enabled
|
|
93
53
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
94
54
|
reject:(RCTPromiseRejectBlock)reject {
|
|
95
|
-
|
|
96
|
-
[FIRAnalytics setAnalyticsCollectionEnabled:enabled];
|
|
97
|
-
} @catch (NSException *exception) {
|
|
98
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return resolve([NSNull null]);
|
|
55
|
+
[RNFBAnalyticsHelper setAnalyticsCollectionEnabled:enabled resolve:resolve reject:reject];
|
|
102
56
|
}
|
|
103
57
|
|
|
104
58
|
- (void)setUserId:(NSString *)id
|
|
105
59
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
106
60
|
reject:(RCTPromiseRejectBlock)reject {
|
|
107
|
-
|
|
108
|
-
[FIRAnalytics setUserID:[self convertNSNullToNil:id]];
|
|
109
|
-
} @catch (NSException *exception) {
|
|
110
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
111
|
-
}
|
|
112
|
-
return resolve([NSNull null]);
|
|
61
|
+
[RNFBAnalyticsHelper setUserId:id resolve:resolve reject:reject];
|
|
113
62
|
}
|
|
114
63
|
|
|
115
64
|
- (void)setUserProperty:(NSString *)name
|
|
116
65
|
value:(NSString *)value
|
|
117
66
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
118
67
|
reject:(RCTPromiseRejectBlock)reject {
|
|
119
|
-
|
|
120
|
-
[FIRAnalytics setUserPropertyString:[self convertNSNullToNil:value] forName:name];
|
|
121
|
-
} @catch (NSException *exception) {
|
|
122
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
123
|
-
}
|
|
124
|
-
return resolve([NSNull null]);
|
|
68
|
+
[RNFBAnalyticsHelper setUserProperty:name value:value resolve:resolve reject:reject];
|
|
125
69
|
}
|
|
126
70
|
|
|
127
71
|
- (void)setUserProperties:(NSDictionary *)properties
|
|
128
72
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
129
73
|
reject:(RCTPromiseRejectBlock)reject {
|
|
130
|
-
|
|
131
|
-
[properties enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
|
|
132
|
-
[FIRAnalytics setUserPropertyString:[self convertNSNullToNil:value] forName:key];
|
|
133
|
-
}];
|
|
134
|
-
} @catch (NSException *exception) {
|
|
135
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
136
|
-
}
|
|
137
|
-
return resolve([NSNull null]);
|
|
74
|
+
[RNFBAnalyticsHelper setUserProperties:properties resolve:resolve reject:reject];
|
|
138
75
|
}
|
|
139
76
|
|
|
140
77
|
- (void)resetAnalyticsData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
141
|
-
|
|
142
|
-
[FIRAnalytics resetAnalyticsData];
|
|
143
|
-
} @catch (NSException *exception) {
|
|
144
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
145
|
-
}
|
|
146
|
-
return resolve([NSNull null]);
|
|
78
|
+
[RNFBAnalyticsHelper resetAnalyticsData:resolve reject:reject];
|
|
147
79
|
}
|
|
148
80
|
|
|
149
81
|
- (void)setSessionTimeoutDuration:(double)milliseconds
|
|
150
82
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
151
83
|
reject:(RCTPromiseRejectBlock)reject {
|
|
152
|
-
[
|
|
153
|
-
return resolve([NSNull null]);
|
|
84
|
+
[RNFBAnalyticsHelper setSessionTimeoutDuration:milliseconds resolve:resolve reject:reject];
|
|
154
85
|
}
|
|
155
86
|
|
|
156
87
|
- (void)getAppInstanceId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
157
|
-
|
|
88
|
+
[RNFBAnalyticsHelper getAppInstanceId:resolve reject:reject];
|
|
158
89
|
}
|
|
159
90
|
|
|
160
91
|
- (void)getSessionId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
161
|
-
|
|
162
|
-
const int64_t timeoutNs = (int64_t)(60 * NSEC_PER_SEC);
|
|
163
|
-
|
|
164
|
-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeoutNs), dispatch_get_main_queue(), ^{
|
|
165
|
-
if (completed) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
completed = YES;
|
|
169
|
-
DLog(@"getSessionId timed_out: no SDK callback within 60 seconds");
|
|
170
|
-
resolve([NSNull null]);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
[FIRAnalytics sessionIDWithCompletion:^(int64_t sessionID, NSError *_Nullable error) {
|
|
174
|
-
if (completed) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
completed = YES;
|
|
178
|
-
|
|
179
|
-
// Occasionally sessionID is 0 despite nil error, reject as if it were an error
|
|
180
|
-
// https://github.com/firebase/firebase-ios-sdk/issues/15258
|
|
181
|
-
if (!error && [NSNumber numberWithLongLong:sessionID] == 0) {
|
|
182
|
-
DLog(@"getSessionId zero_without_error: sessionID=0 (firebase-ios-sdk#15258)");
|
|
183
|
-
return resolve([NSNull null]);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (error) {
|
|
187
|
-
DLog(@"getSessionId sdk_error: domain=%@ code=%ld description=%@", error.domain,
|
|
188
|
-
(long)error.code, error.localizedDescription ?: @"(none)");
|
|
189
|
-
return resolve([NSNull null]);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
DLog(@"getSessionId success: sessionID=%lld", sessionID);
|
|
193
|
-
return resolve([NSNumber numberWithLongLong:sessionID]);
|
|
194
|
-
}];
|
|
92
|
+
[RNFBAnalyticsHelper getSessionId:resolve reject:reject];
|
|
195
93
|
}
|
|
196
94
|
|
|
197
95
|
- (void)setDefaultEventParameters:(NSDictionary *)params
|
|
198
96
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
199
97
|
reject:(RCTPromiseRejectBlock)reject {
|
|
200
|
-
|
|
201
|
-
[FIRAnalytics setDefaultEventParameters:[self cleanJavascriptParams:params]];
|
|
202
|
-
} @catch (NSException *exception) {
|
|
203
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return resolve([NSNull null]);
|
|
98
|
+
[RNFBAnalyticsHelper setDefaultEventParameters:params resolve:resolve reject:reject];
|
|
207
99
|
}
|
|
208
100
|
|
|
209
101
|
- (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress
|
|
210
102
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
211
103
|
reject:(RCTPromiseRejectBlock)reject {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return resolve([NSNull null]);
|
|
104
|
+
[RNFBAnalyticsHelper initiateOnDeviceConversionMeasurementWithEmailAddress:emailAddress
|
|
105
|
+
resolve:resolve
|
|
106
|
+
reject:reject];
|
|
219
107
|
}
|
|
220
108
|
|
|
221
109
|
- (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSString *)hashedEmailAddress
|
|
222
110
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
223
111
|
reject:(RCTPromiseRejectBlock)reject {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return resolve([NSNull null]);
|
|
112
|
+
[RNFBAnalyticsHelper
|
|
113
|
+
initiateOnDeviceConversionMeasurementWithHashedEmailAddress:hashedEmailAddress
|
|
114
|
+
resolve:resolve
|
|
115
|
+
reject:reject];
|
|
232
116
|
}
|
|
233
117
|
|
|
234
118
|
- (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber
|
|
235
119
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
236
120
|
reject:(RCTPromiseRejectBlock)reject {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return resolve([NSNull null]);
|
|
121
|
+
[RNFBAnalyticsHelper initiateOnDeviceConversionMeasurementWithPhoneNumber:phoneNumber
|
|
122
|
+
resolve:resolve
|
|
123
|
+
reject:reject];
|
|
244
124
|
}
|
|
245
125
|
|
|
246
126
|
- (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSString *)hashedPhoneNumber
|
|
247
127
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
248
128
|
reject:(RCTPromiseRejectBlock)reject {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
} @catch (NSException *exception) {
|
|
253
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return resolve([NSNull null]);
|
|
129
|
+
[RNFBAnalyticsHelper initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:hashedPhoneNumber
|
|
130
|
+
resolve:resolve
|
|
131
|
+
reject:reject];
|
|
257
132
|
}
|
|
258
133
|
|
|
259
134
|
- (void)logTransaction:(NSString *)transactionId
|
|
260
135
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
261
136
|
reject:(RCTPromiseRejectBlock)reject {
|
|
262
|
-
|
|
263
|
-
RNFBAnalyticsLogTransaction *handler = [[RNFBAnalyticsLogTransaction alloc] init];
|
|
264
|
-
[handler logTransactionWithTransactionId:transactionId resolve:resolve reject:reject];
|
|
265
|
-
} else {
|
|
266
|
-
reject(@"firebase_analytics", @"logTransaction() is only supported on iOS 15.0 or newer", nil);
|
|
267
|
-
}
|
|
137
|
+
[RNFBAnalyticsHelper logTransaction:transactionId resolve:resolve reject:reject];
|
|
268
138
|
}
|
|
269
139
|
|
|
270
140
|
- (void)setConsent:(NSDictionary *)consentSettings
|
|
271
141
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
272
142
|
reject:(RCTPromiseRejectBlock)reject {
|
|
273
|
-
|
|
274
|
-
BOOL analyticsStorage = [consentSettings[@"analytics_storage"] boolValue];
|
|
275
|
-
BOOL adStorage = [consentSettings[@"ad_storage"] boolValue];
|
|
276
|
-
BOOL adUserData = [consentSettings[@"ad_user_data"] boolValue];
|
|
277
|
-
BOOL adPersonalization = [consentSettings[@"ad_personalization"] boolValue];
|
|
278
|
-
[FIRAnalytics setConsent:@{
|
|
279
|
-
FIRConsentTypeAnalyticsStorage : analyticsStorage ? FIRConsentStatusGranted
|
|
280
|
-
: FIRConsentStatusDenied,
|
|
281
|
-
FIRConsentTypeAdStorage : adStorage ? FIRConsentStatusGranted : FIRConsentStatusDenied,
|
|
282
|
-
FIRConsentTypeAdUserData : adUserData ? FIRConsentStatusGranted : FIRConsentStatusDenied,
|
|
283
|
-
FIRConsentTypeAdPersonalization : adPersonalization ? FIRConsentStatusGranted
|
|
284
|
-
: FIRConsentStatusDenied,
|
|
285
|
-
}];
|
|
286
|
-
} @catch (NSException *exception) {
|
|
287
|
-
return [RNFBSharedUtils rejectPromiseWithExceptionDict:reject exception:exception];
|
|
288
|
-
}
|
|
289
|
-
return resolve([NSNull null]);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
#pragma mark -
|
|
293
|
-
#pragma mark Private methods
|
|
294
|
-
|
|
295
|
-
- (NSDictionary *)cleanJavascriptParams:(NSDictionary *)params {
|
|
296
|
-
NSMutableDictionary *newParams = [params mutableCopy];
|
|
297
|
-
if (newParams[kFIRParameterItems]) {
|
|
298
|
-
NSMutableArray *newItems = [NSMutableArray array];
|
|
299
|
-
[(NSArray *)newParams[kFIRParameterItems]
|
|
300
|
-
enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
|
|
301
|
-
NSMutableDictionary *item = [obj mutableCopy];
|
|
302
|
-
[self rnfb_coerceLongNumericParametersInMutableDictionary:item];
|
|
303
|
-
[newItems addObject:[item copy]];
|
|
304
|
-
}];
|
|
305
|
-
newParams[kFIRParameterItems] = [newItems copy];
|
|
306
|
-
}
|
|
307
|
-
[self rnfb_coerceLongNumericParametersInMutableDictionary:newParams];
|
|
308
|
-
[self rnfb_coerceSuccessParameterInMutableDictionary:newParams];
|
|
309
|
-
NSNumber *extendSession = [newParams valueForKey:kFIRParameterExtendSession];
|
|
310
|
-
if ([extendSession isEqualToNumber:@1]) {
|
|
311
|
-
newParams[kFIRParameterExtendSession] = @YES;
|
|
312
|
-
}
|
|
313
|
-
return [newParams copy];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
- (void)rnfb_coerceLongNumericParametersInMutableDictionary:(NSMutableDictionary *)dict {
|
|
317
|
-
for (NSString *key in RNFBAnalyticsLongNumericParameterKeys()) {
|
|
318
|
-
id value = dict[key];
|
|
319
|
-
if (value != nil && value != [NSNull null]) {
|
|
320
|
-
dict[key] = @([value integerValue]);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
- (void)rnfb_coerceSuccessParameterInMutableDictionary:(NSMutableDictionary *)dict {
|
|
326
|
-
id value = dict[kFIRParameterSuccess];
|
|
327
|
-
if (value == nil || value == [NSNull null]) {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
int success = 0;
|
|
331
|
-
if ([value isKindOfClass:[NSString class]]) {
|
|
332
|
-
NSString *lower = [(NSString *)value lowercaseString];
|
|
333
|
-
if ([lower isEqualToString:@"true"] || [lower isEqualToString:@"yes"] ||
|
|
334
|
-
[lower isEqualToString:@"1"]) {
|
|
335
|
-
success = 1;
|
|
336
|
-
}
|
|
337
|
-
} else {
|
|
338
|
-
success = [value boolValue] ? 1 : 0;
|
|
339
|
-
}
|
|
340
|
-
dict[kFIRParameterSuccess] = @(success);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/// Converts null values received over the bridge from NSNull to nil
|
|
344
|
-
/// @param value Nullable string value
|
|
345
|
-
- (NSString *)convertNSNullToNil:(NSString *)value {
|
|
346
|
-
return [value isEqual:[NSNull null]] ? nil : value;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/// Converts a hex string to NSData
|
|
350
|
-
/// @param hexString A hex string (e.g., SHA256 hash as 64-character hex string)
|
|
351
|
-
/// @return NSData containing the decoded bytes (e.g., 32 bytes for SHA256)
|
|
352
|
-
- (NSData *)dataFromHexString:(NSString *)hexString {
|
|
353
|
-
NSMutableData *data = [NSMutableData dataWithCapacity:hexString.length / 2];
|
|
354
|
-
unsigned char wholeByte;
|
|
355
|
-
char byteChars[3] = {'\0', '\0', '\0'};
|
|
356
|
-
for (NSUInteger i = 0; i < hexString.length; i += 2) {
|
|
357
|
-
byteChars[0] = [hexString characterAtIndex:i];
|
|
358
|
-
byteChars[1] = [hexString characterAtIndex:i + 1];
|
|
359
|
-
wholeByte = strtol(byteChars, NULL, 16);
|
|
360
|
-
[data appendBytes:&wholeByte length:1];
|
|
361
|
-
}
|
|
362
|
-
return data;
|
|
143
|
+
[RNFBAnalyticsHelper setConsent:consentSettings resolve:resolve reject:reject];
|
|
363
144
|
}
|
|
364
145
|
|
|
365
146
|
@end
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
/* Begin PBXBuildFile section */
|
|
10
10
|
2744B98621F45429004F8E3F /* RNFBAnalyticsModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAnalyticsModule.mm */; };
|
|
11
11
|
2744B99021F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */; };
|
|
12
|
+
2744B99121F45429004F8E3F /* RNFBAnalyticsJavascriptParamsCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2744B99221F45429004F8E3F /* RNFBAnalyticsJavascriptParamsCleaner.swift */; };
|
|
13
|
+
2744B99321F45429004F8E3F /* RNFBAnalyticsConsentSettingsMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2744B99421F45429004F8E3F /* RNFBAnalyticsConsentSettingsMapper.swift */; };
|
|
14
|
+
RNFBAN000000000000000006 /* RNFBAnalyticsHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = RNFBAN000000000000000008 /* RNFBAnalyticsHelper.m */; };
|
|
12
15
|
/* End PBXBuildFile section */
|
|
13
16
|
|
|
14
17
|
/* Begin PBXCopyFilesBuildPhase section */
|
|
@@ -28,6 +31,10 @@
|
|
|
28
31
|
2744B98421F45429004F8E3F /* RNFBAnalyticsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAnalyticsModule.h; path = RNFBAnalytics/RNFBAnalyticsModule.h; sourceTree = SOURCE_ROOT; };
|
|
29
32
|
2744B98521F45429004F8E3F /* RNFBAnalyticsModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = RNFBAnalyticsModule.mm; path = RNFBAnalytics/RNFBAnalyticsModule.mm; sourceTree = SOURCE_ROOT; };
|
|
30
33
|
2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAnalyticsLogTransaction.swift; path = RNFBAnalytics/RNFBAnalyticsLogTransaction.swift; sourceTree = SOURCE_ROOT; };
|
|
34
|
+
2744B99221F45429004F8E3F /* RNFBAnalyticsJavascriptParamsCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAnalyticsJavascriptParamsCleaner.swift; path = RNFBAnalytics/RNFBAnalyticsJavascriptParamsCleaner.swift; sourceTree = SOURCE_ROOT; };
|
|
35
|
+
2744B99421F45429004F8E3F /* RNFBAnalyticsConsentSettingsMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBAnalyticsConsentSettingsMapper.swift; path = RNFBAnalytics/RNFBAnalyticsConsentSettingsMapper.swift; sourceTree = SOURCE_ROOT; };
|
|
36
|
+
RNFBAN000000000000000007 /* RNFBAnalyticsHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAnalyticsHelper.h; path = RNFBAnalytics/RNFBAnalyticsHelper.h; sourceTree = SOURCE_ROOT; };
|
|
37
|
+
RNFBAN000000000000000008 /* RNFBAnalyticsHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAnalyticsHelper.m; path = RNFBAnalytics/RNFBAnalyticsHelper.m; sourceTree = SOURCE_ROOT; };
|
|
31
38
|
/* End PBXFileReference section */
|
|
32
39
|
|
|
33
40
|
/* Begin PBXFrameworksBuildPhase section */
|
|
@@ -56,7 +63,11 @@
|
|
|
56
63
|
2744B98C21F45C64004F8E3F /* common */,
|
|
57
64
|
2744B98421F45429004F8E3F /* RNFBAnalyticsModule.h */,
|
|
58
65
|
2744B98521F45429004F8E3F /* RNFBAnalyticsModule.mm */,
|
|
66
|
+
RNFBAN000000000000000007 /* RNFBAnalyticsHelper.h */,
|
|
67
|
+
RNFBAN000000000000000008 /* RNFBAnalyticsHelper.m */,
|
|
59
68
|
2744B98F21F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift */,
|
|
69
|
+
2744B99221F45429004F8E3F /* RNFBAnalyticsJavascriptParamsCleaner.swift */,
|
|
70
|
+
2744B99421F45429004F8E3F /* RNFBAnalyticsConsentSettingsMapper.swift */,
|
|
60
71
|
);
|
|
61
72
|
path = RNFBAnalytics;
|
|
62
73
|
sourceTree = "<group>";
|
|
@@ -128,7 +139,10 @@
|
|
|
128
139
|
buildActionMask = 2147483647;
|
|
129
140
|
files = (
|
|
130
141
|
2744B98621F45429004F8E3F /* RNFBAnalyticsModule.mm in Sources */,
|
|
142
|
+
RNFBAN000000000000000006 /* RNFBAnalyticsHelper.m in Sources */,
|
|
131
143
|
2744B99021F45429004F8E3F /* RNFBAnalyticsLogTransaction.swift in Sources */,
|
|
144
|
+
2744B99121F45429004F8E3F /* RNFBAnalyticsJavascriptParamsCleaner.swift in Sources */,
|
|
145
|
+
2744B99321F45429004F8E3F /* RNFBAnalyticsConsentSettingsMapper.swift in Sources */,
|
|
132
146
|
);
|
|
133
147
|
runOnlyForDeploymentPostprocessing = 0;
|
|
134
148
|
};
|
|
@@ -170,7 +184,7 @@
|
|
|
170
184
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
171
185
|
SDKROOT = iphoneos;
|
|
172
186
|
SKIP_INSTALL = YES;
|
|
173
|
-
SWIFT_VERSION = 5.
|
|
187
|
+
SWIFT_VERSION = 5.10;
|
|
174
188
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
175
189
|
};
|
|
176
190
|
name = Debug;
|
|
@@ -205,7 +219,7 @@
|
|
|
205
219
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
206
220
|
SDKROOT = iphoneos;
|
|
207
221
|
SKIP_INSTALL = YES;
|
|
208
|
-
SWIFT_VERSION = 5.
|
|
222
|
+
SWIFT_VERSION = 5.10;
|
|
209
223
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
210
224
|
VALIDATE_PRODUCT = YES;
|
|
211
225
|
};
|