Fix Tests Analytics #17

Merged
t.schmitt merged 6 commits from analytics into master 2025-07-17 14:11:28 +02:00
7 changed files with 403 additions and 397 deletions
Showing only changes of commit 087280502e - Show all commits

View File

@@ -7,6 +7,7 @@ import FirebaseAnalytics
// MARK: - Protocol // MARK: - Protocol
protocol AnalyticsManagerProtocol { protocol AnalyticsManagerProtocol {
func logScreen( func logScreen(
name: String, name: String,
path: String, path: String,
@@ -23,75 +24,12 @@ protocol AnalyticsManagerProtocol {
func setEnable(_ enable: Bool) func setEnable(_ enable: Bool)
} }
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \(url)")
debugPrint("[Matomo service] Site ID: \(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
func setEnable(_ enable: Bool) {
tracker.isOptedOut = !enable
}
}
// MARK: - Firebase // MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol { class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Methods
func logScreen( func logScreen(
name: String, name: String,
path: String, path: String,
@@ -158,16 +96,16 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
parameters: parameters parameters: parameters
) )
} }
func setEnable(_ enable: Bool) { func setEnable(_ enable: Bool) {
Analytics.setAnalyticsCollectionEnabled(enable) Analytics.setAnalyticsCollectionEnabled(enable)
} }
} }
// MARK: - Traker Type // MARK: - Traker Type
enum TrackerType: CaseIterable { enum TrackerType: CaseIterable {
case matomo
case firebase case firebase
} }
@@ -191,7 +129,7 @@ class AnalyticsManager {
} }
} }
// MARK: - Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
managers.forEach { (key, value) in managers.forEach { (key, value) in
@@ -211,14 +149,12 @@ class AnalyticsManager {
setAnalytics(enable: false, analytics) setAnalytics(enable: false, analytics)
} }
func configure(siteId: String, url: String) { func configure() {
managers[TrackerType.matomo] = MatomoAnalyticsManager(
siteId: siteId,
url: url
)
managers[TrackerType.firebase] = FirebaseAnalyticsManager() managers[TrackerType.firebase] = FirebaseAnalyticsManager()
} }
// MARK: - Private Log Methods
private func logScreen( private func logScreen(
name: String, name: String,
path: String, path: String,

View File

@@ -54,7 +54,7 @@ echo "\n-------------------------\n"
# Analytics # Analytics
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \ swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
--target "firebase matomo" \ --target "firebase" \
--extension-output-path "./Tags/Generated" \ --extension-output-path "./Tags/Generated" \
--extension-name "Analytics" \ --extension-name "Analytics" \
--extension-suffix "GenAllScript" \ --extension-suffix "GenAllScript" \

View File

@@ -93,8 +93,8 @@ enum AnalyticsGenerator {
\(Self.getImport(targets: targets)) \(Self.getImport(targets: targets))
\(Self.getAnalyticsProtocol(targets: targets)) \(Self.getAnalyticsProtocol(targets: targets))
\(Self.getTrackerTypeEnum()) \(Self.getTrackerTypeEnum(targets: targets))
// MARK: - Manager // MARK: - Manager
@@ -111,14 +111,14 @@ enum AnalyticsGenerator {
\(Self.getEnabledContent()) \(Self.getEnabledContent())
\(Self.getAnalyticsProperties(targets: targets)) \(Self.getAnalyticsProperties(targets: targets))
\(Self.getPrivateLogFunction()) \(Self.getPrivateLogFunction())
""" """
} }
private static func getTrackerTypeEnum() -> String { private static func getTrackerTypeEnum(targets: [TrackerType]) -> String {
var result: [String] = [] var result: [String] = []
TrackerType.allCases.forEach { type in targets.forEach { type in
result.append(" case \(type)") result.append(" case \(type)")
} }
@@ -126,6 +126,7 @@ enum AnalyticsGenerator {
// MARK: - Traker Type // MARK: - Traker Type
enum TrackerType: CaseIterable { enum TrackerType: CaseIterable {
\(result.joined(separator: "\n")) \(result.joined(separator: "\n"))
} }
""" """
@@ -141,7 +142,7 @@ enum AnalyticsGenerator {
} }
} }
// MARK: - Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
managers.forEach { (key, value) in managers.forEach { (key, value) in
@@ -180,7 +181,9 @@ enum AnalyticsGenerator {
private static func getPrivateLogFunction() -> String { private static func getPrivateLogFunction() -> String {
""" """
private func logScreen( // MARK: - Private Log Methods
private func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
@@ -252,6 +255,7 @@ enum AnalyticsGenerator {
// MARK: - Protocol // MARK: - Protocol
protocol AnalyticsManagerProtocol { protocol AnalyticsManagerProtocol {
func logScreen( func logScreen(
name: String, name: String,
path: String, path: String,
@@ -267,7 +271,6 @@ enum AnalyticsGenerator {
func setEnable(_ enable: Bool) func setEnable(_ enable: Bool)
} }
""" """
var result: [String] = [proto] var result: [String] = [proto]
@@ -280,7 +283,7 @@ enum AnalyticsGenerator {
result.append(FirebaseGenerator.service) result.append(FirebaseGenerator.service)
} }
return result.joined(separator: "\n") return result.joined(separator: "\n\n")
} }
private static func getProperties( private static func getProperties(

View File

@@ -29,6 +29,9 @@ enum FirebaseGenerator {
// MARK: - Firebase // MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol { class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Methods
""" """
} }
@@ -54,7 +57,7 @@ enum FirebaseGenerator {
}) { }) {
continue continue
} }
parameters[newKey] = newValue as? NSObject parameters[newKey] = newValue as? NSObject
} }
} }
@@ -83,11 +86,11 @@ enum FirebaseGenerator {
if category.isEmpty == false { if category.isEmpty == false {
parameters["AnalyticsParameterItemCategory"] = category as NSObject parameters["AnalyticsParameterItemCategory"] = category as NSObject
} }
if action.isEmpty == false { if action.isEmpty == false {
parameters["action"] = action as NSObject parameters["action"] = action as NSObject
} }
if let supplementaryParameters = params { if let supplementaryParameters = params {
for (newKey, newValue) in supplementaryParameters { for (newKey, newValue) in supplementaryParameters {
if parameters.contains(where: { (key: String, value: NSObject) in if parameters.contains(where: { (key: String, value: NSObject) in
@@ -105,6 +108,7 @@ enum FirebaseGenerator {
parameters: parameters parameters: parameters
) )
} }
""" """
} }
@@ -119,7 +123,6 @@ enum FirebaseGenerator {
private static var footer: String { private static var footer: String {
""" """
} }
""" """
} }
} }

View File

@@ -115,7 +115,6 @@ enum MatomoGenerator {
private static var footer: String { private static var footer: String {
""" """
} }
""" """
} }
} }

View File

@@ -62,7 +62,8 @@ final class AnalyticsDefinitionTests: XCTestCase {
func logScreenDefinitionName() { func logScreenDefinitionName() {
logScreen( logScreen(
name: "Ecran un", name: "Ecran un",
path: "ecran_un/" path: "ecran_un/",
params: nil
) )
} }
""" """
@@ -84,7 +85,7 @@ final class AnalyticsDefinitionTests: XCTestCase {
name: "Ecran un", name: "Ecran un",
action: "", action: "",
category: "", category: "",
params: [:] params: nil
) )
} }
""" """
@@ -103,9 +104,10 @@ final class AnalyticsDefinitionTests: XCTestCase {
// Expect // Expect
let expectScreen = """ let expectScreen = """
static func logScreenDefinitionName() { static func logScreenDefinitionName() {
logScreen( AnalyticsManager.shared.logScreen(
name: "Ecran un", name: "Ecran un",
path: "ecran_un/" path: "ecran_un/",
params: nil
) )
} }
""" """
@@ -123,11 +125,11 @@ final class AnalyticsDefinitionTests: XCTestCase {
// Expect // Expect
let expectEvent = """ let expectEvent = """
static func logEventDefinitionName() { static func logEventDefinitionName() {
logEvent( AnalyticsManager.shared.logEvent(
name: "Ecran un", name: "Ecran un",
action: "", action: "",
category: "", category: "",
params: [:] params: nil
) )
} }
""" """

View File

@@ -1,6 +1,6 @@
// //
// AnalyticsGeneratorTests.swift // AnalyticsGeneratorTests.swift
// //
// //
// Created by Thibaut Schmitt on 06/09/2022. // Created by Thibaut Schmitt on 06/09/2022.
// //
@@ -14,7 +14,7 @@ import ToolCore
@testable import ResgenSwift @testable import ResgenSwift
final class AnalyticsGeneratorTests: XCTestCase { final class AnalyticsGeneratorTests: XCTestCase {
private func getAnalyticsDefinition( private func getAnalyticsDefinition(
id: String, id: String,
path: String = "", path: String = "",
@@ -31,7 +31,183 @@ final class AnalyticsGeneratorTests: XCTestCase {
definition.category = category definition.category = category
return definition return definition
} }
private func protocolString() -> String {
"""
// MARK: - Protocol
protocol AnalyticsManagerProtocol {
func logScreen(
name: String,
path: String,
params: [String: Any]?
)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
func setEnable(_ enable: Bool)
}
"""
}
private func firebaseString() -> String {
"""
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Methods
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
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String: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 {
if parameters.contains(where: { (key: String, value: NSObject) in
key == newKey
}) {
continue
}
parameters[newKey] = newValue as? NSObject
}
}
Analytics.logEvent(
AnalyticsEventSelectContent,
parameters: parameters
)
}
func setEnable(_ enable: Bool) {
Analytics.setAnalyticsCollectionEnabled(enable)
}
}
"""
}
private func matomoString() -> String {
"""
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
func setEnable(_ enable: Bool) {
tracker.isOptedOut = !enable
}
}
"""
}
func testGeneratedExtensionContentFirebase() { func testGeneratedExtensionContentFirebase() {
// Given // Given
let sectionOne = AnalyticsCategory(id: "section_one") let sectionOne = AnalyticsCategory(id: "section_one")
@@ -39,19 +215,19 @@ final class AnalyticsGeneratorTests: XCTestCase {
getAnalyticsDefinition(id: "s1_def_one", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_one", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
getAnalyticsDefinition(id: "s1_def_two", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_two", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
] ]
let sectionTwo = AnalyticsCategory(id: "section_two") let sectionTwo = AnalyticsCategory(id: "section_two")
sectionTwo.definitions = [ sectionTwo.definitions = [
getAnalyticsDefinition(id: "s2_def_one", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]), getAnalyticsDefinition(id: "s2_def_one", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
getAnalyticsDefinition(id: "s2_def_two", name: "s2 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s2_def_two", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
] ]
let sectionThree = AnalyticsCategory(id: "section_three") let sectionThree = AnalyticsCategory(id: "section_three")
sectionThree.definitions = [ sectionThree.definitions = [
getAnalyticsDefinition(id: "s3_def_one", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_one", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
getAnalyticsDefinition(id: "s3_def_two", name: "s3 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_two", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
] ]
// When // When
let extensionContent = AnalyticsGenerator.getExtensionContent( let extensionContent = AnalyticsGenerator.getExtensionContent(
targets: [TrackerType.firebase], targets: [TrackerType.firebase],
@@ -65,64 +241,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """ let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion) // Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import FirebaseAnalytics import FirebaseAnalytics
// MARK: - Protocol \(protocolString())
protocol AnalyticsManagerProtocol { \(firebaseString())
func logScreen(name: String, path: String) // MARK: - Traker Type
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Firebase enum TrackerType: CaseIterable {
class FirebaseAnalyticsManager: AnalyticsManagerProtocol { case firebase
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
} }
// MARK: - Manager // MARK: - Manager
@@ -131,27 +261,59 @@ final class AnalyticsGeneratorTests: XCTestCase {
static var shared = AnalyticsManager() static var shared = AnalyticsManager()
private init() {}
// MARK: - Properties // MARK: - Properties
var managers: [AnalyticsManagerProtocol] = [] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isEnabled: Bool = true private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false
} else {
true
}
}
// MARK: - Methods // MARK: - Enable Methods
func setAnalyticsEnabled(_ enable: Bool) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
isEnabled = enable managers.forEach { (key, value) in
if analytics.contains(where: { type in
type == key
}) {
value.setEnable(enable)
}
}
}
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics)
}
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics)
} }
func configure() { func configure() {
managers.append(FirebaseAnalyticsManager()) managers[TrackerType.firebase] = FirebaseAnalyticsManager()
} }
private func logScreen(name: String, path: String) { // MARK: - Private Log Methods
private func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logScreen(name: name, path: path) manager.logScreen(
name: name,
path: path,
params: params
)
} }
} }
@@ -163,7 +325,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) { ) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -178,7 +340,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() { func logScreenS1DefOne() {
logScreen( logScreen(
name: "s1 def one", name: "s1 def one",
path: "" path: "",
params: nil
) )
} }
@@ -187,7 +350,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two", name: "s1 def two",
action: "", action: "",
category: "", category: "",
params: [:] params: nil
) )
} }
@@ -196,19 +359,20 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() { func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "" path: "",
params: nil
) )
} }
} }
""" """
if extensionContent != expect { if extensionContent != expect {
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
} }
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
} }
func testGeneratedExtensionContentMatomo() { func testGeneratedExtensionContentMatomo() {
// Given // Given
let sectionOne = AnalyticsCategory(id: "section_one") let sectionOne = AnalyticsCategory(id: "section_one")
@@ -216,19 +380,19 @@ final class AnalyticsGeneratorTests: XCTestCase {
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
] ]
let sectionTwo = AnalyticsCategory(id: "section_two") let sectionTwo = AnalyticsCategory(id: "section_two")
sectionTwo.definitions = [ sectionTwo.definitions = [
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]), getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
] ]
let sectionThree = AnalyticsCategory(id: "section_three") let sectionThree = AnalyticsCategory(id: "section_three")
sectionThree.definitions = [ sectionThree.definitions = [
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
] ]
// When // When
let extensionContent = AnalyticsGenerator.getExtensionContent( let extensionContent = AnalyticsGenerator.getExtensionContent(
targets: [TrackerType.matomo], targets: [TrackerType.matomo],
@@ -241,80 +405,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """ let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion) // Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import MatomoTracker import MatomoTracker
// MARK: - Protocol \(protocolString())
protocol AnalyticsManagerProtocol { \(matomoString())
func logScreen(name: String, path: String) // MARK: - Traker Type
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Matomo enum TrackerType: CaseIterable {
class MatomoAnalyticsManager: AnalyticsManagerProtocol { case matomo
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
} }
// MARK: - Manager // MARK: - Manager
@@ -323,32 +425,62 @@ final class AnalyticsGeneratorTests: XCTestCase {
static var shared = AnalyticsManager() static var shared = AnalyticsManager()
private init() {}
// MARK: - Properties // MARK: - Properties
var managers: [AnalyticsManagerProtocol] = [] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isEnabled: Bool = true private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false
} else {
true
}
}
// MARK: - Methods // MARK: - Enable Methods
func setAnalyticsEnabled(_ enable: Bool) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
isEnabled = enable managers.forEach { (key, value) in
if analytics.contains(where: { type in
type == key
}) {
value.setEnable(enable)
}
}
}
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics)
}
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics)
} }
func configure(siteId: String, url: String) { func configure(siteId: String, url: String) {
managers.append( managers[TrackerType.matomo] = MatomoAnalyticsManager(
MatomoAnalyticsManager( siteId: siteId,
siteId: siteId, url: url
url: url
)
) )
} }
private func logScreen(name: String, path: String) { // MARK: - Private Log Methods
private func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logScreen(name: name, path: path) manager.logScreen(
name: name,
path: path,
params: params
)
} }
} }
@@ -360,7 +492,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) { ) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -375,7 +507,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() { func logScreenS1DefOne() {
logScreen( logScreen(
name: "s1 def one", name: "s1 def one",
path: "s1_def_one/" path: "s1_def_one/",
params: nil
) )
} }
@@ -384,7 +517,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two", name: "s1 def two",
action: "test", action: "test",
category: "test", category: "test",
params: [:] params: nil
) )
} }
@@ -393,19 +526,20 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() { func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "s2_def_one/" path: "s2_def_one/",
params: nil
) )
} }
} }
""" """
if extensionContent != expect { if extensionContent != expect {
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
} }
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
} }
func testGeneratedExtensionContentMatomoAndFirebase() { func testGeneratedExtensionContentMatomoAndFirebase() {
// Given // Given
let sectionOne = AnalyticsCategory(id: "section_one") let sectionOne = AnalyticsCategory(id: "section_one")
@@ -413,19 +547,19 @@ final class AnalyticsGeneratorTests: XCTestCase {
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]), getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
] ]
let sectionTwo = AnalyticsCategory(id: "section_two") let sectionTwo = AnalyticsCategory(id: "section_two")
sectionTwo.definitions = [ sectionTwo.definitions = [
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]), getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
] ]
let sectionThree = AnalyticsCategory(id: "section_three") let sectionThree = AnalyticsCategory(id: "section_three")
sectionThree.definitions = [ sectionThree.definitions = [
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]), getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
] ]
// When // When
let extensionContent = AnalyticsGenerator.getExtensionContent( let extensionContent = AnalyticsGenerator.getExtensionContent(
targets: [TrackerType.matomo, TrackerType.firebase], targets: [TrackerType.matomo, TrackerType.firebase],
@@ -439,125 +573,22 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """ let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion) // Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import MatomoTracker import MatomoTracker
import FirebaseAnalytics import FirebaseAnalytics
// MARK: - Protocol \(protocolString())
protocol AnalyticsManagerProtocol { \(matomoString())
func logScreen(name: String, path: String) \(firebaseString())
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Matomo // MARK: - Traker Type
class MatomoAnalyticsManager: AnalyticsManagerProtocol { enum TrackerType: CaseIterable {
// MARK: - Properties case matomo
case firebase
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
}
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
} }
// MARK: - Manager // MARK: - Manager
@@ -566,33 +597,63 @@ final class AnalyticsGeneratorTests: XCTestCase {
static var shared = AnalyticsManager() static var shared = AnalyticsManager()
private init() {}
// MARK: - Properties // MARK: - Properties
var managers: [AnalyticsManagerProtocol] = [] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isEnabled: Bool = true private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false
} else {
true
}
}
// MARK: - Methods // MARK: - Enable Methods
func setAnalyticsEnabled(_ enable: Bool) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
isEnabled = enable managers.forEach { (key, value) in
if analytics.contains(where: { type in
type == key
}) {
value.setEnable(enable)
}
}
}
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics)
}
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics)
} }
func configure(siteId: String, url: String) { func configure(siteId: String, url: String) {
managers.append( managers[TrackerType.matomo] = MatomoAnalyticsManager(
MatomoAnalyticsManager( siteId: siteId,
siteId: siteId, url: url
url: url
)
) )
managers.append(FirebaseAnalyticsManager()) managers[TrackerType.firebase] = FirebaseAnalyticsManager()
} }
private func logScreen(name: String, path: String) { // MARK: - Private Log Methods
private func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logScreen(name: name, path: path) manager.logScreen(
name: name,
path: path,
params: params
)
} }
} }
@@ -604,7 +665,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) { ) {
guard isEnabled else { return } guard isEnabled else { return }
managers.forEach { manager in managers.values.forEach { manager in
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -619,7 +680,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() { func logScreenS1DefOne() {
logScreen( logScreen(
name: "s1 def one", name: "s1 def one",
path: "s1_def_one/" path: "s1_def_one/",
params: nil
) )
} }
@@ -628,7 +690,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two", name: "s1 def two",
action: "test", action: "test",
category: "test", category: "test",
params: [:] params: nil
) )
} }
@@ -637,13 +699,14 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() { func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "s2_def_one/" path: "s2_def_one/",
params: nil
) )
} }
} }
""" """
if extensionContent != expect { if extensionContent != expect {
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
} }