12 Commits
2.2.3 ... 2.2.4

Author SHA1 Message Date
0118492162 Add MainActor on AnalysticsManager shared property (#24)
All checks were successful
openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #24
2026-01-05 14:31:39 +01:00
6debae8162 Merge pull request 'fix/RES-75_Multiligne' (#23) from fix/RES-75_Multiligne into master
All checks were successful
openium/resgen.swift/pipeline/head This commit is unstable
Reviewed-on: #23
2025-11-18 10:04:01 +01:00
434d427136 fix test
All checks were successful
openium/resgen.swift/pipeline/pr-master This commit is unstable
2025-11-10 17:19:13 +01:00
052f416741 Update jenkinsFile
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2025-11-10 16:01:10 +01:00
4b944ed8c7 RES-75 Ajouter un pretty print pour le dictionnaire des params
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
openium/resgen.swift/pipeline/head There was a failure building this commit
2025-10-29 11:07:37 +01:00
1f9af76b40 RES-74 Ajout du multiligne sur les logs des analytics
Some checks failed
openium/resgen.swift/pipeline/head There was a failure building this commit
2025-10-29 09:23:10 +01:00
7247d20ae4 Merge pull request 'feat/RES-73_Ajout_DebugMode_Analytics' (#22) from feat/RES-73_Ajout_DebugMode_Analytics into master
Some checks failed
openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #22
2025-10-21 15:03:05 +02:00
63404f8f20 Ajout de maj
Some checks are pending
openium/resgen.swift/pipeline/pr-master Build started...
2025-10-21 15:02:34 +02:00
c4a3aa54d6 Gestion du cas des strings vides
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2025-10-21 10:57:20 +02:00
b9e610a6d9 Review
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2025-10-20 17:08:08 +02:00
7c6a8d2ac3 Génération du fichier + suppression variable inutile
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
openium/resgen.swift/pipeline/head There was a failure building this commit
2025-10-20 16:33:47 +02:00
f0aac3a91b RES-73 Ajout d'un debugMode iOS
Some checks failed
openium/resgen.swift/pipeline/head There was a failure building this commit
2025-10-20 16:30:36 +02:00
9 changed files with 345 additions and 177 deletions

2
Jenkinsfile vendored
View File

@@ -1,6 +1,6 @@
library "openiumpipeline" library "openiumpipeline"
env.DEVELOPER_DIR="/Applications/Xcode-16.3.0.app/Contents/Developer" env.DEVELOPER_DIR="/Applications/Xcode-26.2.0.app/Contents/Developer"
// env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro" // env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro"
// env.SLACK_CHANNEL = "prj-skdevkit" // env.SLACK_CHANNEL = "prj-skdevkit"
env.IS_PACKAGE_SWIFT=1 env.IS_PACKAGE_SWIFT=1

View File

@@ -1,12 +1,12 @@
// Generated by ResgenSwift.Analytics 2.2.0 // Generated by ResgenSwift.Analytics 2.2.0
import Foundation import Foundation
import MatomoTracker
import FirebaseAnalytics import FirebaseAnalytics
import os
// MARK: - Protocol // MARK: - Protocol
public protocol AnalyticsManagerProtocol { internal protocol AnalyticsManagerProtocol {
func logScreen( func logScreen(
name: String, name: String,
@@ -24,72 +24,6 @@ public 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 {
@@ -170,17 +104,16 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Traker Type // MARK: - Traker Type
public enum TrackerType: CaseIterable { internal enum TrackerType: CaseIterable {
case matomo
case firebase case firebase
} }
// MARK: - Manager // MARK: - Manager
public class AnalyticsManager { internal class AnalyticsManager {
public static var shared = AnalyticsManager() internal static var shared = AnalyticsManager()
private init() {} private init() {}
@@ -188,6 +121,8 @@ public class AnalyticsManager {
var managers: [TrackerType: AnalyticsManagerProtocol] = [:] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isDebugMode: Bool = false
private var isEnabled: Bool { private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false false
@@ -196,6 +131,8 @@ public class AnalyticsManager {
} }
} }
private let logger = Logger(subsystem: "resgen", category: "analytics")
// MARK: - Enable Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
@@ -208,32 +145,55 @@ public class AnalyticsManager {
} }
} }
public func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics) setAnalytics(enable: true, analytics)
} }
public func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics) setAnalytics(enable: false, analytics)
} }
public func configure(siteId: String, url: String) { internal func configure(isDebugMode: Bool = false) {
managers[TrackerType.matomo] = MatomoAnalyticsManager( self.isDebugMode = isDebugMode
siteId: siteId,
url: url
)
managers[TrackerType.firebase] = FirebaseAnalyticsManager() managers[TrackerType.firebase] = FirebaseAnalyticsManager()
} }
// MARK: - Private Log Methods // MARK: - Private Log Methods
private func formattedParams(_ params: [String: Any]?) -> String {
guard let params = params, !params.isEmpty else { return "-" }
let formattedParams = params.map { key, value in
" \(key): \(value)"
}
.joined(separator: "\n")
return "\n" + formattedParams
}
private func logScreen( private func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug("""
🖥️ Screen:
Name: \(name, privacy: .public)
Path: \(path, privacy: .public)
Params: \(self.formattedParams(params), privacy: .public)
""")
}
manager.logScreen( manager.logScreen(
name: name, name: name,
path: path, path: path,
@@ -248,9 +208,25 @@ public class AnalyticsManager {
category: String, category: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug("""
📊 Event:
Name: \(name, privacy: .public)
Action: \(action.isEmpty ? "-" : action, privacy: .public)
Category: \(category.isEmpty ? "-" : category, privacy: .public)
Params: \(self.formattedParams(params), privacy: .public)
""")
}
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -262,7 +238,7 @@ public class AnalyticsManager {
// MARK: - section_one // MARK: - section_one
public func logScreenS1DefOne(title: String) { internal func logScreenS1DefOne(title: String) {
logScreen( logScreen(
name: "s1 def one \(title)", name: "s1 def one \(title)",
path: "s1_def_one/\(title)", path: "s1_def_one/\(title)",
@@ -270,7 +246,7 @@ public class AnalyticsManager {
) )
} }
public func logEventS1DefTwo( internal func logEventS1DefTwo(
title: String, title: String,
count: String, count: String,
test2: String = "test" test2: String = "test"
@@ -290,7 +266,7 @@ public class AnalyticsManager {
// MARK: - section_two // MARK: - section_two
public func logScreenS2DefOne() { internal func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "s2_def_one/", path: "s2_def_one/",

View File

@@ -33,13 +33,13 @@ FORCE_FLAG="$1"
#echo "\n-------------------------\n" #echo "\n-------------------------\n"
## Strings ## Strings
swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \ #swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \
--output-path "./Strings/Generated" \ # --output-path "./Strings/Generated" \
--langs "fr en en-us" \ # --langs "fr en en-us" \
--default-lang "en" \ # --default-lang "en" \
--extension-output-path "./Strings/Generated" \ # --extension-output-path "./Strings/Generated" \
--extension-name "String" \ # --extension-name "String" \
--extension-suffix "GenAllScript" # --extension-suffix "GenAllScript"
#echo "\n-------------------------\n" #echo "\n-------------------------\n"
# #
@@ -53,12 +53,9 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sample
#echo "\n-------------------------\n" #echo "\n-------------------------\n"
# #
## Analytics ## Analytics
#swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \ swift run -c release ResgenSwift analytics -f "./Tags/sampleTags.yml" \
# --target "firebase" \ --target "firebase" \
# --extension-output-path "./Tags/Generated" \ --output-file "./Tags/Generated/Analytics+GenAllScript.swift"
# --extension-name "Analytics" \
# --extension-suffix "GenAllScript" \
# --static-members true
# #
#echo "\n-------------------------\n" #echo "\n-------------------------\n"
# #

View File

@@ -90,7 +90,7 @@ analytics:
inputFile: ./Tags/sampleTags.yml inputFile: ./Tags/sampleTags.yml
target: "matomo firebase" target: "matomo firebase"
outputFile: ./Tags/Generated/Analytics+GenAllScript.swift outputFile: ./Tags/Generated/Analytics+GenAllScript.swift
visibility: public visibility: internal
# #

View File

@@ -38,9 +38,6 @@ struct Analytics: ParsableCommand {
print("[\(Self.toolName)] Will generate analytics") print("[\(Self.toolName)] Will generate analytics")
// Check requirements
guard checkRequirements() else { return }
// Parse input file // Parse input file
let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target) let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target)

View File

@@ -104,6 +104,7 @@ enum AnalyticsGenerator {
\(visibility) class AnalyticsManager { \(visibility) class AnalyticsManager {
@MainActor
\(visibility) static var shared = AnalyticsManager() \(visibility) static var shared = AnalyticsManager()
private init() {} private init() {}
@@ -143,7 +144,9 @@ enum AnalyticsGenerator {
visibility: ExtensionVisibility visibility: ExtensionVisibility
) -> String { ) -> String {
""" """
private var isEnabled: Bool { private var isDebugMode: Bool = false
private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false false
} else { } else {
@@ -151,6 +154,8 @@ enum AnalyticsGenerator {
} }
} }
private let logger = Logger(subsystem: "resgen", category: "analytics")
// MARK: - Enable Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
@@ -186,47 +191,91 @@ enum AnalyticsGenerator {
result.append("import FirebaseAnalytics") result.append("import FirebaseAnalytics")
} }
result.append("import os")
return result.joined(separator: "\n") return result.joined(separator: "\n")
} }
private static func getPrivateLogFunction() -> String { private static func getPrivateLogFunction() -> String {
""" """
// MARK: - Private Log Methods // MARK: - Private Log Methods
private func logScreen( private func formattedParams(_ params: [String: Any]?) -> String {
name: String, guard let params = params, !params.isEmpty else { return "-" }
path: String,
params: [String: Any]?
) {
guard isEnabled else { return }
managers.values.forEach { manager in let formattedParams = params.map { key, value in
manager.logScreen( " \\(key): \\(value)"
name: name, }
path: path, .joined(separator: "\\n")
params: params
) return "\\n" + formattedParams
}
private func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
} }
return
} }
private func logEvent( managers.values.forEach { manager in
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard isEnabled else { return }
managers.values.forEach { manager in if isDebugMode {
manager.logEvent( logger.debug(\"""
name: name, 🖥️ Screen:
action: action, Name: \\(name, privacy: .public)
category: category, Path: \\(path, privacy: .public)
params: params Params: \\(self.formattedParams(params), privacy: .public)
) \""")
} }
manager.logScreen(
name: name,
path: path,
params: params
)
} }
""" }
private func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
📊 Event:
Name: \\(name, privacy: .public)
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logEvent(
name: name,
action: action,
category: category,
params: params
)
}
}
"""
} }
private static func getAnalyticsProperties( private static func getAnalyticsProperties(
@@ -238,11 +287,13 @@ enum AnalyticsGenerator {
let footer = " }" let footer = " }"
if targets.contains(TrackerType.matomo) { if targets.contains(TrackerType.matomo) {
header = "\(visibility) func configure(siteId: String, url: String) {" header = "\(visibility) func configure(siteId: String, url: String, isDebugMode: Bool = false) {"
} else if targets.contains(TrackerType.firebase) { } else if targets.contains(TrackerType.firebase) {
header = "\(visibility) func configure() {" header = "\(visibility) func configure(isDebugMode: Bool = false) {"
} }
content.append(" self.isDebugMode = isDebugMode")
if targets.contains(TrackerType.matomo) { if targets.contains(TrackerType.matomo) {
content.append(""" content.append("""
managers[TrackerType.matomo] = MatomoAnalyticsManager( managers[TrackerType.matomo] = MatomoAnalyticsManager(

View File

@@ -16,12 +16,14 @@ struct GenerateOptions: ParsableArguments {
@Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() }) @Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var configurationFile: String var configurationFile: String
@Option(help: "Project directory. It will be added to every relative path (path that does not start with `/`", @Option(
transform: { help: "Project directory. It will be added to every relative path (path that does not start with `/`",
if $0.last == "/" { transform: {
return $0 if $0.last == "/" {
return $0
}
return $0 + "/"
} }
return $0 + "/" )
})
var projectDirectory: String var projectDirectory: String
} }

View File

@@ -175,11 +175,10 @@ enum StringsFileGenerator {
guard section.hasOneOrMoreMatchingTags(tags: inputTags) else { guard section.hasOneOrMoreMatchingTags(tags: inputTags) else {
return // Go to next section return // Go to next section
} }
print("DOUDOU")
section section
.definitions .definitions
.forEach { definition in // swiftlint:disable:this closure_body_length .forEach { definition in // swiftlint:disable:this closure_body_length
var skipDefinition = false
var isNoTranslation = false var isNoTranslation = false
var localizationTab: [XCStringLocalization] = [] var localizationTab: [XCStringLocalization] = []
@@ -212,7 +211,6 @@ enum StringsFileGenerator {
// Search for langs in twine // Search for langs in twine
for (lang, value) in definition.translations for (lang, value) in definition.translations
where langs.contains(lang) && !value.isEmpty { where langs.contains(lang) && !value.isEmpty {
print("DOUDOU-> generate for \(lang)")
let localization = XCStringLocalization( let localization = XCStringLocalization(
lang: lang, lang: lang,
content: XCStringLocalizationLangContent( content: XCStringLocalizationLangContent(

View File

@@ -35,22 +35,22 @@ final class AnalyticsGeneratorTests: XCTestCase {
private func protocolString(visibility: ExtensionVisibility) -> String { private func protocolString(visibility: ExtensionVisibility) -> String {
""" """
// MARK: - Protocol // MARK: - Protocol
\(visibility) protocol AnalyticsManagerProtocol { \(visibility) protocol AnalyticsManagerProtocol {
func logScreen( func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
) )
func logEvent( func logEvent(
name: String, name: String,
action: String, action: String,
category: String, category: String,
params: [String: Any]? params: [String: Any]?
) )
func setEnable(_ enable: Bool) func setEnable(_ enable: Bool)
} }
""" """
@@ -94,7 +94,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
parameters: parameters parameters: parameters
) )
} }
func logEvent( func logEvent(
name: String, name: String,
action: String, action: String,
@@ -234,7 +234,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
sections: [sectionOne, sectionTwo, sectionThree], sections: [sectionOne, sectionTwo, sectionThree],
tags: ["ios", "iosonly"], tags: ["ios", "iosonly"],
isStatic: false, isStatic: false,
visibility: .public visibility: .internal
) )
// Expect Analytics // Expect Analytics
@@ -243,23 +243,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
import Foundation import Foundation
import FirebaseAnalytics import FirebaseAnalytics
import os
\(protocolString(visibility: .public)) \(protocolString(visibility: .internal))
\(firebaseString()) \(firebaseString())
// MARK: - Traker Type // MARK: - Traker Type
public enum TrackerType: CaseIterable { internal enum TrackerType: CaseIterable {
case firebase case firebase
} }
// MARK: - Manager // MARK: - Manager
public class AnalyticsManager { internal class AnalyticsManager {
public static var shared = AnalyticsManager() @MainActor
internal static var shared = AnalyticsManager()
private init() {} private init() {}
@@ -267,6 +269,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
var managers: [TrackerType: AnalyticsManagerProtocol] = [:] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isDebugMode: Bool = false
private var isEnabled: Bool { private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false false
@@ -275,6 +279,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
} }
} }
private let logger = Logger(subsystem: "resgen", category: "analytics")
// MARK: - Enable Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
@@ -287,28 +293,55 @@ final class AnalyticsGeneratorTests: XCTestCase {
} }
} }
public func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics) setAnalytics(enable: true, analytics)
} }
public func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics) setAnalytics(enable: false, analytics)
} }
public func configure() { internal func configure(isDebugMode: Bool = false) {
self.isDebugMode = isDebugMode
managers[TrackerType.firebase] = FirebaseAnalyticsManager() managers[TrackerType.firebase] = FirebaseAnalyticsManager()
} }
// MARK: - Private Log Methods // MARK: - Private Log Methods
private func formattedParams(_ params: [String: Any]?) -> String {
guard let params = params, !params.isEmpty else { return "-" }
let formattedParams = params.map { key, value in
" \\(key): \\(value)"
}
.joined(separator: "\\n")
return "\\n" + formattedParams
}
private func logScreen( private func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
🖥️ Screen:
Name: \\(name, privacy: .public)
Path: \\(path, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logScreen( manager.logScreen(
name: name, name: name,
path: path, path: path,
@@ -323,9 +356,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
category: String, category: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
📊 Event:
Name: \\(name, privacy: .public)
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -337,7 +386,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - section_one // MARK: - section_one
public func logScreenS1DefOne() { internal func logScreenS1DefOne() {
logScreen( logScreen(
name: "s1 def one", name: "s1 def one",
path: "", path: "",
@@ -345,7 +394,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) )
} }
public func logEventS1DefTwo() { internal func logEventS1DefTwo() {
logEvent( logEvent(
name: "s1 def two", name: "s1 def two",
action: "", action: "",
@@ -356,7 +405,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - section_two // MARK: - section_two
public func logScreenS2DefOne() { internal func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "", path: "",
@@ -399,7 +448,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
sections: [sectionOne, sectionTwo, sectionThree], sections: [sectionOne, sectionTwo, sectionThree],
tags: ["ios", "iosonly"], tags: ["ios", "iosonly"],
isStatic: false, isStatic: false,
visibility: .package visibility: .internal
) )
// Expect Analytics // Expect Analytics
let expect = """ let expect = """
@@ -407,23 +456,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
import Foundation import Foundation
import MatomoTracker import MatomoTracker
import os
\(protocolString(visibility: .package)) \(protocolString(visibility: .internal))
\(matomoString()) \(matomoString())
// MARK: - Traker Type // MARK: - Traker Type
package enum TrackerType: CaseIterable { internal enum TrackerType: CaseIterable {
case matomo case matomo
} }
// MARK: - Manager // MARK: - Manager
package class AnalyticsManager { internal class AnalyticsManager {
package static var shared = AnalyticsManager() @MainActor
internal static var shared = AnalyticsManager()
private init() {} private init() {}
@@ -431,6 +482,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
var managers: [TrackerType: AnalyticsManagerProtocol] = [:] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isDebugMode: Bool = false
private var isEnabled: Bool { private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false false
@@ -439,6 +492,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
} }
} }
private let logger = Logger(subsystem: "resgen", category: "analytics")
// MARK: - Enable Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
@@ -451,15 +506,16 @@ final class AnalyticsGeneratorTests: XCTestCase {
} }
} }
package func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics) setAnalytics(enable: true, analytics)
} }
package func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics) setAnalytics(enable: false, analytics)
} }
package func configure(siteId: String, url: String) { internal func configure(siteId: String, url: String, isDebugMode: Bool = false) {
self.isDebugMode = isDebugMode
managers[TrackerType.matomo] = MatomoAnalyticsManager( managers[TrackerType.matomo] = MatomoAnalyticsManager(
siteId: siteId, siteId: siteId,
url: url url: url
@@ -468,14 +524,40 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - Private Log Methods // MARK: - Private Log Methods
private func formattedParams(_ params: [String: Any]?) -> String {
guard let params = params, !params.isEmpty else { return "-" }
let formattedParams = params.map { key, value in
" \\(key): \\(value)"
}
.joined(separator: "\\n")
return "\\n" + formattedParams
}
private func logScreen( private func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
🖥️ Screen:
Name: \\(name, privacy: .public)
Path: \\(path, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logScreen( manager.logScreen(
name: name, name: name,
path: path, path: path,
@@ -490,9 +572,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
category: String, category: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
📊 Event:
Name: \\(name, privacy: .public)
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,
@@ -504,7 +602,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - section_one // MARK: - section_one
package func logScreenS1DefOne() { internal func logScreenS1DefOne() {
logScreen( logScreen(
name: "s1 def one", name: "s1 def one",
path: "s1_def_one/", path: "s1_def_one/",
@@ -512,7 +610,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) )
} }
package func logEventS1DefTwo() { internal func logEventS1DefTwo() {
logEvent( logEvent(
name: "s1 def two", name: "s1 def two",
action: "test", action: "test",
@@ -523,7 +621,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - section_two // MARK: - section_two
package func logScreenS2DefOne() { internal func logScreenS2DefOne() {
logScreen( logScreen(
name: "s2 def one", name: "s2 def one",
path: "s2_def_one/", path: "s2_def_one/",
@@ -576,6 +674,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
import Foundation import Foundation
import MatomoTracker import MatomoTracker
import FirebaseAnalytics import FirebaseAnalytics
import os
\(protocolString(visibility: .internal)) \(protocolString(visibility: .internal))
@@ -595,6 +694,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
internal class AnalyticsManager { internal class AnalyticsManager {
@MainActor
internal static var shared = AnalyticsManager() internal static var shared = AnalyticsManager()
private init() {} private init() {}
@@ -603,6 +703,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
var managers: [TrackerType: AnalyticsManagerProtocol] = [:] var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isDebugMode: Bool = false
private var isEnabled: Bool { private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false false
@@ -611,6 +713,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
} }
} }
private let logger = Logger(subsystem: "resgen", category: "analytics")
// MARK: - Enable Methods // MARK: - Enable Methods
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
@@ -631,7 +735,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
setAnalytics(enable: false, analytics) setAnalytics(enable: false, analytics)
} }
internal func configure(siteId: String, url: String) { internal func configure(siteId: String, url: String, isDebugMode: Bool = false) {
self.isDebugMode = isDebugMode
managers[TrackerType.matomo] = MatomoAnalyticsManager( managers[TrackerType.matomo] = MatomoAnalyticsManager(
siteId: siteId, siteId: siteId,
url: url url: url
@@ -641,14 +746,40 @@ final class AnalyticsGeneratorTests: XCTestCase {
// MARK: - Private Log Methods // MARK: - Private Log Methods
private func formattedParams(_ params: [String: Any]?) -> String {
guard let params = params, !params.isEmpty else { return "-" }
let formattedParams = params.map { key, value in
" \\(key): \\(value)"
}
.joined(separator: "\\n")
return "\\n" + formattedParams
}
private func logScreen( private func logScreen(
name: String, name: String,
path: String, path: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
🖥️ Screen:
Name: \\(name, privacy: .public)
Path: \\(path, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logScreen( manager.logScreen(
name: name, name: name,
path: path, path: path,
@@ -663,9 +794,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
category: String, category: String,
params: [String: Any]? params: [String: Any]?
) { ) {
guard isEnabled else { return } guard isEnabled else {
if isDebugMode {
logger.log("Analytics disabled")
}
return
}
managers.values.forEach { manager in managers.values.forEach { manager in
if isDebugMode {
logger.debug(\"""
📊 Event:
Name: \\(name, privacy: .public)
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
Params: \\(self.formattedParams(params), privacy: .public)
\""")
}
manager.logEvent( manager.logEvent(
name: name, name: name,
action: action, action: action,