Skip to content

Commit b6a496d

Browse files
Add support nested object into event meta
1 parent 725ec50 commit b6a496d

File tree

6 files changed

+393
-63
lines changed

6 files changed

+393
-63
lines changed

example/lib/main.dart

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,22 @@ class _MyAppState extends State<MyApp> {
137137
print("log event notification received");
138138
});
139139

140-
// Track call
140+
// Track call with nested objects
141141
response = await userContext.trackEvent("myevent", {
142-
"age": 20,
143-
"doubleValue": 12.12,
144-
"boolValue": false,
145-
"stringValue": "121"
142+
"revenue": 99.99,
143+
"user": {
144+
"id": "user123",
145+
"premium": true,
146+
"tags": ["vip", "loyal"]
147+
},
148+
"items": [
149+
{"name": "Product A", "quantity": 2, "price": 49.99},
150+
{"name": "Product B", "quantity": 1, "price": 50.00}
151+
],
152+
"metadata": {
153+
"source": "mobile_app",
154+
"platform": "ios"
155+
}
146156
});
147157

148158
// To cancel track listener

ios/Classes/HelperClasses/Constants.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,6 @@ struct TypeValue {
139139
static let int = "int"
140140
static let double = "double"
141141
static let bool = "bool"
142+
static let map = "map"
143+
static let list = "list"
142144
}

ios/Classes/HelperClasses/Utils.swift

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,59 @@ public class Utils: NSObject {
2626
}
2727
var typedDictionary = [String: Any]()
2828
for (k,v) in args {
29-
if let typedValue = v as? Dictionary<String, Any?>, let value = typedValue["value"] as? Any, let type = typedValue["type"] as? String {
30-
switch type {
31-
case TypeValue.string:
32-
if let strValue = value as? String {
33-
typedDictionary[k] = strValue
34-
}
35-
break
36-
case TypeValue.int:
37-
if let intValue = value as? Int {
38-
typedDictionary[k] = NSNumber(value: intValue).intValue
39-
}
40-
break
41-
case TypeValue.double:
42-
if let doubleValue = value as? Double {
43-
typedDictionary[k] = NSNumber(value: doubleValue).doubleValue
44-
}
45-
break
46-
case TypeValue.bool:
47-
if let booleanValue = value as? Bool {
48-
typedDictionary[k] = NSNumber(value: booleanValue).boolValue
49-
}
50-
break
51-
default:
52-
break
53-
}
29+
if let processedValue = processTypedValue(v) {
30+
typedDictionary[k] = processedValue
5431
}
55-
continue
5632
}
5733
return typedDictionary
5834
}
35+
36+
/// Recursively processes typed values from Flutter to native Swift types
37+
private static func processTypedValue(_ value: Any?) -> Any? {
38+
guard let typedValue = value as? Dictionary<String, Any?>,
39+
let val = typedValue["value"],
40+
let type = typedValue["type"] as? String else {
41+
return nil
42+
}
43+
44+
switch type {
45+
case TypeValue.string:
46+
return val as? String
47+
case TypeValue.int:
48+
if let intValue = val as? Int {
49+
return NSNumber(value: intValue).intValue
50+
}
51+
return nil
52+
case TypeValue.double:
53+
if let doubleValue = val as? Double {
54+
return NSNumber(value: doubleValue).doubleValue
55+
}
56+
return nil
57+
case TypeValue.bool:
58+
if let booleanValue = val as? Bool {
59+
return NSNumber(value: booleanValue).boolValue
60+
}
61+
return nil
62+
case TypeValue.map:
63+
guard let nestedMap = val as? Dictionary<String, Any?> else {
64+
return nil
65+
}
66+
var result = [String: Any]()
67+
for (k, v) in nestedMap {
68+
if let processedValue = processTypedValue(v) {
69+
result[k] = processedValue
70+
}
71+
}
72+
return result
73+
case TypeValue.list:
74+
guard let nestedArray = val as? [Any?] else {
75+
return nil
76+
}
77+
return nestedArray.compactMap { processTypedValue($0) }
78+
default:
79+
return nil
80+
}
81+
}
5982

6083
/// Returns callback required for LogEventListener
6184
static func getLogEventCallback(id: Int, sdkKey: String) -> LogEventListener {

lib/src/utils/constants.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class Constants {
2020
static const String intType = "int";
2121
static const String doubleType = "double";
2222
static const String boolType = "bool";
23+
static const String mapType = "map";
24+
static const String listType = "list";
2325

2426
// Supported Method Names
2527
static const String initializeMethod = "initialize";

lib/src/utils/utils.dart

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,40 +43,11 @@ class Utils {
4343
// Only keep primitive values
4444
Map<String, dynamic> primitiveMap = {};
4545
for (MapEntry e in map.entries) {
46-
if (e.value is String) {
46+
dynamic processedValue = _processValue(e.value);
47+
if (processedValue != null) {
4748
primitiveMap[e.key] = e.value;
48-
typedMap[e.key] = {
49-
Constants.value: e.value,
50-
Constants.type: Constants.stringType
51-
};
52-
continue;
49+
typedMap[e.key] = processedValue;
5350
}
54-
if (e.value is double) {
55-
primitiveMap[e.key] = e.value;
56-
typedMap[e.key] = {
57-
Constants.value: e.value,
58-
Constants.type: Constants.doubleType
59-
};
60-
continue;
61-
}
62-
if (e.value is int) {
63-
primitiveMap[e.key] = e.value;
64-
typedMap[e.key] = {
65-
Constants.value: e.value,
66-
Constants.type: Constants.intType
67-
};
68-
continue;
69-
}
70-
if (e.value is bool) {
71-
primitiveMap[e.key] = e.value;
72-
typedMap[e.key] = {
73-
Constants.value: e.value,
74-
Constants.type: Constants.boolType
75-
};
76-
continue;
77-
}
78-
// ignore: avoid_print
79-
print('Unsupported value type for key: ${e.key}.');
8051
}
8152

8253
if (Platform.isIOS) {
@@ -85,6 +56,65 @@ class Utils {
8556
return primitiveMap;
8657
}
8758

59+
/// Recursively processes values to add type information for iOS
60+
static dynamic _processValue(dynamic value) {
61+
if (value is String) {
62+
return {
63+
Constants.value: value,
64+
Constants.type: Constants.stringType
65+
};
66+
}
67+
if (value is double) {
68+
return {
69+
Constants.value: value,
70+
Constants.type: Constants.doubleType
71+
};
72+
}
73+
if (value is int) {
74+
return {
75+
Constants.value: value,
76+
Constants.type: Constants.intType
77+
};
78+
}
79+
if (value is bool) {
80+
return {
81+
Constants.value: value,
82+
Constants.type: Constants.boolType
83+
};
84+
}
85+
if (value is Map) {
86+
// Handle nested maps
87+
Map<String, dynamic> nestedMap = {};
88+
(value as Map).forEach((k, v) {
89+
dynamic processedValue = _processValue(v);
90+
if (processedValue != null) {
91+
nestedMap[k.toString()] = processedValue;
92+
}
93+
});
94+
return {
95+
Constants.value: nestedMap,
96+
Constants.type: Constants.mapType
97+
};
98+
}
99+
if (value is List) {
100+
// Handle arrays
101+
List<dynamic> nestedList = [];
102+
for (var item in value) {
103+
dynamic processedValue = _processValue(item);
104+
if (processedValue != null) {
105+
nestedList.add(processedValue);
106+
}
107+
}
108+
return {
109+
Constants.value: nestedList,
110+
Constants.type: Constants.listType
111+
};
112+
}
113+
// ignore: avoid_print
114+
print('Unsupported value type: ${value.runtimeType}');
115+
return null;
116+
}
117+
88118
static List<String> convertDecideOptions(
89119
Set<OptimizelyDecideOption> options) {
90120
return options.map((option) => Utils.decideOptions[option]!).toList();

0 commit comments

Comments
 (0)