react-native-purchases 10.3.0 → 10.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.
@@ -25,6 +25,6 @@ Pod::Spec.new do |spec|
25
25
  ]
26
26
 
27
27
  spec.dependency "React-Core"
28
- spec.dependency "PurchasesHybridCommon", '18.14.1'
28
+ spec.dependency "PurchasesHybridCommon", '18.15.1'
29
29
  spec.swift_version = '5.7'
30
30
  end
@@ -29,7 +29,7 @@ android {
29
29
  minSdkVersion getExtOrIntegerDefault('minSdkVersion')
30
30
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
31
31
  versionCode 1
32
- versionName '10.3.0'
32
+ versionName '10.4.0'
33
33
  }
34
34
 
35
35
  buildTypes {
@@ -121,6 +121,6 @@ def kotlin_version = getExtOrDefault('kotlinVersion')
121
121
  dependencies {
122
122
  //noinspection GradleDynamicVersion
123
123
  api 'com.facebook.react:react-native:+'
124
- implementation 'com.revenuecat.purchases:purchases-hybrid-common:18.14.1'
124
+ implementation 'com.revenuecat.purchases:purchases-hybrid-common:18.15.1'
125
125
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
126
126
  }
@@ -51,7 +51,7 @@ public class RNPurchasesModule extends ReactContextBaseJavaModule implements Upd
51
51
  private static final String TRACKED_EVENT = "Purchases-TrackedEvent";
52
52
  private static final String DEBUG_EVENT = "Purchases-DebugEvent";
53
53
  public static final String PLATFORM_NAME = "react-native";
54
- public static final String PLUGIN_VERSION = "10.3.0";
54
+ public static final String PLUGIN_VERSION = "10.4.0";
55
55
 
56
56
  private final ReactApplicationContext reactContext;
57
57
 
@@ -145,13 +145,7 @@ public class RNPurchasesModule extends ReactContextBaseJavaModule implements Upd
145
145
 
146
146
  @ReactMethod
147
147
  public void setAppstackAttributionParams(ReadableMap data, final Promise promise) {
148
- HashMap<String, Object> dataMap = new HashMap<>();
149
- for (Map.Entry<String, Object> entry : data.toHashMap().entrySet()) {
150
- if (entry.getValue() != null) {
151
- dataMap.put(entry.getKey(), entry.getValue());
152
- }
153
- }
154
- CommonKt.setAppstackAttributionParams(dataMap, getOnResult(promise));
148
+ CommonKt.setAppstackAttributionParams(mapWithoutNullValues(data), getOnResult(promise));
155
149
  }
156
150
 
157
151
  @ReactMethod
@@ -551,6 +545,11 @@ public class RNPurchasesModule extends ReactContextBaseJavaModule implements Upd
551
545
  SubscriberAttributesKt.setCreative(creative);
552
546
  }
553
547
 
548
+ @ReactMethod
549
+ public void setAppsFlyerConversionData(ReadableMap data) {
550
+ SubscriberAttributesKt.setAppsFlyerConversionData(data == null ? null : data.toHashMap());
551
+ }
552
+
554
553
  @ReactMethod
555
554
  public void canMakePayments(ReadableArray features, final Promise promise) {
556
555
  ArrayList<Integer> featureList = new ArrayList<>();
@@ -628,7 +627,7 @@ public class RNPurchasesModule extends ReactContextBaseJavaModule implements Upd
628
627
 
629
628
  @ReactMethod
630
629
  public void trackCustomPaywallImpression(ReadableMap data) {
631
- CommonKt.trackCustomPaywallImpression(data.toHashMap());
630
+ CommonKt.trackCustomPaywallImpression(mapWithoutNullValues(data));
632
631
  }
633
632
 
634
633
  @ReactMethod
@@ -736,4 +735,36 @@ public class RNPurchasesModule extends ReactContextBaseJavaModule implements Upd
736
735
  return null;
737
736
  }
738
737
  }
738
+
739
+ private static HashMap<String, Object> mapWithoutNullValues(ReadableMap data) {
740
+ return mapWithoutNullValues(data.toHashMap());
741
+ }
742
+
743
+ private static HashMap<String, Object> mapWithoutNullValues(Map<?, ?> data) {
744
+ HashMap<String, Object> dataMap = new HashMap<>();
745
+ for (Map.Entry<?, ?> entry : data.entrySet()) {
746
+ Object value = valueWithoutNullValues(entry.getValue());
747
+ if (entry.getKey() instanceof String && value != null) {
748
+ dataMap.put((String) entry.getKey(), value);
749
+ }
750
+ }
751
+ return dataMap;
752
+ }
753
+
754
+ private static Object valueWithoutNullValues(@Nullable Object value) {
755
+ if (value instanceof Map) {
756
+ return mapWithoutNullValues((Map<?, ?>) value);
757
+ }
758
+ if (value instanceof List) {
759
+ ArrayList<Object> filteredList = new ArrayList<>();
760
+ for (Object item : (List<?>) value) {
761
+ Object filteredItem = valueWithoutNullValues(item);
762
+ if (filteredItem != null) {
763
+ filteredList.add(filteredItem);
764
+ }
765
+ }
766
+ return filteredList;
767
+ }
768
+ return value;
769
+ }
739
770
  }
@@ -17,6 +17,7 @@ export declare const browserNativeModuleRNPurchases: {
17
17
  setDebugLogsEnabled: (_enabled: boolean) => Promise<void>;
18
18
  setLogLevel: (level: string) => Promise<void>;
19
19
  setLogHandler: (handler: (level: string, message: string) => void) => Promise<void>;
20
+ trackCustomPaywallImpression: (_data: any) => Promise<void>;
20
21
  getCustomerInfo: () => Promise<import("@revenuecat/purchases-typescript-internal").CustomerInfo>;
21
22
  logIn: (appUserID: string) => Promise<{
22
23
  customerInfo: import("@revenuecat/purchases-typescript-internal").CustomerInfo;
@@ -70,6 +71,7 @@ export declare const browserNativeModuleRNPurchases: {
70
71
  setAd: (_ad: string) => Promise<void>;
71
72
  setKeyword: (_keyword: string) => Promise<void>;
72
73
  setCreative: (_creative: string) => Promise<void>;
74
+ setAppsFlyerConversionData: (_data: Record<string, any> | null) => Promise<void>;
73
75
  overridePreferredLocale: (_locale: string | null) => Promise<void>;
74
76
  canMakePayments: (_features: any[]) => Promise<boolean>;
75
77
  beginRefundRequestForActiveEntitlement: () => Promise<void>;
@@ -175,6 +175,12 @@ exports.browserNativeModuleRNPurchases = {
175
175
  return [2 /*return*/];
176
176
  });
177
177
  }); },
178
+ trackCustomPaywallImpression: function (_data) { return __awaiter(void 0, void 0, void 0, function () {
179
+ return __generator(this, function (_a) {
180
+ (0, utils_1.methodNotSupportedOnWeb)('trackCustomPaywallImpression');
181
+ return [2 /*return*/];
182
+ });
183
+ }); },
178
184
  getCustomerInfo: function () { return __awaiter(void 0, void 0, void 0, function () {
179
185
  var customerInfo;
180
186
  return __generator(this, function (_a) {
@@ -505,6 +511,12 @@ exports.browserNativeModuleRNPurchases = {
505
511
  return [2 /*return*/];
506
512
  });
507
513
  }); },
514
+ setAppsFlyerConversionData: function (_data) { return __awaiter(void 0, void 0, void 0, function () {
515
+ return __generator(this, function (_a) {
516
+ (0, utils_1.methodNotSupportedOnWeb)('setAppsFlyerConversionData');
517
+ return [2 /*return*/];
518
+ });
519
+ }); },
508
520
  overridePreferredLocale: function (_locale) { return __awaiter(void 0, void 0, void 0, function () {
509
521
  return __generator(this, function (_a) {
510
522
  (0, utils_1.methodNotSupportedOnWeb)('overridePreferredLocale');
@@ -26,9 +26,18 @@ export type PurchasesConfiguration = {
26
26
  */
27
27
  export interface TrackCustomPaywallImpressionOptions {
28
28
  paywallId?: string | null;
29
+ /**
30
+ * The offering associated with the custom paywall.
31
+ *
32
+ * Prefer passing the offering object when available so RevenueCat can track placement
33
+ * and targeting context for placement-resolved offerings.
34
+ */
35
+ offering?: PurchasesOffering | null;
29
36
  /**
30
37
  * An optional identifier for the offering associated with the custom paywall.
31
38
  * If not provided, the SDK will use the current offering identifier from the cache.
39
+ *
40
+ * @deprecated Prefer passing `offering` when available.
32
41
  */
33
42
  offeringId?: string | null;
34
43
  }
@@ -839,6 +848,25 @@ export default class Purchases {
839
848
  * setting the creative subscriber attribute.
840
849
  */
841
850
  static setCreative(creative: string | null): Promise<void>;
851
+ /**
852
+ * Sets conversion data from AppsFlyer's onInstallConversionData callback. This extracts the
853
+ * relevant attribution fields from the AppsFlyer conversion data and sets the corresponding
854
+ * RevenueCat subscriber attributes ($mediaSource, $campaign, $adGroup, $ad, $keyword, $creative).
855
+ * Note that this method will never unset any attributes.
856
+ *
857
+ * Pass the object received in AppsFlyer's onInstallConversionData listener directly; the nested
858
+ * `data` field holds the conversion data that is forwarded to RevenueCat. The data is only
859
+ * forwarded when `status` is `"success"`; otherwise it is ignored.
860
+ *
861
+ * @param conversionData The object from AppsFlyer's onInstallConversionData callback.
862
+ * @returns {Promise<void>} The promise will be rejected if configure has not been called yet.
863
+ */
864
+ static setAppsFlyerConversionData(conversionData: {
865
+ status: string;
866
+ data: {
867
+ [key: string]: any;
868
+ };
869
+ }): Promise<void>;
842
870
  /**
843
871
  * Overrides the preferred UI locale used by RevenueCat UI components.
844
872
  * Pass null to clear the override and use the device's locale.
@@ -973,8 +1001,10 @@ export default class Purchases {
973
1001
  *
974
1002
  * @param params - Optional parameters for the impression event.
975
1003
  * @param params.paywallId - Optional identifier for the custom paywall being shown.
976
- * @param params.offeringId - Optional identifier for the offering associated with the custom paywall.
977
- * If not provided, the SDK will use the current offering identifier from the cache.
1004
+ * @param params.offering - Optional offering associated with the custom paywall.
1005
+ * @param params.offeringId - Deprecated. Prefer passing `offering` when available.
1006
+ * Optional identifier for the offering associated with the custom paywall. If not provided,
1007
+ * the SDK will use the current offering identifier from the cache.
978
1008
  */
979
1009
  static trackCustomPaywallImpression(params?: TrackCustomPaywallImpressionOptions): Promise<void>;
980
1010
  private static throwIfAndroidPlatform;
package/dist/purchases.js CHANGED
@@ -1711,6 +1711,39 @@ var Purchases = /** @class */ (function () {
1711
1711
  });
1712
1712
  });
1713
1713
  };
1714
+ /**
1715
+ * Sets conversion data from AppsFlyer's onInstallConversionData callback. This extracts the
1716
+ * relevant attribution fields from the AppsFlyer conversion data and sets the corresponding
1717
+ * RevenueCat subscriber attributes ($mediaSource, $campaign, $adGroup, $ad, $keyword, $creative).
1718
+ * Note that this method will never unset any attributes.
1719
+ *
1720
+ * Pass the object received in AppsFlyer's onInstallConversionData listener directly; the nested
1721
+ * `data` field holds the conversion data that is forwarded to RevenueCat. The data is only
1722
+ * forwarded when `status` is `"success"`; otherwise it is ignored.
1723
+ *
1724
+ * @param conversionData The object from AppsFlyer's onInstallConversionData callback.
1725
+ * @returns {Promise<void>} The promise will be rejected if configure has not been called yet.
1726
+ */
1727
+ Purchases.setAppsFlyerConversionData = function (conversionData) {
1728
+ return __awaiter(this, void 0, void 0, function () {
1729
+ var _a;
1730
+ return __generator(this, function (_b) {
1731
+ switch (_b.label) {
1732
+ case 0: return [4 /*yield*/, throwIfNotConfigured()];
1733
+ case 1:
1734
+ _b.sent();
1735
+ if ((conversionData === null || conversionData === void 0 ? void 0 : conversionData.status) !== 'success') {
1736
+ // tslint:disable-next-line:no-console
1737
+ console.warn("[RevenueCat] Ignoring AppsFlyer conversion data with status \"".concat(conversionData === null || conversionData === void 0 ? void 0 : conversionData.status, "\". ") +
1738
+ "Conversion data is only forwarded when status is \"success\".");
1739
+ return [2 /*return*/];
1740
+ }
1741
+ RNPurchases.setAppsFlyerConversionData((_a = conversionData.data) !== null && _a !== void 0 ? _a : null);
1742
+ return [2 /*return*/];
1743
+ }
1744
+ });
1745
+ });
1746
+ };
1714
1747
  /**
1715
1748
  * Overrides the preferred UI locale used by RevenueCat UI components.
1716
1749
  * Pass null to clear the override and use the device's locale.
@@ -2031,17 +2064,28 @@ var Purchases = /** @class */ (function () {
2031
2064
  *
2032
2065
  * @param params - Optional parameters for the impression event.
2033
2066
  * @param params.paywallId - Optional identifier for the custom paywall being shown.
2034
- * @param params.offeringId - Optional identifier for the offering associated with the custom paywall.
2035
- * If not provided, the SDK will use the current offering identifier from the cache.
2067
+ * @param params.offering - Optional offering associated with the custom paywall.
2068
+ * @param params.offeringId - Deprecated. Prefer passing `offering` when available.
2069
+ * Optional identifier for the offering associated with the custom paywall. If not provided,
2070
+ * the SDK will use the current offering identifier from the cache.
2036
2071
  */
2037
2072
  Purchases.trackCustomPaywallImpression = function (params) {
2038
2073
  return __awaiter(this, void 0, void 0, function () {
2039
- return __generator(this, function (_a) {
2040
- switch (_a.label) {
2041
- case 0: return [4 /*yield*/, throwIfNotConfigured()];
2042
- case 1:
2043
- _a.sent();
2044
- RNPurchases.trackCustomPaywallImpression(params !== null && params !== void 0 ? params : {});
2074
+ var options, presentedOfferingContext, offeringId;
2075
+ var _a, _b, _c, _d, _e, _f;
2076
+ return __generator(this, function (_g) {
2077
+ switch (_g.label) {
2078
+ case 0: return [4 /*yield*/, throwIfNotConfigured()];
2079
+ case 1:
2080
+ _g.sent();
2081
+ options = params !== null && params !== void 0 ? params : {};
2082
+ presentedOfferingContext = (_c = (_b = (_a = options.offering) === null || _a === void 0 ? void 0 : _a.availablePackages) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.presentedOfferingContext;
2083
+ offeringId = (_e = (_d = options.offering) === null || _d === void 0 ? void 0 : _d.identifier) !== null && _e !== void 0 ? _e : options.offeringId;
2084
+ RNPurchases.trackCustomPaywallImpression({
2085
+ paywallId: (_f = options.paywallId) !== null && _f !== void 0 ? _f : null,
2086
+ offeringId: offeringId !== null && offeringId !== void 0 ? offeringId : null,
2087
+ presentedOfferingContext: presentedOfferingContext !== null && presentedOfferingContext !== void 0 ? presentedOfferingContext : null,
2088
+ });
2045
2089
  return [2 /*return*/];
2046
2090
  }
2047
2091
  });
package/ios/RNPurchases.m CHANGED
@@ -475,6 +475,10 @@ RCT_EXPORT_METHOD(setCreative:(NSString *)creative) {
475
475
  [RCCommonFunctionality setCreative:creative.mappingNSNullToNil];
476
476
  }
477
477
 
478
+ RCT_EXPORT_METHOD(setAppsFlyerConversionData:(NSDictionary *)data) {
479
+ [RCCommonFunctionality setAppsFlyerConversionData:data.mappingNSNullToNil];
480
+ }
481
+
478
482
  RCT_EXPORT_METHOD(overridePreferredLocale:(nullable NSString *)locale) {
479
483
  [RCCommonFunctionality overridePreferredLocale:locale.mappingNSNullToNil];
480
484
  }
@@ -652,7 +656,8 @@ RCT_EXPORT_METHOD(recordPurchaseForProductID:(nonnull NSString *)productID
652
656
 
653
657
  RCT_EXPORT_METHOD(trackCustomPaywallImpression:(NSDictionary *)data) {
654
658
  if (@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)) {
655
- [RCCommonFunctionality trackCustomPaywallImpression:data];
659
+ NSDictionary *eventData = data.mappingNSNullToNil ?: @{};
660
+ [RCCommonFunctionality trackCustomPaywallImpression:eventData];
656
661
  } else {
657
662
  NSLog(@"[Purchases] Warning: tried to call trackCustomPaywallImpression, but it's only available on iOS 15.0 or greater.");
658
663
  }
@@ -760,7 +765,7 @@ readyForPromotedProduct:(RCStoreProduct *)product
760
765
  }
761
766
 
762
767
  - (NSString *)platformFlavorVersion {
763
- return @"10.3.0";
768
+ return @"10.4.0";
764
769
  }
765
770
 
766
771
  @end
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-purchases",
3
3
  "title": "React Native Purchases",
4
- "version": "10.3.0",
4
+ "version": "10.4.0",
5
5
  "description": "React Native in-app purchases and subscriptions made easy. Supports iOS and Android. ",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -118,7 +118,7 @@
118
118
  ]
119
119
  },
120
120
  "dependencies": {
121
- "@revenuecat/purchases-js-hybrid-mappings": "18.14.1",
122
- "@revenuecat/purchases-typescript-internal": "18.14.1"
121
+ "@revenuecat/purchases-js-hybrid-mappings": "18.15.1",
122
+ "@revenuecat/purchases-typescript-internal": "18.15.1"
123
123
  }
124
124
  }