@datalyr/react-native 1.2.0 → 1.3.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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +30 -1
  3. package/android/build.gradle +54 -0
  4. package/android/src/main/AndroidManifest.xml +14 -0
  5. package/android/src/main/java/com/datalyr/reactnative/DatalyrNativeModule.java +423 -0
  6. package/android/src/main/java/com/datalyr/reactnative/DatalyrPackage.java +30 -0
  7. package/android/src/main/java/com/datalyr/reactnative/DatalyrPlayInstallReferrerModule.java +229 -0
  8. package/datalyr-react-native.podspec +2 -2
  9. package/ios/DatalyrNative.m +4 -0
  10. package/ios/DatalyrNative.swift +58 -1
  11. package/ios/DatalyrSKAdNetwork.m +52 -1
  12. package/lib/ConversionValueEncoder.d.ts +13 -1
  13. package/lib/ConversionValueEncoder.js +57 -23
  14. package/lib/datalyr-sdk.d.ts +34 -2
  15. package/lib/datalyr-sdk.js +90 -8
  16. package/lib/index.d.ts +4 -1
  17. package/lib/index.js +2 -1
  18. package/lib/integrations/apple-search-ads-integration.d.ts +43 -0
  19. package/lib/integrations/apple-search-ads-integration.js +106 -0
  20. package/lib/integrations/index.d.ts +4 -1
  21. package/lib/integrations/index.js +3 -1
  22. package/lib/integrations/meta-integration.d.ts +1 -0
  23. package/lib/integrations/meta-integration.js +4 -3
  24. package/lib/integrations/play-install-referrer.d.ts +74 -0
  25. package/lib/integrations/play-install-referrer.js +156 -0
  26. package/lib/integrations/tiktok-integration.d.ts +1 -0
  27. package/lib/integrations/tiktok-integration.js +4 -3
  28. package/lib/journey.d.ts +106 -0
  29. package/lib/journey.js +258 -0
  30. package/lib/native/DatalyrNativeBridge.d.ts +67 -2
  31. package/lib/native/DatalyrNativeBridge.js +80 -7
  32. package/lib/native/SKAdNetworkBridge.d.ts +21 -0
  33. package/lib/native/SKAdNetworkBridge.js +54 -0
  34. package/package.json +9 -3
  35. package/src/ConversionValueEncoder.ts +67 -26
  36. package/src/datalyr-sdk-expo.ts +98 -9
  37. package/src/datalyr-sdk.ts +109 -14
  38. package/src/expo.ts +8 -0
  39. package/src/index.ts +6 -1
  40. package/src/integrations/apple-search-ads-integration.ts +119 -0
  41. package/src/integrations/index.ts +4 -1
  42. package/src/integrations/meta-integration.ts +4 -3
  43. package/src/integrations/play-install-referrer.ts +203 -0
  44. package/src/integrations/tiktok-integration.ts +4 -3
  45. package/src/journey.ts +338 -0
  46. package/src/native/DatalyrNativeBridge.ts +137 -9
  47. package/src/native/SKAdNetworkBridge.ts +86 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to the Datalyr React Native SDK will be documented in this f
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.1] - 2025-01
9
+
10
+ ### Added
11
+ - Apple Search Ads attribution support via AdServices framework (iOS 14.3+)
12
+ - `getAppleSearchAdsAttribution()` method to retrieve attribution data
13
+ - Automatic capture of Apple Search Ads attribution on SDK initialization
14
+ - Apple Search Ads data included in all events (asa_campaign_id, asa_keyword, etc.)
15
+
8
16
  ## [1.2.0] - 2025-01
9
17
 
10
18
  ### Added
package/README.md CHANGED
@@ -23,6 +23,9 @@ Mobile analytics and attribution SDK for React Native and Expo. Track events, id
23
23
  - [Auto Events](#auto-events)
24
24
  - [SKAdNetwork](#skadnetwork)
25
25
  - [Platform Integrations](#platform-integrations)
26
+ - [Meta](#meta-facebook)
27
+ - [TikTok](#tiktok)
28
+ - [Apple Search Ads](#apple-search-ads)
26
29
  - [Expo Support](#expo-support)
27
30
  - [TypeScript](#typescript)
28
31
  - [Troubleshooting](#troubleshooting)
@@ -482,6 +485,32 @@ await Datalyr.initialize({
482
485
  });
483
486
  ```
484
487
 
488
+ ### Apple Search Ads
489
+
490
+ Attribution for users who install from Apple Search Ads (iOS 14.3+). Automatically fetched on initialization.
491
+
492
+ ```typescript
493
+ // Check if user came from Apple Search Ads
494
+ const asaAttribution = Datalyr.getAppleSearchAdsAttribution();
495
+
496
+ if (asaAttribution?.attribution) {
497
+ console.log(asaAttribution.campaignId); // Campaign ID
498
+ console.log(asaAttribution.campaignName); // Campaign name
499
+ console.log(asaAttribution.adGroupId); // Ad group ID
500
+ console.log(asaAttribution.keyword); // Search keyword
501
+ console.log(asaAttribution.clickDate); // Click date
502
+ }
503
+ ```
504
+
505
+ Attribution data is automatically included in all events with the `asa_` prefix:
506
+ - `asa_campaign_id`, `asa_campaign_name`
507
+ - `asa_ad_group_id`, `asa_ad_group_name`
508
+ - `asa_keyword_id`, `asa_keyword`
509
+ - `asa_org_id`, `asa_org_name`
510
+ - `asa_click_date`, `asa_conversion_type`
511
+
512
+ No additional configuration needed. The SDK uses Apple's AdServices API.
513
+
485
514
  ### App Tracking Transparency
486
515
 
487
516
  Update after ATT dialog:
@@ -495,7 +524,7 @@ await Datalyr.updateTrackingAuthorization(status === 'granted');
495
524
 
496
525
  ```typescript
497
526
  const status = Datalyr.getPlatformIntegrationStatus();
498
- // { meta: true, tiktok: true }
527
+ // { meta: true, tiktok: true, appleSearchAds: true }
499
528
  ```
500
529
 
501
530
  ---
@@ -0,0 +1,54 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+ dependencies {
7
+ classpath 'com.android.tools.build:gradle:8.2.0'
8
+ }
9
+ }
10
+
11
+ apply plugin: 'com.android.library'
12
+
13
+ def safeExtGet(prop, fallback) {
14
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
15
+ }
16
+
17
+ android {
18
+ namespace "com.datalyr.reactnative"
19
+ compileSdkVersion safeExtGet('compileSdkVersion', 35)
20
+
21
+ defaultConfig {
22
+ minSdkVersion safeExtGet('minSdkVersion', 21)
23
+ targetSdkVersion safeExtGet('targetSdkVersion', 35)
24
+ }
25
+
26
+ compileOptions {
27
+ sourceCompatibility JavaVersion.VERSION_17
28
+ targetCompatibility JavaVersion.VERSION_17
29
+ }
30
+
31
+ lint {
32
+ abortOnError false
33
+ }
34
+ }
35
+
36
+ repositories {
37
+ google()
38
+ mavenCentral()
39
+ maven { url "https://artifact.bytedance.com/repository/pangle" } // TikTok SDK
40
+ }
41
+
42
+ dependencies {
43
+ // React Native
44
+ implementation "com.facebook.react:react-native:+"
45
+
46
+ // Meta (Facebook) SDK - Updated Jan 2026
47
+ implementation 'com.facebook.android:facebook-android-sdk:18.1.3'
48
+
49
+ // TikTok Business SDK - Updated Jan 2026
50
+ implementation 'com.tiktok.business.sdk:tiktok-business-android-sdk:1.6.0'
51
+
52
+ // Google Play Install Referrer
53
+ implementation 'com.android.installreferrer:installreferrer:2.2'
54
+ }
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ package="com.datalyr.reactnative">
4
+
5
+ <!-- Required for network requests -->
6
+ <uses-permission android:name="android.permission.INTERNET" />
7
+
8
+ <!-- Required for Google Play Install Referrer -->
9
+ <uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" />
10
+
11
+ <!-- Optional: For device info -->
12
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
13
+
14
+ </manifest>
@@ -0,0 +1,423 @@
1
+ package com.datalyr.reactnative;
2
+
3
+ import android.os.Bundle;
4
+ import android.util.Log;
5
+
6
+ import com.facebook.react.bridge.Arguments;
7
+ import com.facebook.react.bridge.Promise;
8
+ import com.facebook.react.bridge.ReactApplicationContext;
9
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
10
+ import com.facebook.react.bridge.ReactMethod;
11
+ import com.facebook.react.bridge.ReadableMap;
12
+ import com.facebook.react.bridge.ReadableMapKeySetIterator;
13
+ import com.facebook.react.bridge.WritableMap;
14
+
15
+ // Meta (Facebook) SDK imports
16
+ import com.facebook.FacebookSdk;
17
+ import com.facebook.appevents.AppEventsLogger;
18
+ import com.facebook.appevents.AppEventsConstants;
19
+ import com.facebook.appevents.UserDataStore;
20
+ import com.facebook.bolts.AppLinks;
21
+ import android.net.Uri;
22
+
23
+ // TikTok SDK imports
24
+ import com.tiktok.TikTokBusinessSdk;
25
+ import com.tiktok.TikTokBusinessSdk.TTConfig;
26
+ import com.tiktok.appevents.TikTokAppEvent;
27
+ import com.tiktok.appevents.TikTokAppEventLogger;
28
+
29
+ import java.math.BigDecimal;
30
+ import java.util.Currency;
31
+ import java.util.HashMap;
32
+ import java.util.Map;
33
+
34
+ /**
35
+ * Datalyr Native Module for Android
36
+ * Provides Meta (Facebook) and TikTok SDK integrations for React Native
37
+ */
38
+ public class DatalyrNativeModule extends ReactContextBaseJavaModule {
39
+ private static final String TAG = "DatalyrNative";
40
+ private static final String MODULE_NAME = "DatalyrNative";
41
+
42
+ private final ReactApplicationContext reactContext;
43
+ private AppEventsLogger metaLogger;
44
+ private boolean metaInitialized = false;
45
+ private boolean tiktokInitialized = false;
46
+
47
+ public DatalyrNativeModule(ReactApplicationContext context) {
48
+ super(context);
49
+ this.reactContext = context;
50
+ }
51
+
52
+ @Override
53
+ public String getName() {
54
+ return MODULE_NAME;
55
+ }
56
+
57
+ // ============================================================================
58
+ // Meta (Facebook) SDK Methods
59
+ // ============================================================================
60
+
61
+ @ReactMethod
62
+ public void initializeMetaSDK(String appId, String clientToken, boolean advertiserTrackingEnabled, Promise promise) {
63
+ try {
64
+ // Initialize Facebook SDK
65
+ FacebookSdk.setApplicationId(appId);
66
+ if (clientToken != null && !clientToken.isEmpty()) {
67
+ FacebookSdk.setClientToken(clientToken);
68
+ }
69
+ FacebookSdk.setAdvertiserIDCollectionEnabled(advertiserTrackingEnabled);
70
+ FacebookSdk.setAutoLogAppEventsEnabled(true);
71
+ FacebookSdk.sdkInitialize(reactContext.getApplicationContext());
72
+
73
+ // Create logger instance
74
+ metaLogger = AppEventsLogger.newLogger(reactContext.getApplicationContext());
75
+ metaInitialized = true;
76
+
77
+ Log.d(TAG, "Meta SDK initialized with App ID: " + appId);
78
+ promise.resolve(true);
79
+ } catch (Exception e) {
80
+ Log.e(TAG, "Failed to initialize Meta SDK", e);
81
+ promise.reject("meta_init_error", "Failed to initialize Meta SDK: " + e.getMessage());
82
+ }
83
+ }
84
+
85
+ @ReactMethod
86
+ public void fetchDeferredAppLink(Promise promise) {
87
+ if (!metaInitialized) {
88
+ promise.resolve(null);
89
+ return;
90
+ }
91
+
92
+ try {
93
+ AppLinks.getTargetUrlFromInboundIntent(reactContext.getApplicationContext(), reactContext.getCurrentActivity().getIntent())
94
+ .continueWith(task -> {
95
+ if (task.getError() != null) {
96
+ Log.d(TAG, "Deferred app link error: " + task.getError().getMessage());
97
+ promise.resolve(null);
98
+ return null;
99
+ }
100
+
101
+ Uri targetUrl = task.getResult();
102
+ if (targetUrl != null) {
103
+ promise.resolve(targetUrl.toString());
104
+ } else {
105
+ promise.resolve(null);
106
+ }
107
+ return null;
108
+ });
109
+ } catch (Exception e) {
110
+ Log.d(TAG, "Deferred app link not available");
111
+ promise.resolve(null);
112
+ }
113
+ }
114
+
115
+ @ReactMethod
116
+ public void logMetaEvent(String eventName, Double valueToSum, ReadableMap parameters, Promise promise) {
117
+ if (!metaInitialized || metaLogger == null) {
118
+ promise.resolve(false);
119
+ return;
120
+ }
121
+
122
+ try {
123
+ Bundle params = readableMapToBundle(parameters);
124
+
125
+ if (valueToSum != null) {
126
+ metaLogger.logEvent(eventName, valueToSum, params);
127
+ } else if (params.isEmpty()) {
128
+ metaLogger.logEvent(eventName);
129
+ } else {
130
+ metaLogger.logEvent(eventName, params);
131
+ }
132
+
133
+ Log.d(TAG, "Meta event logged: " + eventName);
134
+ promise.resolve(true);
135
+ } catch (Exception e) {
136
+ Log.e(TAG, "Failed to log Meta event", e);
137
+ promise.reject("meta_event_error", "Failed to log Meta event: " + e.getMessage());
138
+ }
139
+ }
140
+
141
+ @ReactMethod
142
+ public void logMetaPurchase(double amount, String currency, ReadableMap parameters, Promise promise) {
143
+ if (!metaInitialized || metaLogger == null) {
144
+ promise.resolve(false);
145
+ return;
146
+ }
147
+
148
+ try {
149
+ Bundle params = readableMapToBundle(parameters);
150
+ BigDecimal purchaseAmount = BigDecimal.valueOf(amount);
151
+ Currency currencyObj = Currency.getInstance(currency);
152
+
153
+ metaLogger.logPurchase(purchaseAmount, currencyObj, params);
154
+
155
+ Log.d(TAG, "Meta purchase logged: " + amount + " " + currency);
156
+ promise.resolve(true);
157
+ } catch (Exception e) {
158
+ Log.e(TAG, "Failed to log Meta purchase", e);
159
+ promise.reject("meta_purchase_error", "Failed to log Meta purchase: " + e.getMessage());
160
+ }
161
+ }
162
+
163
+ @ReactMethod
164
+ public void setMetaUserData(ReadableMap userData, Promise promise) {
165
+ if (!metaInitialized) {
166
+ promise.resolve(false);
167
+ return;
168
+ }
169
+
170
+ try {
171
+ // Set user data for Advanced Matching
172
+ Bundle userDataBundle = new Bundle();
173
+
174
+ if (userData.hasKey("email")) {
175
+ userDataBundle.putString("em", userData.getString("email"));
176
+ }
177
+ if (userData.hasKey("firstName")) {
178
+ userDataBundle.putString("fn", userData.getString("firstName"));
179
+ }
180
+ if (userData.hasKey("lastName")) {
181
+ userDataBundle.putString("ln", userData.getString("lastName"));
182
+ }
183
+ if (userData.hasKey("phone")) {
184
+ userDataBundle.putString("ph", userData.getString("phone"));
185
+ }
186
+ if (userData.hasKey("dateOfBirth")) {
187
+ userDataBundle.putString("db", userData.getString("dateOfBirth"));
188
+ }
189
+ if (userData.hasKey("gender")) {
190
+ userDataBundle.putString("ge", userData.getString("gender"));
191
+ }
192
+ if (userData.hasKey("city")) {
193
+ userDataBundle.putString("ct", userData.getString("city"));
194
+ }
195
+ if (userData.hasKey("state")) {
196
+ userDataBundle.putString("st", userData.getString("state"));
197
+ }
198
+ if (userData.hasKey("zip")) {
199
+ userDataBundle.putString("zp", userData.getString("zip"));
200
+ }
201
+ if (userData.hasKey("country")) {
202
+ userDataBundle.putString("country", userData.getString("country"));
203
+ }
204
+
205
+ AppEventsLogger.setUserData(
206
+ userData.hasKey("email") ? userData.getString("email") : null,
207
+ userData.hasKey("firstName") ? userData.getString("firstName") : null,
208
+ userData.hasKey("lastName") ? userData.getString("lastName") : null,
209
+ userData.hasKey("phone") ? userData.getString("phone") : null,
210
+ userData.hasKey("dateOfBirth") ? userData.getString("dateOfBirth") : null,
211
+ userData.hasKey("gender") ? userData.getString("gender") : null,
212
+ userData.hasKey("city") ? userData.getString("city") : null,
213
+ userData.hasKey("state") ? userData.getString("state") : null,
214
+ userData.hasKey("zip") ? userData.getString("zip") : null,
215
+ userData.hasKey("country") ? userData.getString("country") : null
216
+ );
217
+
218
+ Log.d(TAG, "Meta user data set for Advanced Matching");
219
+ promise.resolve(true);
220
+ } catch (Exception e) {
221
+ Log.e(TAG, "Failed to set Meta user data", e);
222
+ promise.reject("meta_userdata_error", "Failed to set Meta user data: " + e.getMessage());
223
+ }
224
+ }
225
+
226
+ @ReactMethod
227
+ public void clearMetaUserData(Promise promise) {
228
+ if (!metaInitialized) {
229
+ promise.resolve(false);
230
+ return;
231
+ }
232
+
233
+ try {
234
+ AppEventsLogger.clearUserData();
235
+ Log.d(TAG, "Meta user data cleared");
236
+ promise.resolve(true);
237
+ } catch (Exception e) {
238
+ Log.e(TAG, "Failed to clear Meta user data", e);
239
+ promise.reject("meta_clear_error", "Failed to clear Meta user data: " + e.getMessage());
240
+ }
241
+ }
242
+
243
+ @ReactMethod
244
+ public void updateMetaTrackingAuthorization(boolean enabled, Promise promise) {
245
+ try {
246
+ FacebookSdk.setAdvertiserIDCollectionEnabled(enabled);
247
+ Log.d(TAG, "Meta tracking authorization updated: " + enabled);
248
+ promise.resolve(true);
249
+ } catch (Exception e) {
250
+ Log.e(TAG, "Failed to update Meta tracking authorization", e);
251
+ promise.reject("meta_tracking_error", "Failed to update Meta tracking: " + e.getMessage());
252
+ }
253
+ }
254
+
255
+ // ============================================================================
256
+ // TikTok SDK Methods
257
+ // ============================================================================
258
+
259
+ @ReactMethod
260
+ public void initializeTikTokSDK(String appId, String tiktokAppId, String accessToken, boolean debug, Promise promise) {
261
+ try {
262
+ TTConfig config = new TTConfig(reactContext.getApplicationContext())
263
+ .setAppId(appId)
264
+ .setTTAppId(tiktokAppId);
265
+
266
+ if (accessToken != null && !accessToken.isEmpty()) {
267
+ config.setAccessToken(accessToken);
268
+ }
269
+
270
+ if (debug) {
271
+ config.openDebugMode();
272
+ }
273
+
274
+ TikTokBusinessSdk.initializeSdk(config);
275
+ tiktokInitialized = true;
276
+
277
+ Log.d(TAG, "TikTok SDK initialized with App ID: " + tiktokAppId);
278
+ promise.resolve(true);
279
+ } catch (Exception e) {
280
+ Log.e(TAG, "Failed to initialize TikTok SDK", e);
281
+ promise.reject("tiktok_init_error", "Failed to initialize TikTok SDK: " + e.getMessage());
282
+ }
283
+ }
284
+
285
+ @ReactMethod
286
+ public void trackTikTokEvent(String eventName, String eventId, ReadableMap properties, Promise promise) {
287
+ if (!tiktokInitialized) {
288
+ promise.resolve(false);
289
+ return;
290
+ }
291
+
292
+ try {
293
+ TikTokAppEvent event;
294
+ if (eventId != null && !eventId.isEmpty()) {
295
+ event = new TikTokAppEvent(eventName).setEventId(eventId);
296
+ } else {
297
+ event = new TikTokAppEvent(eventName);
298
+ }
299
+
300
+ // Add properties to the event
301
+ if (properties != null) {
302
+ ReadableMapKeySetIterator iterator = properties.keySetIterator();
303
+ while (iterator.hasNextKey()) {
304
+ String key = iterator.nextKey();
305
+ switch (properties.getType(key)) {
306
+ case String:
307
+ event.addProperty(key, properties.getString(key));
308
+ break;
309
+ case Number:
310
+ event.addProperty(key, properties.getDouble(key));
311
+ break;
312
+ case Boolean:
313
+ event.addProperty(key, properties.getBoolean(key));
314
+ break;
315
+ default:
316
+ break;
317
+ }
318
+ }
319
+ }
320
+
321
+ TikTokBusinessSdk.trackTTEvent(event);
322
+
323
+ Log.d(TAG, "TikTok event logged: " + eventName);
324
+ promise.resolve(true);
325
+ } catch (Exception e) {
326
+ Log.e(TAG, "Failed to log TikTok event", e);
327
+ promise.reject("tiktok_event_error", "Failed to log TikTok event: " + e.getMessage());
328
+ }
329
+ }
330
+
331
+ @ReactMethod
332
+ public void identifyTikTokUser(String externalId, String externalUserName, String phoneNumber, String email, Promise promise) {
333
+ if (!tiktokInitialized) {
334
+ promise.resolve(false);
335
+ return;
336
+ }
337
+
338
+ try {
339
+ TikTokBusinessSdk.identify(
340
+ externalId != null && !externalId.isEmpty() ? externalId : null,
341
+ externalUserName != null && !externalUserName.isEmpty() ? externalUserName : null,
342
+ phoneNumber != null && !phoneNumber.isEmpty() ? phoneNumber : null,
343
+ email != null && !email.isEmpty() ? email : null
344
+ );
345
+
346
+ Log.d(TAG, "TikTok user identified");
347
+ promise.resolve(true);
348
+ } catch (Exception e) {
349
+ Log.e(TAG, "Failed to identify TikTok user", e);
350
+ promise.reject("tiktok_identify_error", "Failed to identify TikTok user: " + e.getMessage());
351
+ }
352
+ }
353
+
354
+ @ReactMethod
355
+ public void logoutTikTok(Promise promise) {
356
+ if (!tiktokInitialized) {
357
+ promise.resolve(false);
358
+ return;
359
+ }
360
+
361
+ try {
362
+ TikTokBusinessSdk.logout();
363
+ Log.d(TAG, "TikTok user logged out");
364
+ promise.resolve(true);
365
+ } catch (Exception e) {
366
+ Log.e(TAG, "Failed to logout TikTok user", e);
367
+ promise.reject("tiktok_logout_error", "Failed to logout TikTok user: " + e.getMessage());
368
+ }
369
+ }
370
+
371
+ @ReactMethod
372
+ public void updateTikTokTrackingAuthorization(boolean enabled, Promise promise) {
373
+ // TikTok SDK handles this automatically on Android
374
+ // No explicit method needed
375
+ Log.d(TAG, "TikTok tracking authorization update requested: " + enabled);
376
+ promise.resolve(true);
377
+ }
378
+
379
+ // ============================================================================
380
+ // SDK Availability
381
+ // ============================================================================
382
+
383
+ @ReactMethod
384
+ public void getSDKAvailability(Promise promise) {
385
+ WritableMap result = Arguments.createMap();
386
+ result.putBoolean("meta", true);
387
+ result.putBoolean("tiktok", true);
388
+ result.putBoolean("playInstallReferrer", true);
389
+ // Apple Search Ads is iOS only
390
+ result.putBoolean("appleSearchAds", false);
391
+ promise.resolve(result);
392
+ }
393
+
394
+ // ============================================================================
395
+ // Helper Methods
396
+ // ============================================================================
397
+
398
+ private Bundle readableMapToBundle(ReadableMap map) {
399
+ Bundle bundle = new Bundle();
400
+ if (map == null) {
401
+ return bundle;
402
+ }
403
+
404
+ ReadableMapKeySetIterator iterator = map.keySetIterator();
405
+ while (iterator.hasNextKey()) {
406
+ String key = iterator.nextKey();
407
+ switch (map.getType(key)) {
408
+ case String:
409
+ bundle.putString(key, map.getString(key));
410
+ break;
411
+ case Number:
412
+ bundle.putDouble(key, map.getDouble(key));
413
+ break;
414
+ case Boolean:
415
+ bundle.putBoolean(key, map.getBoolean(key));
416
+ break;
417
+ default:
418
+ break;
419
+ }
420
+ }
421
+ return bundle;
422
+ }
423
+ }
@@ -0,0 +1,30 @@
1
+ package com.datalyr.reactnative;
2
+
3
+ import com.facebook.react.ReactPackage;
4
+ import com.facebook.react.bridge.NativeModule;
5
+ import com.facebook.react.bridge.ReactApplicationContext;
6
+ import com.facebook.react.uimanager.ViewManager;
7
+
8
+ import java.util.ArrayList;
9
+ import java.util.Collections;
10
+ import java.util.List;
11
+
12
+ /**
13
+ * React Native Package for Datalyr SDK
14
+ * Registers all native modules (Meta, TikTok, Play Install Referrer)
15
+ */
16
+ public class DatalyrPackage implements ReactPackage {
17
+
18
+ @Override
19
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
20
+ List<NativeModule> modules = new ArrayList<>();
21
+ modules.add(new DatalyrNativeModule(reactContext));
22
+ modules.add(new DatalyrPlayInstallReferrerModule(reactContext));
23
+ return modules;
24
+ }
25
+
26
+ @Override
27
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
28
+ return Collections.emptyList();
29
+ }
30
+ }