diff --git a/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift b/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift index 5018618..7c52c33 100644 --- a/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift +++ b/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift @@ -5,7 +5,11 @@ import FirebaseAnalytics // MARK: - Protocol protocol AnalyticsManagerProtocol { - func logScreen(name: String, path: String) + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) func logEvent( name: String, action: String, @@ -17,11 +21,27 @@ protocol AnalyticsManagerProtocol { // MARK: - Firebase class FirebaseAnalyticsManager: AnalyticsManagerProtocol { - func logScreen(name: String, path: String) { + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { let parameters = [ AnalyticsParameterScreenName: name as NSObject ] + if let supplementaryParameters = params { + for (newKey, newValue) in supplementaryParameters { + if parameters.contains(where: { (key: String, value: NSObject) in + key == newKey + }) { + continue + } + + parameters[newKey] = newValue as? NSObject + } + } + Analytics.logEvent( AnalyticsEventScreenView, parameters: parameters @@ -80,11 +100,19 @@ class AnalyticsManager { managers.append(FirebaseAnalyticsManager()) } - private func logScreen(name: String, path: String) { + private func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard isEnabled else { return } managers.forEach { manager in - manager.logScreen(name: name, path: path) + manager.logScreen( + name: name, + path: path, + params: params + ) } } @@ -108,31 +136,39 @@ class AnalyticsManager { // MARK: - section_one - func logScreenS1DefOne(title: String) { - logScreen( + static func logScreenS1DefOne(title: String, test2: String = "test") { + AnalyticsManager.shared.logScreen( name: "s1 def one \(title)", - path: "" + path: "", + params: ["test2": test2] ) } - func logEventS1DefTwo(title: String, count: String) { - logEvent( + static func logEventS1DefTwo( + title: String, + count: String, + test2: String = "test" + ) { + AnalyticsManager.shared.logEvent( name: "s1 def two", action: "test", category: "test", params: [ "title": title, - "count": count + "count": count, + "test": "test", + "test2": test2 ] ) } // MARK: - section_two - func logScreenS2DefOne() { - logScreen( + static func logScreenS2DefOne() { + AnalyticsManager.shared.logScreen( name: "s2 def one", - path: "" + path: "", + params: nil ) } } diff --git a/SampleFiles/Tags/sampleTags.yml b/SampleFiles/Tags/sampleTags.yml index 4c91dd0..ce71f05 100644 --- a/SampleFiles/Tags/sampleTags.yml +++ b/SampleFiles/Tags/sampleTags.yml @@ -10,6 +10,13 @@ categories: - name: title type: String replaceIn: name,path + - name: test + type: String + value: test + replaceIn: name,path + - name: test2 + type: String + defaultValue: test events: - id: s1_def_two @@ -22,6 +29,12 @@ categories: type: String - name: count type: String + - name: test + type: String + value: test + - name: test2 + type: String + defaultValue: test - id: section_two screens: diff --git a/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift index 02973c6..36d34c4 100644 --- a/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift @@ -103,11 +103,19 @@ class AnalyticsGenerator { private static func getPrivateLogFunction() -> String { """ - private func logScreen(name: String, path: String) { + private func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard isEnabled else { return } managers.forEach { manager in - manager.logScreen(name: name, path: path) + manager.logScreen( + name: name, + path: path, + params: params + ) } } @@ -169,7 +177,11 @@ class AnalyticsGenerator { // MARK: - Protocol protocol AnalyticsManagerProtocol { - func logScreen(name: String, path: String) + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) func logEvent( name: String, action: String, diff --git a/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift index 5c54aca..e8a97fc 100644 --- a/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift @@ -31,11 +31,31 @@ enum FirebaseGenerator { private static var logScreen: String { """ - func logScreen(name: String, path: String) { - let parameters = [ + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { + var parameters = [ AnalyticsParameterScreenName: name as NSObject ] + if path.isEmpty == false { + parameters["path"] = path + "/iOS" as NSObject + } + + if let supplementaryParameters = params { + for (newKey, newValue) in supplementaryParameters { + if parameters.contains(where: { (key: String, value: NSObject) in + key == newKey + }) { + continue + } + + parameters[newKey] = newValue as? NSObject + } + } + Analytics.logEvent( AnalyticsEventScreenView, parameters: parameters @@ -54,10 +74,16 @@ enum FirebaseGenerator { params: [String: Any]? ) { var parameters: [String:NSObject] = [ - AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject, - AnalyticsParameterItemCategory: category as NSObject, - "action": action as NSObject, + AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject ] + + if category.isEmpty == false { + parameters["AnalyticsParameterItemCategory"] = category as NSObject + } + + if action.isEmpty == false { + parameters["action"] = action as NSObject + } if let supplementaryParameters = params { for (newKey, newValue) in supplementaryParameters { diff --git a/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift index 740cf95..cd789ca 100644 --- a/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift @@ -66,7 +66,11 @@ enum MatomoGenerator { private static var logScreen: String { """ - func logScreen(name: String, path: String) { + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard !tracker.isOptedOut else { return } guard let trackerUrl = tracker.contentBase?.absoluteString else { return } diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift index 35b63d9..002c4b4 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift @@ -51,14 +51,21 @@ class AnalyticsDefinition { var params = parameters var result: String - if type == .screen { - params = params.filter { param in - !param.replaceIn.isEmpty + let paramsString = params.compactMap { parameter -> String? in + guard parameter.value.isEmpty else { return nil } + + let defaultValue: String + switch parameter.type { + case .bool: + defaultValue = "\(parameter.defaultValue.lowercased())" + case .int, .double: + defaultValue = "\(parameter.defaultValue)" + case .string: + defaultValue = "\"\(parameter.defaultValue)\"" } - } - - let paramsString = params.map { parameter in - "\(parameter.name): \(parameter.type)" + + let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)" + return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)" } if paramsString.count > 2 { @@ -84,7 +91,10 @@ class AnalyticsDefinition { case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") - default: break + default: + if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false { + param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") + } } } } @@ -99,7 +109,18 @@ class AnalyticsDefinition { } supplementaryParams.forEach { param in - params.append("\"\(param.name)\": \(param.name)") + if param.value.isEmpty { + params.append("\"\(param.name)\": \(param.name)") + } else { + switch param.type { + case .bool: + params.append("\"\(param.name)\": \(param.value.lowercased())") + case .int, .double: + params.append("\"\(param.name)\": \(param.value)") + case .string: + params.append("\"\(param.name)\": \"\(param.value)\"") + } + } } if params.count > 1 { @@ -113,14 +134,15 @@ class AnalyticsDefinition { [\(params.joined(separator: ", "))] """ } else { - result = "[:]" + result = "nil" } if type == .screen { return """ logScreen( name: "\(name)", - path: "\(path)" + path: "\(path)", + params: \(result) ) """ } else { diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift index d775768..26b9122 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift @@ -41,5 +41,7 @@ struct AnalyticsDefinitionEventDTO: Codable { struct AnalyticsParameterDTO: Codable { var name: String var type: String + var value: String? + var defaultValue: String? var replaceIn: String? } diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift index 9c659c3..048553a 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift @@ -9,13 +9,17 @@ import Foundation class AnalyticsParameter { var name: String - var type: String + var type: ParameterType + var value: String + var defaultValue: String var replaceIn: [String] = [] // MARK: - Init - init(name: String, type: String) { + init(name: String, type: ParameterType, value: String, defaultValue: String) { self.name = name self.type = type + self.value = value + self.defaultValue = defaultValue } } diff --git a/Sources/ResgenSwift/Analytics/Model/ParameterType.swift b/Sources/ResgenSwift/Analytics/Model/ParameterType.swift new file mode 100644 index 0000000..1f60ef9 --- /dev/null +++ b/Sources/ResgenSwift/Analytics/Model/ParameterType.swift @@ -0,0 +1,15 @@ +// +// File.swift +// +// +// Created by Loris Perret on 17/07/2024. +// + +import Foundation + +enum ParameterType: String { + case string = "String" + case int = "Int" + case double = "Double" + case bool = "Bool" +} diff --git a/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift b/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift index f667247..b6ef6a6 100644 --- a/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift +++ b/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift @@ -30,25 +30,52 @@ class AnalyticsFileParser { } private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] { - parameters.map { dtoParameter in + func verify(value: String?, for type: ParameterType) { + guard let value, value.isEmpty == false else { return } + + switch type { + case .int: + if Int(value) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .bool: + if Bool(value.lowercased()) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .double: + if Double(value) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .string: + break + } + } + + return parameters.map { dtoParameter in // Type let type = dtoParameter.type.uppercasedFirst() - guard - type == "String" || - type == "Int" || - type == "Double" || - type == "Bool" - else { + guard let typeEnum = ParameterType(rawValue: type) else { let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)") print(error.description) Analytics.exit(withError: error) } + + verify(value: dtoParameter.value, for: typeEnum) + verify(value: dtoParameter.defaultValue, for: typeEnum) let parameter = AnalyticsParameter( name: dtoParameter.name, - type: type + type: typeEnum, + value: dtoParameter.value ?? "", + defaultValue: dtoParameter.defaultValue ?? "" ) if let replaceIn = dtoParameter.replaceIn { @@ -103,6 +130,8 @@ class AnalyticsFileParser { Analytics.exit(withError: error) } + definition.path = path + } else if let path = screen.path { definition.path = path }