@datalyr/react-native 1.4.6 → 1.4.8
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.
|
@@ -4,40 +4,45 @@ import TikTokBusinessSDK
|
|
|
4
4
|
import AdServices
|
|
5
5
|
|
|
6
6
|
public class DatalyrNativeModule: Module {
|
|
7
|
+
private var tiktokInitialized = false
|
|
8
|
+
private var metaInitialized = false
|
|
9
|
+
|
|
7
10
|
public func definition() -> ModuleDefinition {
|
|
8
11
|
Name("DatalyrNative")
|
|
9
12
|
|
|
10
13
|
// MARK: - Meta (Facebook) SDK Methods
|
|
11
14
|
|
|
12
15
|
AsyncFunction("initializeMetaSDK") { (appId: String, clientToken: String?, advertiserTrackingEnabled: Bool, promise: Promise) in
|
|
13
|
-
DispatchQueue.main.async {
|
|
14
|
-
|
|
15
|
-
Settings.shared.appID = appId
|
|
16
|
+
DispatchQueue.main.async { [weak self] in
|
|
17
|
+
Settings.shared.appID = appId
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
if let token = clientToken, !token.isEmpty {
|
|
20
|
+
Settings.shared.clientToken = token
|
|
21
|
+
}
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
Settings.shared.isAdvertiserTrackingEnabled = advertiserTrackingEnabled
|
|
24
|
+
Settings.shared.isAdvertiserIDCollectionEnabled = advertiserTrackingEnabled
|
|
23
25
|
|
|
26
|
+
var initError: NSError?
|
|
27
|
+
let success = DatalyrObjCExceptionCatcher.tryBlock({
|
|
24
28
|
ApplicationDelegate.shared.application(
|
|
25
29
|
UIApplication.shared,
|
|
26
30
|
didFinishLaunchingWithOptions: nil
|
|
27
31
|
)
|
|
28
|
-
}
|
|
32
|
+
}, error: &initError)
|
|
29
33
|
|
|
30
|
-
if
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
if success {
|
|
35
|
+
self?.metaInitialized = true
|
|
36
|
+
promise.resolve(true)
|
|
37
|
+
} else {
|
|
38
|
+
let message = initError?.localizedDescription ?? "Unknown ObjC exception during Meta SDK init"
|
|
39
|
+
promise.reject("meta_init_error", message)
|
|
33
40
|
}
|
|
34
|
-
|
|
35
|
-
promise.resolve(true)
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
AsyncFunction("fetchDeferredAppLink") { (promise: Promise) in
|
|
40
|
-
|
|
45
|
+
DispatchQueue.main.async {
|
|
41
46
|
AppLinkUtility.fetchDeferredAppLink { url, error in
|
|
42
47
|
if error != nil {
|
|
43
48
|
promise.resolve(nil)
|
|
@@ -51,120 +56,128 @@ public class DatalyrNativeModule: Module {
|
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
|
-
|
|
55
|
-
if error != nil {
|
|
56
|
-
promise.resolve(nil)
|
|
57
|
-
}
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
AsyncFunction("logMetaEvent") { (eventName: String, valueToSum: Double?, parameters: [String: Any]?, promise: Promise) in
|
|
61
|
-
|
|
62
|
+
guard self.metaInitialized else {
|
|
63
|
+
promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
DispatchQueue.main.async {
|
|
68
|
+
var params: [AppEvents.ParameterName: Any] = [:]
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
if let dict = parameters {
|
|
71
|
+
for (key, value) in dict {
|
|
72
|
+
params[AppEvents.ParameterName(key)] = value
|
|
73
|
+
}
|
|
66
74
|
}
|
|
67
|
-
}
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
var logError: NSError?
|
|
77
|
+
DatalyrObjCExceptionCatcher.tryBlock({
|
|
78
|
+
if let value = valueToSum {
|
|
79
|
+
AppEvents.shared.logEvent(AppEvents.Name(eventName), valueToSum: value, parameters: params)
|
|
80
|
+
} else if params.isEmpty {
|
|
81
|
+
AppEvents.shared.logEvent(AppEvents.Name(eventName))
|
|
82
|
+
} else {
|
|
83
|
+
AppEvents.shared.logEvent(AppEvents.Name(eventName), parameters: params)
|
|
84
|
+
}
|
|
85
|
+
}, error: &logError)
|
|
86
|
+
|
|
87
|
+
if let logError = logError {
|
|
88
|
+
promise.reject("meta_event_error", logError.localizedDescription)
|
|
74
89
|
} else {
|
|
75
|
-
|
|
90
|
+
promise.resolve(true)
|
|
76
91
|
}
|
|
77
92
|
}
|
|
93
|
+
}
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
AsyncFunction("logMetaPurchase") { (amount: Double, currency: String, parameters: [String: Any]?, promise: Promise) in
|
|
96
|
+
guard self.metaInitialized else {
|
|
97
|
+
promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
|
|
81
98
|
return
|
|
82
99
|
}
|
|
83
100
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
AsyncFunction("logMetaPurchase") { (amount: Double, currency: String, parameters: [String: Any]?, promise: Promise) in
|
|
88
|
-
var params: [AppEvents.ParameterName: Any] = [:]
|
|
101
|
+
DispatchQueue.main.async {
|
|
102
|
+
var params: [AppEvents.ParameterName: Any] = [:]
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
if let dict = parameters {
|
|
105
|
+
for (key, value) in dict {
|
|
106
|
+
params[AppEvents.ParameterName(key)] = value
|
|
107
|
+
}
|
|
93
108
|
}
|
|
94
|
-
}
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
var logError: NSError?
|
|
111
|
+
DatalyrObjCExceptionCatcher.tryBlock({
|
|
112
|
+
AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: params)
|
|
113
|
+
}, error: &logError)
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
if let logError = logError {
|
|
116
|
+
promise.reject("meta_event_error", logError.localizedDescription)
|
|
117
|
+
} else {
|
|
118
|
+
promise.resolve(true)
|
|
119
|
+
}
|
|
103
120
|
}
|
|
104
|
-
|
|
105
|
-
promise.resolve(true)
|
|
106
121
|
}
|
|
107
122
|
|
|
108
123
|
AsyncFunction("setMetaUserData") { (userData: [String: Any], promise: Promise) in
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
AppEvents.shared.setUserData(userData["firstName"] as? String, forType: .firstName)
|
|
112
|
-
AppEvents.shared.setUserData(userData["lastName"] as? String, forType: .lastName)
|
|
113
|
-
AppEvents.shared.setUserData(userData["phone"] as? String, forType: .phone)
|
|
114
|
-
AppEvents.shared.setUserData(userData["dateOfBirth"] as? String, forType: .dateOfBirth)
|
|
115
|
-
AppEvents.shared.setUserData(userData["gender"] as? String, forType: .gender)
|
|
116
|
-
AppEvents.shared.setUserData(userData["city"] as? String, forType: .city)
|
|
117
|
-
AppEvents.shared.setUserData(userData["state"] as? String, forType: .state)
|
|
118
|
-
AppEvents.shared.setUserData(userData["zip"] as? String, forType: .zip)
|
|
119
|
-
AppEvents.shared.setUserData(userData["country"] as? String, forType: .country)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if let error = error {
|
|
123
|
-
promise.reject("meta_exception", error.localizedDescription)
|
|
124
|
+
guard self.metaInitialized else {
|
|
125
|
+
promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
|
|
124
126
|
return
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
DispatchQueue.main.async {
|
|
130
|
+
if let email = userData["email"] as? String { AppEvents.shared.setUserData(email, forType: .email) }
|
|
131
|
+
if let firstName = userData["firstName"] as? String { AppEvents.shared.setUserData(firstName, forType: .firstName) }
|
|
132
|
+
if let lastName = userData["lastName"] as? String { AppEvents.shared.setUserData(lastName, forType: .lastName) }
|
|
133
|
+
if let phone = userData["phone"] as? String { AppEvents.shared.setUserData(phone, forType: .phone) }
|
|
134
|
+
if let dateOfBirth = userData["dateOfBirth"] as? String { AppEvents.shared.setUserData(dateOfBirth, forType: .dateOfBirth) }
|
|
135
|
+
if let gender = userData["gender"] as? String { AppEvents.shared.setUserData(gender, forType: .gender) }
|
|
136
|
+
if let city = userData["city"] as? String { AppEvents.shared.setUserData(city, forType: .city) }
|
|
137
|
+
if let state = userData["state"] as? String { AppEvents.shared.setUserData(state, forType: .state) }
|
|
138
|
+
if let zip = userData["zip"] as? String { AppEvents.shared.setUserData(zip, forType: .zip) }
|
|
139
|
+
if let country = userData["country"] as? String { AppEvents.shared.setUserData(country, forType: .country) }
|
|
129
140
|
|
|
130
|
-
|
|
131
|
-
let error = ObjCExceptionHelper.execute {
|
|
132
|
-
AppEvents.shared.clearUserData()
|
|
141
|
+
promise.resolve(true)
|
|
133
142
|
}
|
|
143
|
+
}
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
|
|
145
|
+
AsyncFunction("clearMetaUserData") { (promise: Promise) in
|
|
146
|
+
guard self.metaInitialized else {
|
|
147
|
+
promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
|
|
137
148
|
return
|
|
138
149
|
}
|
|
139
150
|
|
|
140
|
-
|
|
151
|
+
DispatchQueue.main.async {
|
|
152
|
+
AppEvents.shared.clearUserData()
|
|
153
|
+
promise.resolve(true)
|
|
154
|
+
}
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
AsyncFunction("updateMetaTrackingAuthorization") { (enabled: Bool, promise: Promise) in
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
Settings.shared.isAdvertiserIDCollectionEnabled = enabled
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if let error = error {
|
|
150
|
-
promise.reject("meta_exception", error.localizedDescription)
|
|
158
|
+
guard self.metaInitialized else {
|
|
159
|
+
promise.reject("meta_not_initialized", "Meta SDK not initialized. Call initializeMetaSDK first.")
|
|
151
160
|
return
|
|
152
161
|
}
|
|
153
162
|
|
|
154
|
-
|
|
163
|
+
DispatchQueue.main.async {
|
|
164
|
+
Settings.shared.isAdvertiserTrackingEnabled = enabled
|
|
165
|
+
Settings.shared.isAdvertiserIDCollectionEnabled = enabled
|
|
166
|
+
promise.resolve(true)
|
|
167
|
+
}
|
|
155
168
|
}
|
|
156
169
|
|
|
157
170
|
// MARK: - TikTok SDK Methods
|
|
158
171
|
|
|
159
172
|
AsyncFunction("initializeTikTokSDK") { (appId: String, tiktokAppId: String, accessToken: String?, debug: Bool, promise: Promise) in
|
|
160
|
-
DispatchQueue.main.async {
|
|
161
|
-
let
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
} else {
|
|
165
|
-
config = TikTokConfig(appId: appId, tiktokAppId: tiktokAppId)
|
|
173
|
+
DispatchQueue.main.async { [weak self] in
|
|
174
|
+
guard let token = accessToken, !token.isEmpty else {
|
|
175
|
+
promise.reject("tiktok_init_error", "TikTok accessToken is required. The deprecated init without accessToken has been removed.")
|
|
176
|
+
return
|
|
166
177
|
}
|
|
167
178
|
|
|
179
|
+
let config = TikTokConfig(accessToken: token, appId: appId, tiktokAppId: tiktokAppId)
|
|
180
|
+
|
|
168
181
|
if debug {
|
|
169
182
|
config?.setLogLevel(TikTokLogLevelDebug)
|
|
170
183
|
}
|
|
@@ -174,21 +187,28 @@ public class DatalyrNativeModule: Module {
|
|
|
174
187
|
return
|
|
175
188
|
}
|
|
176
189
|
|
|
177
|
-
|
|
190
|
+
var initError: NSError?
|
|
191
|
+
let success = DatalyrObjCExceptionCatcher.tryBlock({
|
|
178
192
|
TikTokBusiness.initializeSdk(validConfig)
|
|
179
|
-
}
|
|
193
|
+
}, error: &initError)
|
|
180
194
|
|
|
181
|
-
if
|
|
182
|
-
|
|
183
|
-
|
|
195
|
+
if success {
|
|
196
|
+
self?.tiktokInitialized = true
|
|
197
|
+
promise.resolve(true)
|
|
198
|
+
} else {
|
|
199
|
+
let message = initError?.localizedDescription ?? "Unknown ObjC exception during TikTok SDK init"
|
|
200
|
+
promise.reject("tiktok_init_error", message)
|
|
184
201
|
}
|
|
185
|
-
|
|
186
|
-
promise.resolve(true)
|
|
187
202
|
}
|
|
188
203
|
}
|
|
189
204
|
|
|
190
205
|
AsyncFunction("trackTikTokEvent") { (eventName: String, eventId: String?, properties: [String: Any]?, promise: Promise) in
|
|
191
|
-
|
|
206
|
+
guard self.tiktokInitialized else {
|
|
207
|
+
promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
DispatchQueue.main.async {
|
|
192
212
|
let event: TikTokBaseEvent
|
|
193
213
|
|
|
194
214
|
if let eid = eventId, !eid.isEmpty {
|
|
@@ -203,46 +223,46 @@ public class DatalyrNativeModule: Module {
|
|
|
203
223
|
}
|
|
204
224
|
}
|
|
205
225
|
|
|
206
|
-
|
|
207
|
-
|
|
226
|
+
var trackError: NSError?
|
|
227
|
+
DatalyrObjCExceptionCatcher.tryBlock({
|
|
228
|
+
TikTokBusiness.trackTTEvent(event)
|
|
229
|
+
}, error: &trackError)
|
|
208
230
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
231
|
+
if let trackError = trackError {
|
|
232
|
+
promise.reject("tiktok_event_error", trackError.localizedDescription)
|
|
233
|
+
} else {
|
|
234
|
+
promise.resolve(true)
|
|
235
|
+
}
|
|
212
236
|
}
|
|
213
|
-
|
|
214
|
-
promise.resolve(true)
|
|
215
237
|
}
|
|
216
238
|
|
|
217
239
|
AsyncFunction("identifyTikTokUser") { (externalId: String, externalUserName: String, phoneNumber: String, email: String, promise: Promise) in
|
|
218
|
-
|
|
240
|
+
guard self.tiktokInitialized else {
|
|
241
|
+
promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
DispatchQueue.main.async {
|
|
219
246
|
TikTokBusiness.identify(
|
|
220
247
|
withExternalID: externalId.isEmpty ? nil : externalId,
|
|
221
248
|
externalUserName: externalUserName.isEmpty ? nil : externalUserName,
|
|
222
249
|
phoneNumber: phoneNumber.isEmpty ? nil : phoneNumber,
|
|
223
250
|
email: email.isEmpty ? nil : email
|
|
224
251
|
)
|
|
252
|
+
promise.resolve(true)
|
|
225
253
|
}
|
|
226
|
-
|
|
227
|
-
if let error = error {
|
|
228
|
-
promise.reject("tiktok_exception", error.localizedDescription)
|
|
229
|
-
return
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
promise.resolve(true)
|
|
233
254
|
}
|
|
234
255
|
|
|
235
256
|
AsyncFunction("logoutTikTok") { (promise: Promise) in
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if let error = error {
|
|
241
|
-
promise.reject("tiktok_exception", error.localizedDescription)
|
|
257
|
+
guard self.tiktokInitialized else {
|
|
258
|
+
promise.reject("tiktok_not_initialized", "TikTok SDK not initialized. Call initializeTikTokSDK first.")
|
|
242
259
|
return
|
|
243
260
|
}
|
|
244
261
|
|
|
245
|
-
|
|
262
|
+
DispatchQueue.main.async {
|
|
263
|
+
TikTokBusiness.logout()
|
|
264
|
+
promise.resolve(true)
|
|
265
|
+
}
|
|
246
266
|
}
|
|
247
267
|
|
|
248
268
|
AsyncFunction("updateTikTokTrackingAuthorization") { (enabled: Bool, promise: Promise) in
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
/// Catches ObjC NSExceptions (from Meta/TikTok SDKs) and converts them to NSErrors.
|
|
6
|
+
/// Swift's do/try/catch cannot catch NSExceptions — they propagate through Hermes
|
|
7
|
+
/// and cause EXC_BAD_ACCESS (SIGSEGV) crashes.
|
|
8
|
+
@interface DatalyrObjCExceptionCatcher : NSObject
|
|
9
|
+
|
|
10
|
+
+ (BOOL)tryBlock:(void(NS_NOESCAPE ^)(void))block error:(NSError *_Nullable *_Nullable)error;
|
|
11
|
+
|
|
12
|
+
@end
|
|
13
|
+
|
|
14
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#import "DatalyrObjCExceptionCatcher.h"
|
|
2
|
+
|
|
3
|
+
@implementation DatalyrObjCExceptionCatcher
|
|
4
|
+
|
|
5
|
+
+ (BOOL)tryBlock:(void(NS_NOESCAPE ^)(void))block error:(NSError **)error {
|
|
6
|
+
@try {
|
|
7
|
+
block();
|
|
8
|
+
return YES;
|
|
9
|
+
}
|
|
10
|
+
@catch (NSException *exception) {
|
|
11
|
+
if (error) {
|
|
12
|
+
NSString *description = exception.reason ?: exception.name;
|
|
13
|
+
NSDictionary *userInfo = @{
|
|
14
|
+
NSLocalizedDescriptionKey: description,
|
|
15
|
+
@"ExceptionName": exception.name ?: @"Unknown",
|
|
16
|
+
};
|
|
17
|
+
if (exception.userInfo) {
|
|
18
|
+
NSMutableDictionary *merged = [userInfo mutableCopy];
|
|
19
|
+
[merged addEntriesFromDictionary:exception.userInfo];
|
|
20
|
+
userInfo = merged;
|
|
21
|
+
}
|
|
22
|
+
*error = [NSError errorWithDomain:@"com.datalyr.objc-exception"
|
|
23
|
+
code:-1
|
|
24
|
+
userInfo:userInfo];
|
|
25
|
+
}
|
|
26
|
+
return NO;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalyr/react-native",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.8",
|
|
4
4
|
"description": "Datalyr SDK for React Native & Expo - Server-side attribution tracking with bundled Meta and TikTok SDKs for iOS and Android",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#import "ObjCExceptionHelper.h"
|
|
2
|
-
|
|
3
|
-
@implementation ObjCExceptionHelper
|
|
4
|
-
|
|
5
|
-
+ (nullable NSError *)execute:(void (NS_NOESCAPE ^)(void))block {
|
|
6
|
-
@try {
|
|
7
|
-
block();
|
|
8
|
-
return nil;
|
|
9
|
-
} @catch (NSException *exception) {
|
|
10
|
-
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
|
11
|
-
userInfo[NSLocalizedDescriptionKey] = exception.reason ?: @"Unknown NSException";
|
|
12
|
-
userInfo[@"ExceptionName"] = exception.name;
|
|
13
|
-
if (exception.userInfo) {
|
|
14
|
-
userInfo[@"ExceptionUserInfo"] = exception.userInfo;
|
|
15
|
-
}
|
|
16
|
-
return [NSError errorWithDomain:@"com.datalyr.exception"
|
|
17
|
-
code:-1
|
|
18
|
-
userInfo:userInfo];
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
@end
|