@datalyr/react-native 1.3.0 → 1.4.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.
@@ -1,332 +0,0 @@
1
- import Foundation
2
- import FBSDKCoreKit
3
- import TikTokBusinessSDK
4
- import AdServices
5
-
6
- @objc(DatalyrNative)
7
- class DatalyrNative: NSObject {
8
-
9
- @objc static func requiresMainQueueSetup() -> Bool {
10
- return false
11
- }
12
-
13
- // MARK: - Meta (Facebook) SDK Methods
14
-
15
- @objc func initializeMetaSDK(
16
- _ appId: String,
17
- clientToken: String?,
18
- advertiserTrackingEnabled: Bool,
19
- resolve: @escaping RCTPromiseResolveBlock,
20
- reject: @escaping RCTPromiseRejectBlock
21
- ) {
22
- DispatchQueue.main.async {
23
- Settings.shared.appID = appId
24
-
25
- if let token = clientToken, !token.isEmpty {
26
- Settings.shared.clientToken = token
27
- }
28
-
29
- Settings.shared.isAdvertiserTrackingEnabled = advertiserTrackingEnabled
30
- Settings.shared.isAdvertiserIDCollectionEnabled = advertiserTrackingEnabled
31
-
32
- ApplicationDelegate.shared.application(
33
- UIApplication.shared,
34
- didFinishLaunchingWithOptions: nil
35
- )
36
-
37
- resolve(true)
38
- }
39
- }
40
-
41
- @objc func fetchDeferredAppLink(
42
- _ resolve: @escaping RCTPromiseResolveBlock,
43
- reject: @escaping RCTPromiseRejectBlock
44
- ) {
45
- AppLinkUtility.fetchDeferredAppLink { url, error in
46
- if error != nil {
47
- // Don't reject - deferred deep link not available is expected in many cases
48
- // Error is normal when no deferred link exists
49
- resolve(nil)
50
- return
51
- }
52
-
53
- if let url = url {
54
- resolve(url.absoluteString)
55
- } else {
56
- resolve(nil)
57
- }
58
- }
59
- }
60
-
61
- @objc func logMetaEvent(
62
- _ eventName: String,
63
- valueToSum: NSNumber?,
64
- parameters: NSDictionary?,
65
- resolve: @escaping RCTPromiseResolveBlock,
66
- reject: @escaping RCTPromiseRejectBlock
67
- ) {
68
- var params: [AppEvents.ParameterName: Any] = [:]
69
-
70
- if let dict = parameters as? [String: Any] {
71
- for (key, value) in dict {
72
- params[AppEvents.ParameterName(key)] = value
73
- }
74
- }
75
-
76
- if let value = valueToSum?.doubleValue {
77
- AppEvents.shared.logEvent(AppEvents.Name(eventName), valueToSum: value, parameters: params)
78
- } else if params.isEmpty {
79
- AppEvents.shared.logEvent(AppEvents.Name(eventName))
80
- } else {
81
- AppEvents.shared.logEvent(AppEvents.Name(eventName), parameters: params)
82
- }
83
-
84
- resolve(true)
85
- }
86
-
87
- @objc func logMetaPurchase(
88
- _ amount: Double,
89
- currency: String,
90
- parameters: NSDictionary?,
91
- resolve: @escaping RCTPromiseResolveBlock,
92
- reject: @escaping RCTPromiseRejectBlock
93
- ) {
94
- var params: [AppEvents.ParameterName: Any] = [:]
95
-
96
- if let dict = parameters as? [String: Any] {
97
- for (key, value) in dict {
98
- params[AppEvents.ParameterName(key)] = value
99
- }
100
- }
101
-
102
- AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: params)
103
- resolve(true)
104
- }
105
-
106
- @objc func setMetaUserData(
107
- _ userData: NSDictionary,
108
- resolve: @escaping RCTPromiseResolveBlock,
109
- reject: @escaping RCTPromiseRejectBlock
110
- ) {
111
- AppEvents.shared.setUserData(
112
- userData["email"] as? String,
113
- forType: .email
114
- )
115
- AppEvents.shared.setUserData(
116
- userData["firstName"] as? String,
117
- forType: .firstName
118
- )
119
- AppEvents.shared.setUserData(
120
- userData["lastName"] as? String,
121
- forType: .lastName
122
- )
123
- AppEvents.shared.setUserData(
124
- userData["phone"] as? String,
125
- forType: .phone
126
- )
127
- AppEvents.shared.setUserData(
128
- userData["dateOfBirth"] as? String,
129
- forType: .dateOfBirth
130
- )
131
- AppEvents.shared.setUserData(
132
- userData["gender"] as? String,
133
- forType: .gender
134
- )
135
- AppEvents.shared.setUserData(
136
- userData["city"] as? String,
137
- forType: .city
138
- )
139
- AppEvents.shared.setUserData(
140
- userData["state"] as? String,
141
- forType: .state
142
- )
143
- AppEvents.shared.setUserData(
144
- userData["zip"] as? String,
145
- forType: .zip
146
- )
147
- AppEvents.shared.setUserData(
148
- userData["country"] as? String,
149
- forType: .country
150
- )
151
-
152
- resolve(true)
153
- }
154
-
155
- @objc func clearMetaUserData(
156
- _ resolve: @escaping RCTPromiseResolveBlock,
157
- reject: @escaping RCTPromiseRejectBlock
158
- ) {
159
- AppEvents.shared.clearUserData()
160
- resolve(true)
161
- }
162
-
163
- @objc func updateMetaTrackingAuthorization(
164
- _ enabled: Bool,
165
- resolve: @escaping RCTPromiseResolveBlock,
166
- reject: @escaping RCTPromiseRejectBlock
167
- ) {
168
- Settings.shared.isAdvertiserTrackingEnabled = enabled
169
- Settings.shared.isAdvertiserIDCollectionEnabled = enabled
170
- resolve(true)
171
- }
172
-
173
- // MARK: - TikTok SDK Methods
174
-
175
- @objc func initializeTikTokSDK(
176
- _ appId: String,
177
- tiktokAppId: String,
178
- accessToken: String?,
179
- debug: Bool,
180
- resolve: @escaping RCTPromiseResolveBlock,
181
- reject: @escaping RCTPromiseRejectBlock
182
- ) {
183
- DispatchQueue.main.async {
184
- let config = TikTokConfig(appId: appId, tiktokAppId: tiktokAppId)
185
-
186
- if let token = accessToken, !token.isEmpty {
187
- config?.accessToken = token
188
- }
189
-
190
- if debug {
191
- config?.setLogLevel(.debug)
192
- }
193
-
194
- if let validConfig = config {
195
- TikTokBusiness.initializeSdk(validConfig)
196
- resolve(true)
197
- } else {
198
- reject("tiktok_init_error", "Failed to create TikTok config", nil)
199
- }
200
- }
201
- }
202
-
203
- @objc func trackTikTokEvent(
204
- _ eventName: String,
205
- eventId: String?,
206
- properties: NSDictionary?,
207
- resolve: @escaping RCTPromiseResolveBlock,
208
- reject: @escaping RCTPromiseRejectBlock
209
- ) {
210
- // Use TikTokBaseEvent for modern API (trackEvent methods are deprecated)
211
- let event: TikTokBaseEvent
212
-
213
- if let eid = eventId, !eid.isEmpty {
214
- event = TikTokBaseEvent(eventName: eventName, eventId: eid)
215
- } else {
216
- event = TikTokBaseEvent(eventName: eventName)
217
- }
218
-
219
- // Add properties to the event
220
- if let dict = properties as? [String: Any] {
221
- for (key, value) in dict {
222
- event.addProperty(withKey: key, value: value)
223
- }
224
- }
225
-
226
- TikTokBusiness.trackTTEvent(event)
227
- resolve(true)
228
- }
229
-
230
- @objc func identifyTikTokUser(
231
- _ externalId: String,
232
- externalUserName: String,
233
- phoneNumber: String,
234
- email: String,
235
- resolve: @escaping RCTPromiseResolveBlock,
236
- reject: @escaping RCTPromiseRejectBlock
237
- ) {
238
- // Method signature: identifyWithExternalID:externalUserName:phoneNumber:email:
239
- TikTokBusiness.identify(
240
- withExternalID: externalId.isEmpty ? nil : externalId,
241
- externalUserName: externalUserName.isEmpty ? nil : externalUserName,
242
- phoneNumber: phoneNumber.isEmpty ? nil : phoneNumber,
243
- email: email.isEmpty ? nil : email
244
- )
245
- resolve(true)
246
- }
247
-
248
- @objc func logoutTikTok(
249
- _ resolve: @escaping RCTPromiseResolveBlock,
250
- reject: @escaping RCTPromiseRejectBlock
251
- ) {
252
- TikTokBusiness.logout()
253
- resolve(true)
254
- }
255
-
256
- @objc func updateTikTokTrackingAuthorization(
257
- _ enabled: Bool,
258
- resolve: @escaping RCTPromiseResolveBlock,
259
- reject: @escaping RCTPromiseRejectBlock
260
- ) {
261
- // TikTok SDK handles ATT automatically, but we track the change
262
- resolve(true)
263
- }
264
-
265
- // MARK: - SDK Availability Check
266
-
267
- @objc func getSDKAvailability(
268
- _ resolve: @escaping RCTPromiseResolveBlock,
269
- reject: @escaping RCTPromiseRejectBlock
270
- ) {
271
- resolve([
272
- "meta": true,
273
- "tiktok": true,
274
- "appleSearchAds": true
275
- ])
276
- }
277
-
278
- // MARK: - Apple Search Ads Attribution
279
-
280
- @objc func getAppleSearchAdsAttribution(
281
- _ resolve: @escaping RCTPromiseResolveBlock,
282
- reject: @escaping RCTPromiseRejectBlock
283
- ) {
284
- // AdServices is available on iOS 14.3+
285
- if #available(iOS 14.3, *) {
286
- do {
287
- // Get the attribution token from AdServices
288
- let token = try AAAttribution.attributionToken()
289
-
290
- // Send token to Apple's API to get attribution data
291
- var request = URLRequest(url: URL(string: "https://api-adservices.apple.com/api/v1/")!)
292
- request.httpMethod = "POST"
293
- request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
294
- request.httpBody = token.data(using: .utf8)
295
-
296
- let task = URLSession.shared.dataTask(with: request) { data, response, error in
297
- if let error = error {
298
- // Network error - resolve with nil instead of rejecting
299
- resolve(nil)
300
- return
301
- }
302
-
303
- guard let data = data else {
304
- resolve(nil)
305
- return
306
- }
307
-
308
- do {
309
- if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
310
- // Return attribution data
311
- // Includes: attribution, orgId, orgName, campaignId, campaignName,
312
- // adGroupId, adGroupName, clickDate, conversionType, etc.
313
- resolve(json)
314
- } else {
315
- resolve(nil)
316
- }
317
- } catch {
318
- resolve(nil)
319
- }
320
- }
321
- task.resume()
322
-
323
- } catch {
324
- // Attribution token not available (user didn't come from Apple Search Ads)
325
- resolve(nil)
326
- }
327
- } else {
328
- // iOS version too old
329
- resolve(nil)
330
- }
331
- }
332
- }
@@ -1,77 +0,0 @@
1
- #import <React/RCTBridgeModule.h>
2
- #import <StoreKit/StoreKit.h>
3
-
4
- @interface DatalyrSKAdNetwork : NSObject <RCTBridgeModule>
5
- @end
6
-
7
- @implementation DatalyrSKAdNetwork
8
-
9
- RCT_EXPORT_MODULE();
10
-
11
- // SKAN 3.0 - Legacy method for iOS 14.0-16.0
12
- RCT_EXPORT_METHOD(updateConversionValue:(NSInteger)value
13
- resolve:(RCTPromiseResolveBlock)resolve
14
- reject:(RCTPromiseRejectBlock)reject) {
15
- if (@available(iOS 14.0, *)) {
16
- @try {
17
- [SKAdNetwork updateConversionValue:value];
18
- resolve(@(YES));
19
- } @catch (NSException *exception) {
20
- reject(@"skadnetwork_error", exception.reason, nil);
21
- }
22
- } else {
23
- reject(@"ios_version_error", @"SKAdNetwork requires iOS 14.0+", nil);
24
- }
25
- }
26
-
27
- // SKAN 4.0 - New method for iOS 16.1+ with coarse value and lock window support
28
- RCT_EXPORT_METHOD(updatePostbackConversionValue:(NSInteger)fineValue
29
- coarseValue:(NSString *)coarseValue
30
- lockWindow:(BOOL)lockWindow
31
- resolve:(RCTPromiseResolveBlock)resolve
32
- reject:(RCTPromiseRejectBlock)reject) {
33
- if (@available(iOS 16.1, *)) {
34
- // Convert string to SKAdNetwork.CoarseConversionValue
35
- SKAdNetworkCoarseConversionValue coarse;
36
- if ([coarseValue isEqualToString:@"high"]) {
37
- coarse = SKAdNetworkCoarseConversionValueHigh;
38
- } else if ([coarseValue isEqualToString:@"medium"]) {
39
- coarse = SKAdNetworkCoarseConversionValueMedium;
40
- } else {
41
- coarse = SKAdNetworkCoarseConversionValueLow;
42
- }
43
-
44
- [SKAdNetwork updatePostbackConversionValue:fineValue
45
- coarseValue:coarse
46
- lockWindow:lockWindow
47
- completionHandler:^(NSError * _Nullable error) {
48
- if (error) {
49
- reject(@"skadnetwork_error", error.localizedDescription, error);
50
- } else {
51
- resolve(@(YES));
52
- }
53
- }];
54
- } else if (@available(iOS 14.0, *)) {
55
- // Fallback to SKAN 3.0 for iOS 14.0-16.0
56
- @try {
57
- [SKAdNetwork updateConversionValue:fineValue];
58
- resolve(@(YES));
59
- } @catch (NSException *exception) {
60
- reject(@"skadnetwork_error", exception.reason, nil);
61
- }
62
- } else {
63
- reject(@"ios_version_error", @"SKAdNetwork requires iOS 14.0+", nil);
64
- }
65
- }
66
-
67
- // Check if SKAN 4.0 is available (iOS 16.1+)
68
- RCT_EXPORT_METHOD(isSKAN4Available:(RCTPromiseResolveBlock)resolve
69
- reject:(RCTPromiseRejectBlock)reject) {
70
- if (@available(iOS 16.1, *)) {
71
- resolve(@(YES));
72
- } else {
73
- resolve(@(NO));
74
- }
75
- }
76
-
77
- @end