@appmetrica/react-native-analytics 3.0.0 → 3.2.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 (42) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/io/appmetrica/analytics/reactnative/AppMetricaModule.java +16 -1
  3. package/android/src/main/java/io/appmetrica/analytics/reactnative/UserProfileSerializer.java +257 -0
  4. package/android/src/main/java/io/appmetrica/analytics/reactnative/Utils.java +18 -0
  5. package/appmetrica-react-native-analytics.podspec +1 -1
  6. package/ios/AMARNAppMetrica.m +11 -0
  7. package/ios/AMARNAppMetricaUtils.h +2 -0
  8. package/ios/AMARNAppMetricaUtils.m +26 -12
  9. package/ios/AMARNUserProfileSerializer.h +6 -0
  10. package/ios/AMARNUserProfileSerializer.m +182 -0
  11. package/lib/commonjs/ecommerce.js +10 -9
  12. package/lib/commonjs/ecommerce.js.map +1 -1
  13. package/lib/commonjs/index.js +20 -1
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/userProfile.js +283 -0
  16. package/lib/commonjs/userProfile.js.map +1 -0
  17. package/lib/commonjs/utils.js +72 -0
  18. package/lib/commonjs/utils.js.map +1 -0
  19. package/lib/module/ecommerce.js +10 -9
  20. package/lib/module/ecommerce.js.map +1 -1
  21. package/lib/module/index.js +9 -1
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/userProfile.js +267 -0
  24. package/lib/module/userProfile.js.map +1 -0
  25. package/lib/module/utils.js +61 -0
  26. package/lib/module/utils.js.map +1 -0
  27. package/lib/typescript/src/ecommerce.d.ts +3 -3
  28. package/lib/typescript/src/ecommerce.d.ts.map +1 -1
  29. package/lib/typescript/src/index.d.ts +7 -1
  30. package/lib/typescript/src/index.d.ts.map +1 -1
  31. package/lib/typescript/src/revenue.d.ts +1 -1
  32. package/lib/typescript/src/revenue.d.ts.map +1 -1
  33. package/lib/typescript/src/userProfile.d.ts +84 -0
  34. package/lib/typescript/src/userProfile.d.ts.map +1 -0
  35. package/lib/typescript/src/utils.d.ts +9 -0
  36. package/lib/typescript/src/utils.d.ts.map +1 -0
  37. package/package.json +1 -1
  38. package/src/ecommerce.ts +20 -12
  39. package/src/index.ts +16 -2
  40. package/src/revenue.ts +1 -1
  41. package/src/userProfile.ts +362 -0
  42. package/src/utils.ts +71 -0
@@ -85,5 +85,5 @@ dependencies {
85
85
  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
86
86
  //noinspection GradleDynamicVersion
87
87
  implementation "com.facebook.react:react-native:+"
88
- implementation "io.appmetrica.analytics:analytics:6.5.0"
88
+ implementation "io.appmetrica.analytics:analytics:7.2.0"
89
89
  }
@@ -11,6 +11,7 @@ import com.facebook.react.bridge.ReactMethod;
11
11
  import com.facebook.react.bridge.ReadableArray;
12
12
  import com.facebook.react.bridge.ReadableMap;
13
13
  import com.facebook.react.module.annotations.ReactModule;
14
+
14
15
  import io.appmetrica.analytics.AppMetrica;
15
16
  import io.appmetrica.analytics.AppMetricaConfig;
16
17
  import io.appmetrica.analytics.ecommerce.ECommerceEvent;
@@ -39,7 +40,7 @@ public class AppMetricaModule extends ReactContextBaseJavaModule {
39
40
  public void activate(ReadableMap configMap) {
40
41
  AppMetricaConfig config = Utils.toAppMetricaConfig(configMap);
41
42
  AppMetrica.activate(reactContext, config);
42
- if (Boolean.TRUE.equals(config.sessionsAutoTrackingEnabled)) {
43
+ if (!Boolean.FALSE.equals(config.sessionsAutoTrackingEnabled)) {
43
44
  AppMetrica.resumeSession(getCurrentActivity());
44
45
  }
45
46
  }
@@ -136,4 +137,18 @@ public class AppMetricaModule extends ReactContextBaseJavaModule {
136
137
  public void reportAdRevenue(ReadableMap revenue) {
137
138
  AppMetrica.reportAdRevenue(Utils.toAdRevenue(revenue));
138
139
  }
140
+
141
+ @ReactMethod
142
+ public void reportUserProfile(ReadableMap userProfile) {
143
+ try {
144
+ AppMetrica.reportUserProfile(Utils.toUserProfile(userProfile));
145
+ } catch (Throwable e) {
146
+ Log.w(TAG, "Cannot parse user profile", e);
147
+ }
148
+ }
149
+
150
+ @ReactMethod
151
+ public void putErrorEnvironmentValue(String key, String value) {
152
+ AppMetrica.putErrorEnvironmentValue(key, value);
153
+ }
139
154
  }
@@ -0,0 +1,257 @@
1
+ package io.appmetrica.analytics.reactnative;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.bridge.ReadableArray;
6
+ import com.facebook.react.bridge.ReadableMap;
7
+
8
+ import io.appmetrica.analytics.profile.Attribute;
9
+ import io.appmetrica.analytics.profile.BirthDateAttribute;
10
+ import io.appmetrica.analytics.profile.BooleanAttribute;
11
+ import io.appmetrica.analytics.profile.CounterAttribute;
12
+ import io.appmetrica.analytics.profile.GenderAttribute;
13
+ import io.appmetrica.analytics.profile.NameAttribute;
14
+ import io.appmetrica.analytics.profile.NotificationsEnabledAttribute;
15
+ import io.appmetrica.analytics.profile.NumberAttribute;
16
+ import io.appmetrica.analytics.profile.StringAttribute;
17
+ import io.appmetrica.analytics.profile.UserProfile;
18
+ import io.appmetrica.analytics.profile.UserProfileUpdate;
19
+
20
+ final class UserProfileSerializer {
21
+ private UserProfileSerializer() {}
22
+
23
+ @NonNull
24
+ public static UserProfile fromReadableMap(@NonNull ReadableMap profileMap){
25
+
26
+ ReadableArray attributes = profileMap.getArray("attributes");
27
+ if (attributes == null) {
28
+ throw new IllegalArgumentException();
29
+ }
30
+ UserProfile.Builder builder = UserProfile.newBuilder();
31
+
32
+ for (int idx = 0; idx < attributes.size(); idx++) {
33
+
34
+ ReadableMap attribute = attributes.getMap(idx);
35
+ if (attribute != null) {
36
+ builder.apply(parseUserProfileUpdate(attribute));
37
+ }
38
+ }
39
+
40
+ return builder.build();
41
+ }
42
+
43
+ @NonNull
44
+ private static UserProfileUpdate<?> parseUserProfileUpdate(@NonNull ReadableMap map){
45
+ String type = map.getString("type");
46
+
47
+ if (type == null) {
48
+ throw new IllegalArgumentException("Type should not be null");
49
+ }
50
+
51
+ if (type.startsWith("BirthDate")) {
52
+ return parseBirthDate(type, map);
53
+ }
54
+ if (type.startsWith("Boolean")) {
55
+ return parseBoolean(type, map);
56
+ }
57
+ if (type.startsWith("Counter")) {
58
+ return parseCounter(type, map);
59
+ }
60
+ if (type.startsWith("Gender")) {
61
+ return parseGender(type, map);
62
+ }
63
+ if (type.startsWith("Name")) {
64
+ return parseName(type, map);
65
+ }
66
+ if (type.startsWith("NotificationsEnabled")) {
67
+ return parseNotificationsEnabled(type, map);
68
+ }
69
+ if (type.startsWith("Number")) {
70
+ return parseNumber(type, map);
71
+ }
72
+ if (type.startsWith("String")) {
73
+ return parseString(type, map);
74
+ }
75
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
76
+ }
77
+
78
+ @NonNull
79
+ private static UserProfileUpdate<?> parseBirthDate(@NonNull String type, @NonNull ReadableMap map) {
80
+ BirthDateAttribute att = Attribute.birthDate();
81
+ switch (type) {
82
+ case "BirthDateWithAge": {
83
+ int age = map.getInt("age");
84
+ boolean ifUndefined = map.getBoolean("ifUndefined");
85
+ return ifUndefined ? att.withAgeIfUndefined(age) : att.withAge(age);
86
+ }
87
+ case "BirthDateWithYear": {
88
+ int year = map.getInt("year");
89
+ boolean ifUndefined = map.getBoolean("ifUndefined");
90
+ return ifUndefined ? att.withBirthDateIfUndefined(year) : att.withBirthDate(year);
91
+ }
92
+ case "BirthDateWithMonth": {
93
+ int year = map.getInt("year");
94
+ int month = map.getInt("month");
95
+ boolean ifUndefined = map.getBoolean("ifUndefined");
96
+ return ifUndefined ? att.withBirthDateIfUndefined(year, month) : att.withBirthDate(year, month);
97
+ }
98
+ case "BirthDateWithDay": {
99
+ int year = map.getInt("year");
100
+ int month = map.getInt("month");
101
+ int days = map.getInt("day");
102
+ boolean ifUndefined = map.getBoolean("ifUndefined");
103
+ return ifUndefined ? att.withBirthDateIfUndefined(year, month, days) : att.withBirthDate(year, month, days);
104
+ }
105
+ case "BirthDateValueReset": {
106
+ return att.withValueReset();
107
+ }
108
+ }
109
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
110
+ }
111
+
112
+ @NonNull
113
+ private static UserProfileUpdate<?> parseBoolean(@NonNull String type, @NonNull ReadableMap map) {
114
+ String key = map.getString("key");
115
+ if (key == null) {
116
+ throw new IllegalArgumentException("Key should not be null");
117
+ }
118
+ BooleanAttribute att = Attribute.customBoolean(key);
119
+ switch (type) {
120
+ case "BooleanValue": {
121
+ boolean value = map.getBoolean("value");
122
+ boolean ifUndefined = map.getBoolean("ifUndefined");
123
+ return ifUndefined ? att.withValueIfUndefined(value) : att.withValue(value);
124
+ }
125
+ case "BooleanValueReset": {
126
+ return att.withValueReset();
127
+ }
128
+ }
129
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
130
+ }
131
+
132
+ @NonNull
133
+ private static UserProfileUpdate<?> parseCounter(@NonNull String type, @NonNull ReadableMap map) {
134
+ String key = map.getString("key");
135
+ if (key == null) {
136
+ throw new IllegalArgumentException("Key should not be null");
137
+ }
138
+ CounterAttribute att = Attribute.customCounter(key);
139
+ if (type.equals("Counter")) {
140
+ double delta = map.getDouble("delta");
141
+ return att.withDelta(delta);
142
+ }
143
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
144
+ }
145
+
146
+ @NonNull
147
+ private static UserProfileUpdate<?> parseGender(@NonNull String type, @NonNull ReadableMap map) {
148
+ GenderAttribute att = Attribute.gender();
149
+ // BirthDate
150
+ switch (type) {
151
+ case "GenderValue": {
152
+ String value = map.getString("value");
153
+ if (value == null) {
154
+ throw new IllegalArgumentException("Value should not be null");
155
+ }
156
+
157
+ GenderAttribute.Gender gender = getGender(value);
158
+ boolean ifUndefined = map.getBoolean("ifUndefined");
159
+ return ifUndefined ? att.withValueIfUndefined(gender) : att.withValue(gender);
160
+ }
161
+ case "GenderValueReset": {
162
+ return att.withValueReset();
163
+ }
164
+ }
165
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
166
+ }
167
+
168
+ @NonNull
169
+ private static GenderAttribute.Gender getGender(@NonNull String value) {
170
+ switch (value) {
171
+ case "female":
172
+ return GenderAttribute.Gender.FEMALE;
173
+ case "male":
174
+ return GenderAttribute.Gender.MALE;
175
+ default:
176
+ return GenderAttribute.Gender.OTHER;
177
+ }
178
+ }
179
+
180
+ @NonNull
181
+ private static UserProfileUpdate<?> parseName(@NonNull String type, @NonNull ReadableMap map) {
182
+ NameAttribute att = Attribute.name();
183
+ switch (type) {
184
+ case "NameValue": {
185
+ String value = map.getString("value");
186
+ if (value == null) {
187
+ throw new IllegalArgumentException("Value should not be null");
188
+ }
189
+ boolean ifUndefined = map.getBoolean("ifUndefined");
190
+ return ifUndefined ? att.withValueIfUndefined(value) : att.withValue(value);
191
+ }
192
+ case "NameValueReset": {
193
+ return att.withValueReset();
194
+ }
195
+ }
196
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
197
+ }
198
+
199
+ @NonNull
200
+ private static UserProfileUpdate<?> parseNotificationsEnabled(@NonNull String type, @NonNull ReadableMap map) {
201
+ NotificationsEnabledAttribute att = Attribute.notificationsEnabled();
202
+ switch (type) {
203
+ case "NotificationsEnabledValue": {
204
+ boolean value = map.getBoolean("value");
205
+ boolean ifUndefined = map.getBoolean("ifUndefined");
206
+ return ifUndefined ? att.withValueIfUndefined(value) : att.withValue(value);
207
+ }
208
+ case "NotificationsEnabledValueReset": {
209
+ return att.withValueReset();
210
+ }
211
+ }
212
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
213
+ }
214
+
215
+ @NonNull
216
+ private static UserProfileUpdate<?> parseNumber(@NonNull String type, @NonNull ReadableMap map) {
217
+ String key = map.getString("key");
218
+ if (key == null) {
219
+ throw new IllegalArgumentException("Key should not be null");
220
+ }
221
+ NumberAttribute att = Attribute.customNumber(key);
222
+ switch (type) {
223
+ case "NumberValue": {
224
+ double value = map.getDouble("value");
225
+ boolean ifUndefined = map.getBoolean("ifUndefined");
226
+ return ifUndefined ? att.withValueIfUndefined(value) : att.withValue(value);
227
+ }
228
+ case "NumberValueReset": {
229
+ return att.withValueReset();
230
+ }
231
+ }
232
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
233
+ }
234
+
235
+ @NonNull
236
+ private static UserProfileUpdate<?> parseString(@NonNull String type, @NonNull ReadableMap map) {
237
+ String key = map.getString("key");
238
+ if (key == null) {
239
+ throw new IllegalArgumentException("Key should not be null");
240
+ }
241
+ StringAttribute att = Attribute.customString(key);
242
+ switch (type) {
243
+ case "StringValue": {
244
+ String value = map.getString("value");
245
+ if (value == null) {
246
+ throw new IllegalArgumentException("Value should not be null");
247
+ }
248
+ boolean ifUndefined = map.getBoolean("ifUndefined");
249
+ return ifUndefined ? att.withValueIfUndefined(value) : att.withValue(value);
250
+ }
251
+ case "StringValueReset": {
252
+ return att.withValueReset();
253
+ }
254
+ }
255
+ throw new IllegalArgumentException("Unknown UserProfile type " + type);
256
+ }
257
+ }
@@ -13,6 +13,7 @@ import io.appmetrica.analytics.AppMetricaConfig;
13
13
  import io.appmetrica.analytics.PreloadInfo;
14
14
  import io.appmetrica.analytics.Revenue;
15
15
  import io.appmetrica.analytics.StartupParamsCallback;
16
+ import io.appmetrica.analytics.profile.UserProfile;
16
17
  import io.appmetrica.analytics.ecommerce.ECommerceAmount;
17
18
  import io.appmetrica.analytics.ecommerce.ECommerceCartItem;
18
19
  import io.appmetrica.analytics.ecommerce.ECommerceEvent;
@@ -71,6 +72,18 @@ abstract class Utils {
71
72
  if (configMap.hasKey("sessionsAutoTracking")) {
72
73
  builder.withSessionsAutoTrackingEnabled(configMap.getBoolean("sessionsAutoTracking"));
73
74
  }
75
+ if (configMap.hasKey("userProfileID")) {
76
+ builder.withUserProfileID(configMap.getString("userProfileID"));
77
+ }
78
+ if (configMap.hasKey("errorEnvironment")) {
79
+ ReadableMap errorEnvironmentMap = configMap.getMap("errorEnvironment");
80
+ if (errorEnvironmentMap != null) {
81
+ for (Map.Entry<String, Object> entry : errorEnvironmentMap.toHashMap().entrySet()) {
82
+ Object value = entry.getValue();
83
+ builder.withErrorEnvironmentValue(entry.getKey(), value == null ? null : value.toString());
84
+ }
85
+ }
86
+ }
74
87
 
75
88
  return builder.build();
76
89
  }
@@ -454,6 +467,11 @@ abstract class Utils {
454
467
  }
455
468
  }
456
469
 
470
+ @NonNull
471
+ static UserProfile toUserProfile(ReadableMap userProfileMap) {
472
+ return UserProfileSerializer.fromReadableMap(userProfileMap);
473
+ }
474
+
457
475
  @Nullable
458
476
  private static Map<String, String> toMapOfStrings(@Nullable ReadableMap oldMap) {
459
477
  if (oldMap == null) {
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm}"
18
18
 
19
- s.dependency "AppMetricaAnalytics", "5.4.0"
19
+ s.dependency "AppMetricaAnalytics", "5.8.0"
20
20
 
21
21
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
22
22
  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
@@ -2,6 +2,7 @@
2
2
  #import "AMARNAppMetrica.h"
3
3
  #import "AMARNAppMetricaUtils.h"
4
4
  #import "AMARNStartupParamsUtils.h"
5
+ #import "AMARNUserProfileSerializer.h"
5
6
  #import <AppMetricaCrashes/AppMetricaCrashes.h>
6
7
 
7
8
  @implementation AMARNAppMetrica
@@ -109,6 +110,16 @@ RCT_EXPORT_METHOD(reportAdRevenue:(NSDictionary *)revenueDict)
109
110
  [AMAAppMetrica reportAdRevenue:[AMARNAppMetricaUtils adRevenueForDict:revenueDict] onFailure:nil];
110
111
  }
111
112
 
113
+ RCT_EXPORT_METHOD(reportUserProfile:(NSDictionary *)userProfileDict)
114
+ {
115
+ [AMAAppMetrica reportUserProfile:[AMARNAppMetricaUtils userProfileForDict:userProfileDict] onFailure:nil];
116
+ }
117
+
118
+ RCT_EXPORT_METHOD(putErrorEnvironmentValue:(NSString *)key:(NSString *)value)
119
+ {
120
+ [[AMAAppMetricaCrashes crashes] setErrorEnvironmentValue:value forKey:key];
121
+ }
122
+
112
123
  - (NSObject *)wrap:(NSObject *)value
113
124
  {
114
125
  if (value == nil) {
@@ -2,6 +2,7 @@
2
2
  #import <CoreLocation/CoreLocation.h>
3
3
  #import <AppMetricaCore/AppMetricaCore.h>
4
4
  #import <AppMetricaCrashes/AppMetricaCrashes.h>
5
+ #import "AMARNUserProfileSerializer.h"
5
6
 
6
7
  @interface AMARNAppMetricaUtils : NSObject
7
8
 
@@ -20,5 +21,6 @@
20
21
  + (AMAAdRevenueInfo *)adRevenueForDict:(NSDictionary *)revenueDict;
21
22
  + (AMAAdType)toAdType:(NSString *)type;
22
23
  + (NSDictionary *)convertRevenueInfoPayload:(NSString *)payload;
24
+ + (AMAUserProfile *)userProfileForDict:(NSDictionary *)userProfileDict;
23
25
 
24
26
  @end
@@ -40,6 +40,9 @@
40
40
  if (configDict[@"maxReportsInDatabaseCount"] != nil) {
41
41
  configuration.maxReportsInDatabaseCount = [configDict[@"maxReportsInDatabaseCount"] unsignedIntegerValue];
42
42
  }
43
+ if (configDict[@"userProfileID"] != nil) {
44
+ configuration.userProfileID = configDict[@"userProfileID"];
45
+ }
43
46
 
44
47
  return configuration;
45
48
  }
@@ -50,6 +53,12 @@
50
53
  if (crashConfigDict[@"crashReporting"] != nil) {
51
54
  crashesConfiguration.autoCrashTracking = [crashConfigDict[@"crashReporting"] boolValue];
52
55
  }
56
+ if (crashConfigDict[@"errorEnvironment"] != nil) {
57
+ NSDictionary *errorEnvironmentDict = crashConfigDict[@"errorEnvironment"];
58
+ for (NSString *key in errorEnvironmentDict) {
59
+ [[AMAAppMetricaCrashes crashes] setErrorEnvironmentValue:errorEnvironmentDict[key] forKey:key];
60
+ }
61
+ }
53
62
  return crashesConfiguration;
54
63
  }
55
64
 
@@ -113,7 +122,7 @@
113
122
  categoryComponents:categoriesPath
114
123
  searchQuery:searchQuery
115
124
  payload:payload];
116
-
125
+
117
126
  return screen;
118
127
  }
119
128
 
@@ -124,16 +133,16 @@
124
133
  }
125
134
  AMAECommerceAmount *amount = [self ecommerceAmountForDict:ecommercePriceDict[@"amount"]];
126
135
  NSArray *componentsArray = ecommercePriceDict[@"internalComponents"];
127
-
136
+
128
137
  NSMutableArray *components = [[NSMutableArray alloc] init];
129
138
 
130
139
  for (NSDictionary *item in componentsArray) {
131
140
  [components addObject:[self ecommerceAmountForDict:item]];
132
141
  }
133
-
142
+
134
143
  AMAECommercePrice *price = [[AMAECommercePrice alloc] initWithFiat:amount
135
144
  internalComponents:components];
136
-
145
+
137
146
  return price;
138
147
  }
139
148
 
@@ -145,7 +154,7 @@
145
154
  NSString *type = ecommerceReferrerDict[@"type"];
146
155
  NSString *identifier = ecommerceReferrerDict[@"identifier"];
147
156
  AMAECommerceScreen *screen = [self ecommerceScreenForDict:ecommerceReferrerDict[@"screen"]];
148
-
157
+
149
158
  AMAECommerceReferrer *referrer = [[AMAECommerceReferrer alloc] initWithType:type
150
159
  identifier:identifier
151
160
  screen:screen];
@@ -164,7 +173,7 @@
164
173
  NSDictionary *payload = ecommerceProductDict[@"payload"];
165
174
  AMAECommercePrice *actualPrice = [self ecommercePriceForDict:ecommerceProductDict[@"actualPrice"]];
166
175
  AMAECommercePrice *originalPrice = [self ecommercePriceForDict:ecommerceProductDict[@"originalPrice"]];
167
-
176
+
168
177
  AMAECommerceProduct *product = [[AMAECommerceProduct alloc] initWithSKU:sku
169
178
  name:name
170
179
  categoryComponents:categoriesPath
@@ -184,7 +193,7 @@
184
193
  AMAECommercePrice *price = [self ecommercePriceForDict:ecommerceCartItemDict[@"price"]];
185
194
  NSDecimalNumber *quantity = [NSDecimalNumber decimalNumberWithDecimal:[ecommerceCartItemDict[@"quantity"] decimalValue]];
186
195
  AMAECommerceReferrer *referrer = [self ecommerceReferrerForDict:ecommerceCartItemDict[@"referrer"]];
187
-
196
+
188
197
  AMAECommerceCartItem *items = [[AMAECommerceCartItem alloc] initWithProduct:product quantity:quantity revenue:price referrer:referrer];
189
198
  return items;
190
199
  }
@@ -202,7 +211,7 @@
202
211
  for (NSDictionary *item in cartItemsArrayDict) {
203
212
  [cartItems addObject:[self ecommerceCartItemForDict:item]];
204
213
  }
205
-
214
+
206
215
  AMAECommerceOrder *order = [[AMAECommerceOrder alloc] initWithIdentifier:orderId cartItems:cartItems payload:payload];
207
216
  return order;
208
217
  }
@@ -212,7 +221,7 @@
212
221
  if (ecommerceAmountDict == nil) {
213
222
  return nil;
214
223
  }
215
-
224
+
216
225
  NSString *unit = ecommerceAmountDict[@"unit"];
217
226
  NSDecimalNumber *value = [NSDecimalNumber decimalNumberWithDecimal:[ecommerceAmountDict[@"amount"] decimalValue]];
218
227
  AMAECommerceAmount *amount = [[AMAECommerceAmount alloc] initWithUnit:unit value:value];
@@ -251,7 +260,7 @@
251
260
  if ([type isEqualToString:@"removeCartItemEvent"]) {
252
261
  AMAECommerceCartItem *item = [self ecommerceCartItemForDict:ecommerceDict[@"cartItem"]];
253
262
  AMAECommerce *event = [AMAECommerce removeCartItemEventWithItem:item];
254
-
263
+
255
264
  return event;
256
265
  }
257
266
  if ([type isEqualToString:@"beginCheckoutEvent"]) {
@@ -267,7 +276,7 @@
267
276
  return nil;
268
277
  }
269
278
 
270
- + (AMARevenueInfo *)revenueForDict:(NSDictionary *)revenueDict
279
+ + (AMARevenueInfo *)revenueForDict:(NSDictionary *)revenueDict
271
280
  {
272
281
  NSNumber *number = revenueDict[@"price"];
273
282
  NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithDecimal:number.decimalValue];
@@ -294,7 +303,7 @@
294
303
  return revenueInfo;
295
304
  }
296
305
 
297
- + (AMAAdRevenueInfo *)adRevenueForDict:(NSDictionary *)revenueDict
306
+ + (AMAAdRevenueInfo *)adRevenueForDict:(NSDictionary *)revenueDict
298
307
  {
299
308
  NSNumber *number = revenueDict[@"price"];
300
309
  NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithDecimal:number.decimalValue];
@@ -365,4 +374,9 @@
365
374
  }
366
375
  }
367
376
 
377
+ + (AMAUserProfile *)userProfileForDict:(NSDictionary *)userProfileDict
378
+ {
379
+ return amarn_deserializeUserProfile(userProfileDict);
380
+ }
381
+
368
382
  @end
@@ -0,0 +1,6 @@
1
+
2
+ #import <AppMetricaCore/AppMetricaCore.h>
3
+
4
+ @class AMAUserProfile;
5
+
6
+ AMAUserProfile *amarn_deserializeUserProfile(NSDictionary *dictionary);