Analytics improvement (#9)
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Co-authored-by: Quentin Bandera <q.bandera@openium.fr> Reviewed-on: #9 Co-authored-by: Loris Perret <l.perret@openium.fr> Co-committed-by: Loris Perret <l.perret@openium.fr>
This commit is contained in:
83
README.md
83
README.md
@ -133,7 +133,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typaloas `typealias Tags = String`.
|
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typealias `typealias Tags = String`.
|
||||||
|
|
||||||
|
|
||||||
## Analytics
|
## Analytics
|
||||||
@ -141,7 +141,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site.
|
Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/analytics.yml" \
|
||||||
--target "matomo firebase" \
|
--target "matomo firebase" \
|
||||||
--extension-output-path "./Analytics/Generated" \
|
--extension-output-path "./Analytics/Generated" \
|
||||||
--extension-name "AppAnalytics" \
|
--extension-name "AppAnalytics" \
|
||||||
@ -159,7 +159,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typaloas `typealias Analytics = String`.
|
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typealias `typealias Analytics = String`.
|
||||||
|
|
||||||
### YAML
|
### YAML
|
||||||
|
|
||||||
@ -186,19 +186,83 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
7. `comments` *(optional)*
|
7. `comments` *(optional)*
|
||||||
8. `parameters` *(optional)*
|
8. `parameters` *(optional)*
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
You can use parameters in generate methods.
|
You can use parameters in generate methods.
|
||||||
|
|
||||||
1. `name`: name of the parameter
|
1. `name`: name of the parameter
|
||||||
2. `type`: type of the parameter (Int, String, Bool, Double)
|
2. `type`: type of the parameter (Int, String, Bool, Double)
|
||||||
|
3. `value`: value of the parameter
|
||||||
|
4. `defaultValue`: defaultValue of the parameter
|
||||||
3. `replaceIn` *(optional)*
|
3. `replaceIn` *(optional)*
|
||||||
|
|
||||||
|
**Value**
|
||||||
|
|
||||||
|
If you want to send another parameter with a static value. For example, you want to send to which screen the event is triggered.
|
||||||
|
You can add the parameter 'screenName' for example and its 'value' is 'Home'. With this, you do not need to specify the value in the function call.
|
||||||
|
|
||||||
|
**DefaultValue**
|
||||||
|
|
||||||
|
If you want ta add a parameter in the call of the function but you want to make it optionnal with a default value you need to use this property.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: _TITLE_
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: title
|
||||||
|
type: String
|
||||||
|
defaultValue: someTitle
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated method will be:
|
||||||
|
```
|
||||||
|
logIdOfTag(title: String = "someTitle")
|
||||||
|
```
|
||||||
|
|
||||||
**Replace in**
|
**Replace in**
|
||||||
|
|
||||||
This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*.
|
This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*.
|
||||||
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase)
|
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase).
|
||||||
|
You can't use `value`and `replaceIn`in thge same time.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: _TITLE_
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: title
|
||||||
|
type: String
|
||||||
|
replaceIn: name
|
||||||
|
```
|
||||||
|
|
||||||
|
In this sample, we want to add the parameter `title` in the field `name`. So, we need to place `_TITLE_` in the field `name`.
|
||||||
|
|
||||||
|
The generated method will be:
|
||||||
|
```
|
||||||
|
logIdOfTag(title: String)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also want to replace a parameter in an other parameter. You can do this with the `replaceIn` property. The condition is that the parameter which will use the `replaceIn`need to have the `value`property
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: title
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: something
|
||||||
|
type: String
|
||||||
|
value: test _TEXT_
|
||||||
|
- name: text
|
||||||
|
type: String
|
||||||
|
replaceIn: something
|
||||||
|
```
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
@ -287,6 +351,15 @@ tags:
|
|||||||
extensionName: String?
|
extensionName: String?
|
||||||
extensionSuffix: String?
|
extensionSuffix: String?
|
||||||
staticMembers: Bool?
|
staticMembers: Bool?
|
||||||
|
|
||||||
|
analytics:
|
||||||
|
-
|
||||||
|
inputFile: String
|
||||||
|
target: String
|
||||||
|
extensionOutputPath: String
|
||||||
|
extensionName: String?
|
||||||
|
extensionSuffix: String?
|
||||||
|
staticMembers: Bool?
|
||||||
```
|
```
|
||||||
|
|
||||||
### Multiple configurations
|
### Multiple configurations
|
||||||
|
@ -6,14 +6,20 @@ import FirebaseAnalytics
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Matomo
|
// MARK: - Matomo
|
||||||
@ -48,8 +54,11 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
|
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
guard !tracker.isOptedOut else { return }
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
||||||
@ -65,8 +74,6 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard !tracker.isOptedOut else { return }
|
|
||||||
|
|
||||||
tracker.track(
|
tracker.track(
|
||||||
eventWithCategory: category,
|
eventWithCategory: category,
|
||||||
action: action,
|
action: action,
|
||||||
@ -75,32 +82,27 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
url: nil
|
url: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
tracker.isOptedOut = !enable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
Analytics.logEvent(
|
if path.isEmpty == false {
|
||||||
AnalyticsEventScreenView,
|
parameters["path"] = path + "/iOS" as NSObject
|
||||||
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 {
|
if let supplementaryParameters = params {
|
||||||
for (newKey, newValue) in supplementaryParameters {
|
for (newKey, newValue) in supplementaryParameters {
|
||||||
@ -115,10 +117,57 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
AnalyticsEventScreenView,
|
||||||
parameters: parameters
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Traker Type
|
||||||
|
|
||||||
|
enum TrackerType: CaseIterable {
|
||||||
|
case matomo
|
||||||
|
case firebase
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
@ -127,33 +176,61 @@ class AnalyticsManager {
|
|||||||
|
|
||||||
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: - 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) {
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +242,7 @@ class AnalyticsManager {
|
|||||||
) {
|
) {
|
||||||
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,
|
||||||
@ -177,31 +254,39 @@ class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - section_one
|
// MARK: - section_one
|
||||||
|
|
||||||
func logScreenS1DefOne(title: String) {
|
static func logScreenS1DefOne(title: String) {
|
||||||
logScreen(
|
AnalyticsManager.shared.logScreen(
|
||||||
name: "s1 def one \(title)",
|
name: "s1 def one \(title)",
|
||||||
path: "s1_def_one/\(title)"
|
path: "s1_def_one/\(title)",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logEventS1DefTwo(title: String, count: String) {
|
static func logEventS1DefTwo(
|
||||||
logEvent(
|
title: String,
|
||||||
|
count: String,
|
||||||
|
test2: String = "test"
|
||||||
|
) {
|
||||||
|
AnalyticsManager.shared.logEvent(
|
||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [
|
params: [
|
||||||
"title": title,
|
"title": title,
|
||||||
"count": count
|
"count": count,
|
||||||
|
"test": "test",
|
||||||
|
"test2": test2
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - section_two
|
// MARK: - section_two
|
||||||
|
|
||||||
func logScreenS2DefOne() {
|
static func logScreenS2DefOne() {
|
||||||
logScreen(
|
AnalyticsManager.shared.logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/"
|
path: "s2_def_one/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ categories:
|
|||||||
type: String
|
type: String
|
||||||
- name: count
|
- name: count
|
||||||
type: String
|
type: String
|
||||||
|
- name: test
|
||||||
|
type: String
|
||||||
|
value: test
|
||||||
|
- name: test2
|
||||||
|
type: String
|
||||||
|
defaultValue: test
|
||||||
|
|
||||||
- id: section_two
|
- id: section_two
|
||||||
screens:
|
screens:
|
||||||
|
@ -50,14 +50,15 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/sampleTags.txt
|
|||||||
--extension-name "Tags" \
|
--extension-name "Tags" \
|
||||||
--extension-suffix "GenAllScript"
|
--extension-suffix "GenAllScript"
|
||||||
|
|
||||||
#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 $FORCE_FLAG "./Tags/sampleTags.yml" \
|
||||||
--target "matomo firebase" \
|
--target "firebase matomo" \
|
||||||
--extension-output-path "./Tags/Generated" \
|
--extension-output-path "./Tags/Generated" \
|
||||||
--extension-name "Analytics" \
|
--extension-name "Analytics" \
|
||||||
--extension-suffix "GenAllScript"
|
--extension-suffix "GenAllScript" \
|
||||||
|
--static-members true
|
||||||
|
|
||||||
echo "\n-------------------------\n"
|
echo "\n-------------------------\n"
|
||||||
|
|
||||||
|
@ -90,35 +90,75 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||||
|
|
||||||
\(getImport(targets: targets))
|
\(Self.getImport(targets: targets))
|
||||||
|
|
||||||
|
\(Self.getAnalyticsProtocol(targets: targets))
|
||||||
|
|
||||||
|
\(Self.getTrackerTypeEnum())
|
||||||
|
|
||||||
\(getAnalyticsProtocol(targets: targets))
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var managers: [AnalyticsManagerProtocol] = []
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
\(getEnabledContent())
|
\(Self.getEnabledContent())
|
||||||
|
|
||||||
\(getAnalyticsProperties(targets: targets))
|
\(Self.getAnalyticsProperties(targets: targets))
|
||||||
|
|
||||||
\(getPrivateLogFunction())
|
\(Self.getPrivateLogFunction())
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getTrackerTypeEnum() -> String {
|
||||||
|
var result: [String] = []
|
||||||
|
TrackerType.allCases.forEach { type in
|
||||||
|
result.append(" case \(type)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return """
|
||||||
|
// MARK: - Traker Type
|
||||||
|
|
||||||
|
enum TrackerType: CaseIterable {
|
||||||
|
\(result.joined(separator: "\n"))
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getEnabledContent() -> String {
|
private static func getEnabledContent() -> String {
|
||||||
"""
|
"""
|
||||||
private var isEnabled: Bool = true
|
private var isEnabled: Bool {
|
||||||
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - 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)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
@ -126,6 +166,8 @@ enum AnalyticsGenerator {
|
|||||||
private static func getImport(targets: [TrackerType]) -> String {
|
private static func getImport(targets: [TrackerType]) -> String {
|
||||||
var result: [String] = []
|
var result: [String] = []
|
||||||
|
|
||||||
|
result.append("import Foundation")
|
||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
result.append("import MatomoTracker")
|
result.append("import MatomoTracker")
|
||||||
}
|
}
|
||||||
@ -138,11 +180,19 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
private static func getPrivateLogFunction() -> String {
|
private static func getPrivateLogFunction() -> String {
|
||||||
"""
|
"""
|
||||||
private func logScreen(name: String, path: String) {
|
private func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard isEnabled else { return }
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +204,7 @@ enum AnalyticsGenerator {
|
|||||||
) {
|
) {
|
||||||
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,
|
||||||
@ -179,16 +229,14 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
content.append("""
|
content.append("""
|
||||||
managers.append(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
MatomoAnalyticsManager(
|
siteId: siteId,
|
||||||
siteId: siteId,
|
url: url
|
||||||
url: url
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
content.append(" managers.append(FirebaseAnalyticsManager())")
|
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -204,14 +252,20 @@ enum AnalyticsGenerator {
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -13,10 +13,11 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
Self.header,
|
FirebaseGenerator.header,
|
||||||
Self.logScreen,
|
FirebaseGenerator.logScreen,
|
||||||
Self.logEvent,
|
FirebaseGenerator.logEvent,
|
||||||
Self.footer
|
FirebaseGenerator.enable,
|
||||||
|
FirebaseGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@ -33,11 +34,31 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
private static var logScreen: String {
|
private static var logScreen: String {
|
||||||
"""
|
"""
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
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(
|
Analytics.logEvent(
|
||||||
AnalyticsEventScreenView,
|
AnalyticsEventScreenView,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
@ -56,10 +77,17 @@ enum FirebaseGenerator {
|
|||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:NSObject] = [
|
||||||
"action": action as NSObject,
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
"category": category as NSObject,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if category.isEmpty == false {
|
||||||
|
parameters["AnalyticsParameterItemCategory"] = category as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if action.isEmpty == false {
|
||||||
|
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
|
||||||
@ -73,13 +101,21 @@ enum FirebaseGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
AnalyticsEventSelectContent,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static var enable: String {
|
||||||
|
"""
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,12 @@ enum MatomoGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
Self.header,
|
MatomoGenerator.header,
|
||||||
Self.setup,
|
MatomoGenerator.setup,
|
||||||
Self.logScreen,
|
MatomoGenerator.logScreen,
|
||||||
Self.logEvent,
|
MatomoGenerator.logEvent,
|
||||||
Self.footer
|
MatomoGenerator.enable,
|
||||||
|
MatomoGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@ -66,8 +67,11 @@ enum MatomoGenerator {
|
|||||||
|
|
||||||
private static var logScreen: String {
|
private static var logScreen: String {
|
||||||
"""
|
"""
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
guard !tracker.isOptedOut else { return }
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
||||||
@ -88,8 +92,6 @@ enum MatomoGenerator {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard !tracker.isOptedOut else { return }
|
|
||||||
|
|
||||||
tracker.track(
|
tracker.track(
|
||||||
eventWithCategory: category,
|
eventWithCategory: category,
|
||||||
action: action,
|
action: action,
|
||||||
@ -98,6 +100,15 @@ enum MatomoGenerator {
|
|||||||
url: nil
|
url: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private static var enable: String {
|
||||||
|
"""
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
tracker.isOptedOut = !enable
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,17 +51,23 @@ class AnalyticsDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func getParameters() -> String {
|
private func getParameters() -> String {
|
||||||
var params = parameters
|
|
||||||
var result: String
|
var result: String
|
||||||
|
|
||||||
if type == .screen {
|
let paramsString = parameters.compactMap { parameter -> String? in
|
||||||
params = params.filter { param in
|
guard parameter.value.isEmpty else { return nil }
|
||||||
!param.replaceIn.isEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let paramsString = params.map { parameter in
|
let defaultValue: String
|
||||||
"\(parameter.name): \(parameter.type)"
|
switch parameter.type {
|
||||||
|
case .bool:
|
||||||
|
defaultValue = "\(parameter.defaultValue.lowercased())"
|
||||||
|
case .int, .double:
|
||||||
|
defaultValue = "\(parameter.defaultValue)"
|
||||||
|
case .string:
|
||||||
|
defaultValue = "\"\(parameter.defaultValue)\""
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
|
||||||
|
return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramsString.count > 2 {
|
if paramsString.count > 2 {
|
||||||
@ -87,7 +93,10 @@ class AnalyticsDefinition {
|
|||||||
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: break
|
default:
|
||||||
|
if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
|
||||||
|
param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +111,18 @@ class AnalyticsDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
supplementaryParams.forEach { param in
|
supplementaryParams.forEach { param in
|
||||||
params.append("\"\(param.name)\": \(param.name)")
|
if param.value.isEmpty {
|
||||||
|
params.append("\"\(param.name)\": \(param.name)")
|
||||||
|
} else {
|
||||||
|
switch param.type {
|
||||||
|
case .bool:
|
||||||
|
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
||||||
|
case .int, .double:
|
||||||
|
params.append("\"\(param.name)\": \(param.value)")
|
||||||
|
case .string:
|
||||||
|
params.append("\"\(param.name)\": \"\(param.value)\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.count > 1 {
|
if params.count > 1 {
|
||||||
@ -116,14 +136,15 @@ class AnalyticsDefinition {
|
|||||||
[\(params.joined(separator: ", "))]
|
[\(params.joined(separator: ", "))]
|
||||||
"""
|
"""
|
||||||
} else {
|
} else {
|
||||||
result = "[:]"
|
result = "nil"
|
||||||
}
|
}
|
||||||
|
|
||||||
if type == .screen {
|
if type == .screen {
|
||||||
return """
|
return """
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "\(name)",
|
name: "\(name)",
|
||||||
path: "\(path)"
|
path: "\(path)",
|
||||||
|
params: \(result)
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
} else {
|
} else {
|
||||||
@ -153,7 +174,7 @@ class AnalyticsDefinition {
|
|||||||
replaceIn()
|
replaceIn()
|
||||||
return """
|
return """
|
||||||
static func \(getFuncName())\(getParameters()) {
|
static func \(getFuncName())\(getParameters()) {
|
||||||
\(getlogFunction())
|
AnalyticsManager.shared.\(getlogFunction())
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -46,5 +46,7 @@ struct AnalyticsParameterDTO: Codable {
|
|||||||
|
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: String
|
||||||
|
var value: String?
|
||||||
|
var defaultValue: String?
|
||||||
var replaceIn: String?
|
var replaceIn: String?
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,17 @@ class AnalyticsParameter {
|
|||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: ParameterType
|
||||||
|
var value: String
|
||||||
|
var defaultValue: String
|
||||||
var replaceIn: [String] = []
|
var replaceIn: [String] = []
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
|
|
||||||
init(name: String, type: String) {
|
init(name: String, type: ParameterType, value: String, defaultValue: String) {
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = type
|
self.type = type
|
||||||
|
self.value = value
|
||||||
|
self.defaultValue = defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
Sources/ResgenSwift/Analytics/Model/ParameterType.swift
Normal file
15
Sources/ResgenSwift/Analytics/Model/ParameterType.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// File.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 17/07/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ParameterType: String {
|
||||||
|
case string = "String"
|
||||||
|
case int = "Int"
|
||||||
|
case double = "Double"
|
||||||
|
case bool = "Bool"
|
||||||
|
}
|
@ -67,25 +67,58 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||||
parameters.map { dtoParameter in
|
func verify(value: String?, for type: ParameterType) {
|
||||||
|
guard let value, value.isEmpty == false else { return }
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .int:
|
||||||
|
if Int(value) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .bool:
|
||||||
|
if Bool(value.lowercased()) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .double:
|
||||||
|
if Double(value) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .string:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.map { dtoParameter in
|
||||||
// Type
|
// Type
|
||||||
let type = dtoParameter.type.uppercasedFirst()
|
let type = dtoParameter.type.uppercasedFirst()
|
||||||
|
|
||||||
guard
|
guard let typeEnum = ParameterType(rawValue: type) else {
|
||||||
type == "String" ||
|
|
||||||
type == "Int" ||
|
|
||||||
type == "Double" ||
|
|
||||||
type == "Bool"
|
|
||||||
else {
|
|
||||||
let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)")
|
let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dtoParameter.value != nil, dtoParameter.replaceIn != nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(value: dtoParameter.value, for: typeEnum)
|
||||||
|
verify(value: dtoParameter.defaultValue, for: typeEnum)
|
||||||
|
|
||||||
let parameter = AnalyticsParameter(
|
let parameter = AnalyticsParameter(
|
||||||
name: dtoParameter.name,
|
name: dtoParameter.name,
|
||||||
type: type
|
type: typeEnum,
|
||||||
|
value: dtoParameter.value ?? "",
|
||||||
|
defaultValue: dtoParameter.defaultValue ?? ""
|
||||||
)
|
)
|
||||||
|
|
||||||
if let replaceIn = dtoParameter.replaceIn {
|
if let replaceIn = dtoParameter.replaceIn {
|
||||||
@ -114,7 +147,7 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let parameters {
|
if let parameters {
|
||||||
definition.parameters = getParameters(from: parameters)
|
definition.parameters = AnalyticsFileParser.getParameters(from: parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
@ -140,6 +173,8 @@ class AnalyticsFileParser {
|
|||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
definition.path = path
|
||||||
|
} else if let path = screen.path {
|
||||||
definition.path = path
|
definition.path = path
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +211,14 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
definition.action = action
|
definition.action = action
|
||||||
|
} else {
|
||||||
|
if let category = event.category {
|
||||||
|
definition.category = category
|
||||||
|
}
|
||||||
|
|
||||||
|
if let action = event.action {
|
||||||
|
definition.action = action
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
|
Reference in New Issue
Block a user