@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
- let error = ObjCExceptionHelper.execute {
15
- Settings.shared.appID = appId
16
+ DispatchQueue.main.async { [weak self] in
17
+ Settings.shared.appID = appId
16
18
 
17
- if let token = clientToken, !token.isEmpty {
18
- Settings.shared.clientToken = token
19
- }
19
+ if let token = clientToken, !token.isEmpty {
20
+ Settings.shared.clientToken = token
21
+ }
20
22
 
21
- Settings.shared.isAdvertiserTrackingEnabled = advertiserTrackingEnabled
22
- Settings.shared.isAdvertiserIDCollectionEnabled = advertiserTrackingEnabled
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 let error = error {
31
- promise.reject("meta_init_exception", error.localizedDescription)
32
- return
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
- let error = ObjCExceptionHelper.execute {
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
- var params: [AppEvents.ParameterName: Any] = [:]
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
- if let dict = parameters {
64
- for (key, value) in dict {
65
- params[AppEvents.ParameterName(key)] = value
70
+ if let dict = parameters {
71
+ for (key, value) in dict {
72
+ params[AppEvents.ParameterName(key)] = value
73
+ }
66
74
  }
67
- }
68
75
 
69
- let error = ObjCExceptionHelper.execute {
70
- if let value = valueToSum {
71
- AppEvents.shared.logEvent(AppEvents.Name(eventName), valueToSum: value, parameters: params)
72
- } else if params.isEmpty {
73
- AppEvents.shared.logEvent(AppEvents.Name(eventName))
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
- AppEvents.shared.logEvent(AppEvents.Name(eventName), parameters: params)
90
+ promise.resolve(true)
76
91
  }
77
92
  }
93
+ }
78
94
 
79
- if let error = error {
80
- promise.reject("meta_exception", error.localizedDescription)
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
- promise.resolve(true)
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
- if let dict = parameters {
91
- for (key, value) in dict {
92
- params[AppEvents.ParameterName(key)] = value
104
+ if let dict = parameters {
105
+ for (key, value) in dict {
106
+ params[AppEvents.ParameterName(key)] = value
107
+ }
93
108
  }
94
- }
95
109
 
96
- let error = ObjCExceptionHelper.execute {
97
- AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: params)
98
- }
110
+ var logError: NSError?
111
+ DatalyrObjCExceptionCatcher.tryBlock({
112
+ AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: params)
113
+ }, error: &logError)
99
114
 
100
- if let error = error {
101
- promise.reject("meta_exception", error.localizedDescription)
102
- return
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
- let error = ObjCExceptionHelper.execute {
110
- AppEvents.shared.setUserData(userData["email"] as? String, forType: .email)
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
- promise.resolve(true)
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
- AsyncFunction("clearMetaUserData") { (promise: Promise) in
131
- let error = ObjCExceptionHelper.execute {
132
- AppEvents.shared.clearUserData()
141
+ promise.resolve(true)
133
142
  }
143
+ }
134
144
 
135
- if let error = error {
136
- promise.reject("meta_exception", error.localizedDescription)
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
- promise.resolve(true)
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
- let error = ObjCExceptionHelper.execute {
145
- Settings.shared.isAdvertiserTrackingEnabled = enabled
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
- promise.resolve(true)
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 config: TikTokConfig?
162
- if let token = accessToken, !token.isEmpty {
163
- config = TikTokConfig(accessToken: token, appId: appId, tiktokAppId: tiktokAppId)
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
- let error = ObjCExceptionHelper.execute {
190
+ var initError: NSError?
191
+ let success = DatalyrObjCExceptionCatcher.tryBlock({
178
192
  TikTokBusiness.initializeSdk(validConfig)
179
- }
193
+ }, error: &initError)
180
194
 
181
- if let error = error {
182
- promise.reject("tiktok_init_exception", error.localizedDescription)
183
- return
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
- let error = ObjCExceptionHelper.execute {
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
- TikTokBusiness.trackTTEvent(event)
207
- }
226
+ var trackError: NSError?
227
+ DatalyrObjCExceptionCatcher.tryBlock({
228
+ TikTokBusiness.trackTTEvent(event)
229
+ }, error: &trackError)
208
230
 
209
- if let error = error {
210
- promise.reject("tiktok_exception", error.localizedDescription)
211
- return
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
- let error = ObjCExceptionHelper.execute {
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
- let error = ObjCExceptionHelper.execute {
237
- TikTokBusiness.logout()
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
- promise.resolve(true)
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.6",
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,11 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
-
3
- NS_ASSUME_NONNULL_BEGIN
4
-
5
- @interface ObjCExceptionHelper : NSObject
6
-
7
- + (nullable NSError *)execute:(void (NS_NOESCAPE ^)(void))block;
8
-
9
- @end
10
-
11
- NS_ASSUME_NONNULL_END
@@ -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