Compare commits
3 Commits
2.2.0
...
4426091dcb
Author | SHA1 | Date | |
---|---|---|---|
4426091dcb | |||
187980933e | |||
a64a956254 |
@@ -36,7 +36,7 @@ swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/fonts.txt" \
|
|||||||
|
|
||||||
## Colors
|
## Colors
|
||||||
|
|
||||||
Colors generator generates an extension of `UIColor` (or a custom class) along with colorsets in specified xcassets.
|
Colors generator generates colorsets in specified xcassets and an extension of `Color` (or a custom class) associated to those colorsets. If the extension name is not specified, no extension will be generated.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
|
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
|
||||||
|
6
SampleFiles/Colors/colors.xcassets/Colors/Contents.json
Normal file
6
SampleFiles/Colors/colors.xcassets/Colors/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,13 @@
|
|||||||
// Generated by ResgenSwift.Analytics 2.1.0
|
// Generated by ResgenSwift.Analytics 2.1.0
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@@ -22,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,
|
||||||
@@ -157,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,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
|
||||||
@@ -210,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,
|
||||||
@@ -262,12 +199,12 @@ class AnalyticsManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func logEventS1DefTwo(
|
func logEventS1DefTwo(
|
||||||
title: String,
|
title: String,
|
||||||
count: String,
|
count: String,
|
||||||
test2: String = "test"
|
test2: String = "test"
|
||||||
) {
|
) {
|
||||||
AnalyticsManager.shared.logEvent(
|
logEvent(
|
||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
|
@@ -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" \
|
||||||
|
@@ -5,11 +5,14 @@
|
|||||||
// Created by Loris Perret on 08/12/2023.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// CPD-OFF
|
||||||
|
|
||||||
import CoreVideo
|
import CoreVideo
|
||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
// Disabled cause it's a pain to handle in generated string
|
// Disabled cause it's a pain to handle in generated string
|
||||||
|
// swiftlint:disable type_body_length
|
||||||
|
|
||||||
enum AnalyticsGenerator {
|
enum AnalyticsGenerator {
|
||||||
|
|
||||||
@@ -89,48 +92,49 @@ enum AnalyticsGenerator {
|
|||||||
) -> String {
|
) -> String {
|
||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||||
|
|
||||||
\(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
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
\(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)")
|
||||||
}
|
}
|
||||||
|
|
||||||
return """
|
return """
|
||||||
// MARK: - Traker Type
|
// MARK: - Traker Type
|
||||||
|
|
||||||
enum TrackerType: CaseIterable {
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
\(result.joined(separator: "\n"))
|
\(result.joined(separator: "\n"))
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getEnabledContent() -> String {
|
private static func getEnabledContent() -> String {
|
||||||
"""
|
"""
|
||||||
private var isEnabled: Bool {
|
private var isEnabled: Bool {
|
||||||
@@ -140,9 +144,9 @@ enum AnalyticsGenerator {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
if analytics.contains(where: { type in
|
if analytics.contains(where: { type in
|
||||||
@@ -152,11 +156,11 @@ enum AnalyticsGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
setAnalytics(enable: true, analytics)
|
setAnalytics(enable: true, analytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
setAnalytics(enable: false, analytics)
|
setAnalytics(enable: false, analytics)
|
||||||
}
|
}
|
||||||
@@ -171,6 +175,7 @@ enum AnalyticsGenerator {
|
|||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
result.append("import MatomoTracker")
|
result.append("import MatomoTracker")
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
result.append("import FirebaseAnalytics")
|
result.append("import FirebaseAnalytics")
|
||||||
}
|
}
|
||||||
@@ -180,13 +185,15 @@ 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]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(
|
manager.logScreen(
|
||||||
name: name,
|
name: name,
|
||||||
@@ -203,7 +210,7 @@ enum AnalyticsGenerator {
|
|||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
@@ -235,6 +242,7 @@ enum AnalyticsGenerator {
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||||||
}
|
}
|
||||||
@@ -252,22 +260,22 @@ enum AnalyticsGenerator {
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var result: [String] = [proto]
|
var result: [String] = [proto]
|
||||||
@@ -280,7 +288,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(
|
||||||
@@ -319,3 +327,5 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CPD-ON
|
||||||
|
@@ -13,11 +13,11 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
FirebaseGenerator.header,
|
Self.header,
|
||||||
FirebaseGenerator.logScreen,
|
Self.logScreen,
|
||||||
FirebaseGenerator.logEvent,
|
Self.logEvent,
|
||||||
FirebaseGenerator.enable,
|
Self.enable,
|
||||||
FirebaseGenerator.footer
|
Self.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,9 @@ enum FirebaseGenerator {
|
|||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,11 +45,11 @@ enum FirebaseGenerator {
|
|||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
if path.isEmpty == false {
|
if path.isEmpty == false {
|
||||||
parameters["path"] = path + "/iOS" as NSObject
|
parameters["path"] = path + "/iOS" 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
|
||||||
@@ -54,11 +57,11 @@ enum FirebaseGenerator {
|
|||||||
}) {
|
}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters[newKey] = newValue as? NSObject
|
parameters[newKey] = newValue as? NSObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
AnalyticsEventScreenView,
|
AnalyticsEventScreenView,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
@@ -79,15 +82,15 @@ enum FirebaseGenerator {
|
|||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:NSObject] = [
|
||||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
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,9 +108,10 @@ enum FirebaseGenerator {
|
|||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var enable: String {
|
private static var enable: String {
|
||||||
"""
|
"""
|
||||||
func setEnable(_ enable: Bool) {
|
func setEnable(_ enable: Bool) {
|
||||||
@@ -115,11 +119,10 @@ enum FirebaseGenerator {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,18 +5,20 @@
|
|||||||
// Created by Loris Perret on 05/12/2023.
|
// Created by Loris Perret on 05/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// CPD-OFF
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum MatomoGenerator {
|
enum MatomoGenerator {
|
||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
MatomoGenerator.header,
|
Self.header,
|
||||||
MatomoGenerator.setup,
|
Self.setup,
|
||||||
MatomoGenerator.logScreen,
|
Self.logScreen,
|
||||||
MatomoGenerator.logEvent,
|
Self.logEvent,
|
||||||
MatomoGenerator.enable,
|
Self.enable,
|
||||||
MatomoGenerator.footer
|
Self.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@@ -100,10 +102,10 @@ enum MatomoGenerator {
|
|||||||
url: nil
|
url: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var enable: String {
|
private static var enable: String {
|
||||||
"""
|
"""
|
||||||
func setEnable(_ enable: Bool) {
|
func setEnable(_ enable: Bool) {
|
||||||
@@ -115,7 +117,8 @@ enum MatomoGenerator {
|
|||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CPD-ON
|
||||||
|
@@ -52,20 +52,22 @@ class AnalyticsDefinition {
|
|||||||
|
|
||||||
private func getParameters() -> String {
|
private func getParameters() -> String {
|
||||||
var result: String
|
var result: String
|
||||||
|
|
||||||
let paramsString = parameters.compactMap { parameter -> String? in
|
let paramsString = parameters.compactMap { parameter -> String? in
|
||||||
guard parameter.value.isEmpty else { return nil }
|
guard parameter.value.isEmpty else { return nil }
|
||||||
|
|
||||||
let defaultValue: String
|
let defaultValue: String
|
||||||
switch parameter.type {
|
switch parameter.type {
|
||||||
case .bool:
|
case .bool:
|
||||||
defaultValue = "\(parameter.defaultValue.lowercased())"
|
defaultValue = "\(parameter.defaultValue.lowercased())"
|
||||||
|
|
||||||
case .int, .double:
|
case .int, .double:
|
||||||
defaultValue = "\(parameter.defaultValue)"
|
defaultValue = "\(parameter.defaultValue)"
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
defaultValue = "\"\(parameter.defaultValue)\""
|
defaultValue = "\"\(parameter.defaultValue)\""
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
|
let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
|
||||||
return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
|
return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
|
||||||
}
|
}
|
||||||
@@ -90,9 +92,13 @@ class AnalyticsDefinition {
|
|||||||
for rep in parameter.replaceIn {
|
for rep in parameter.replaceIn {
|
||||||
switch rep {
|
switch rep {
|
||||||
case "name": name = name.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "name": name = name.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
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 "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
|
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))")
|
param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
@@ -117,8 +123,10 @@ class AnalyticsDefinition {
|
|||||||
switch param.type {
|
switch param.type {
|
||||||
case .bool:
|
case .bool:
|
||||||
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
||||||
|
|
||||||
case .int, .double:
|
case .int, .double:
|
||||||
params.append("\"\(param.name)\": \(param.value)")
|
params.append("\"\(param.name)\": \(param.value)")
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
params.append("\"\(param.name)\": \"\(param.value)\"")
|
params.append("\"\(param.name)\": \"\(param.value)\"")
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ class AnalyticsParameter {
|
|||||||
var replaceIn: [String] = []
|
var replaceIn: [String] = []
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
|
|
||||||
init(name: String, type: ParameterType, value: String, defaultValue: String) {
|
init(name: String, type: ParameterType, value: String, defaultValue: String) {
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = type
|
self.type = type
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ParameterType: String {
|
enum ParameterType: String {
|
||||||
|
|
||||||
case string = "String"
|
case string = "String"
|
||||||
case int = "Int"
|
case int = "Int"
|
||||||
case double = "Double"
|
case double = "Double"
|
||||||
|
@@ -70,7 +70,7 @@ class AnalyticsFileParser {
|
|||||||
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||||
func verify(value: String?, for type: ParameterType) {
|
func verify(value: String?, for type: ParameterType) {
|
||||||
guard let value, value.isEmpty == false else { return }
|
guard let value, value.isEmpty == false else { return }
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .int:
|
case .int:
|
||||||
if Int(value) == nil {
|
if Int(value) == nil {
|
||||||
@@ -78,23 +78,26 @@ class AnalyticsFileParser {
|
|||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .bool:
|
case .bool:
|
||||||
if Bool(value.lowercased()) == nil {
|
if Bool(value.lowercased()) == nil {
|
||||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .double:
|
case .double:
|
||||||
if Double(value) == nil {
|
if Double(value) == nil {
|
||||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameters.map { dtoParameter in
|
return parameters.map { dtoParameter in
|
||||||
// Type
|
// Type
|
||||||
let type = dtoParameter.type.uppercasedFirst()
|
let type = dtoParameter.type.uppercasedFirst()
|
||||||
@@ -104,13 +107,13 @@ class AnalyticsFileParser {
|
|||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dtoParameter.value != nil, dtoParameter.replaceIn != nil {
|
if dtoParameter.value != nil, dtoParameter.replaceIn != nil {
|
||||||
let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)")
|
let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(value: dtoParameter.value, for: typeEnum)
|
verify(value: dtoParameter.value, for: typeEnum)
|
||||||
verify(value: dtoParameter.defaultValue, for: typeEnum)
|
verify(value: dtoParameter.defaultValue, for: typeEnum)
|
||||||
|
|
||||||
@@ -147,7 +150,7 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let parameters {
|
if let parameters {
|
||||||
definition.parameters = AnalyticsFileParser.getParameters(from: parameters)
|
definition.parameters = Self.getParameters(from: parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
@@ -215,7 +218,7 @@ class AnalyticsFileParser {
|
|||||||
if let category = event.category {
|
if let category = event.category {
|
||||||
definition.category = category
|
definition.category = category
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = event.action {
|
if let action = event.action {
|
||||||
definition.action = action
|
definition.action = action
|
||||||
}
|
}
|
||||||
|
@@ -21,8 +21,6 @@ struct Colors: ParsableCommand {
|
|||||||
// MARK: - Static
|
// MARK: - Static
|
||||||
|
|
||||||
static let toolName = "Color"
|
static let toolName = "Color"
|
||||||
static let defaultExtensionName = "Color"
|
|
||||||
static let defaultExtensionNameUIKit = "UIColor"
|
|
||||||
static let assetsColorsFolderName = "Colors"
|
static let assetsColorsFolderName = "Colors"
|
||||||
|
|
||||||
// MARK: - Command options
|
// MARK: - Command options
|
||||||
@@ -57,22 +55,28 @@ struct Colors: ParsableCommand {
|
|||||||
// -> Time: 3.4505380392074585 seconds
|
// -> Time: 3.4505380392074585 seconds
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
if let extensionName = options.extensionName,
|
||||||
colors: parsedColors,
|
let extensionFilePath = options.extensionFilePath {
|
||||||
staticVar: options.staticMembers,
|
ColorExtensionGenerator.writeExtensionFile(
|
||||||
extensionName: options.extensionName,
|
colors: parsedColors,
|
||||||
extensionFilePath: options.extensionFilePath,
|
staticVar: options.staticMembers,
|
||||||
isSwiftUI: true
|
extensionName: extensionName,
|
||||||
)
|
extensionFilePath: extensionFilePath,
|
||||||
|
isSwiftUI: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
if let extensionNameUIKit = options.extensionNameUIKit,
|
||||||
colors: parsedColors,
|
let extensionFilePathUIKit = options.extensionFilePathUIKit {
|
||||||
staticVar: options.staticMembers,
|
ColorExtensionGenerator.writeExtensionFile(
|
||||||
extensionName: options.extensionNameUIKit,
|
colors: parsedColors,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
staticVar: options.staticMembers,
|
||||||
isSwiftUI: false
|
extensionName: extensionNameUIKit,
|
||||||
)
|
extensionFilePath: extensionFilePathUIKit,
|
||||||
|
isSwiftUI: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
print("[\(Self.toolName)] Colors generated")
|
print("[\(Self.toolName)] Colors generated")
|
||||||
}
|
}
|
||||||
@@ -96,18 +100,29 @@ struct Colors: ParsableCommand {
|
|||||||
Self.exit(withError: error)
|
Self.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name (if both are defined)
|
||||||
guard options.extensionName != options.extensionNameUIKit else {
|
if let extensionName = options.extensionName,
|
||||||
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
let extensionNameUIKit = options.extensionNameUIKit {
|
||||||
print(error.description)
|
guard extensionName != extensionNameUIKit else {
|
||||||
Self.exit(withError: error)
|
let error = ColorsToolError.extensionNamesCollision(extensionName)
|
||||||
|
print(error.description)
|
||||||
|
Self.exit(withError: error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
|
let fileToCompareToInput: String = {
|
||||||
|
// If there is no extension file to compare
|
||||||
|
// Then check the xcassets file instead
|
||||||
|
if let extensionFilePath = options.extensionFilePath {
|
||||||
|
return extensionFilePath
|
||||||
|
}
|
||||||
|
return options.xcassetsPath
|
||||||
|
}()
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(
|
||||||
force: options.forceGeneration,
|
force: options.forceGeneration,
|
||||||
inputFilePath: options.inputFile,
|
inputFilePath: options.inputFile,
|
||||||
extensionFilePath: options.extensionFilePath
|
extensionFilePath: fileToCompareToInput
|
||||||
) else {
|
) else {
|
||||||
print("[\(Self.toolName)] Colors are already up to date :) ")
|
print("[\(Self.toolName)] Colors are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
|
@@ -30,11 +30,11 @@ struct ColorsToolOptions: ParsableArguments {
|
|||||||
@Option(help: "Tell if it will generate static properties or not")
|
@Option(help: "Tell if it will generate static properties or not")
|
||||||
var staticMembers: Bool = false
|
var staticMembers: Bool = false
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an Color extension.")
|
@Option(help: "Extension name. If not specified, no extension will be generated.")
|
||||||
var extensionName: String = Colors.defaultExtensionName
|
var extensionName: String?
|
||||||
|
|
||||||
@Option(help: "SwiftUI Extension name. If not specified, it will generate an UIColor extension.")
|
@Option(help: "SwiftUI Extension name. If not specified, no extension will be generated.")
|
||||||
var extensionNameUIKit: String = Colors.defaultExtensionNameUIKit
|
var extensionNameUIKit: String?
|
||||||
|
|
||||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
|
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
|
||||||
var extensionSuffix: String?
|
var extensionSuffix: String?
|
||||||
@@ -46,27 +46,35 @@ extension ColorsToolOptions {
|
|||||||
|
|
||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String? {
|
||||||
|
guard let extensionName else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePath: String {
|
var extensionFilePath: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileName)"
|
guard let extensionFileName else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileName)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String? {
|
||||||
|
guard let extensionNameUIKit else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePathUIKit: String {
|
var extensionFilePathUIKit: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
guard let extensionFileNameUIKit else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@@ -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))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user