diff --git a/Config/BWIBuildSettings.swift b/Config/BWIBuildSettings.swift index aef0bb53a..42e9a8109 100644 --- a/Config/BWIBuildSettings.swift +++ b/Config/BWIBuildSettings.swift @@ -534,8 +534,15 @@ class BWIBuildSettings: NSObject { var bwiShowHappyBirthdayCampaign = false var bwiHappyBirthdayCampaignIdentifier: String = "2022" var bwiDisableSecuritySettingsUntrustedDevices = true + + + // MARK: - analytics with matomo var bwiMatomoTrackingDefaultState = false var bwiMatomoEnabled = false + var matomoNameProd = "" + var matomoNameBeta = "" + var matomoServerProd = "" + var bwiShowNewFeatures = true // MARK: - Message Bubbles bwi show in our menu and only for beta builds diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 82507f6f9..8f65bf50d 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -52,6 +52,7 @@ targets: - path: ../bwi/NotificationTimes/Date+fromHourMinute.swift - path: ../bwi/MatomoAnalytics/BWIAnalytics.swift - path: ../bwi/MatomoAnalytics/BWIAnalyticsAccountDataService.swift + - path: ../bwi/MatomoAnalytics/AnalyticsConfiguration.swift - path: ../bwi/MatomoAnalytics/E2EEError.swift - path: ../Riot/Managers/Settings/RiotSettings.swift - path: ../Config/BuildSettings.swift diff --git a/bwi/AppConfig/AppConfig.swift b/bwi/AppConfig/AppConfig.swift index 697db725d..5b50a41cb 100644 --- a/bwi/AppConfig/AppConfig.swift +++ b/bwi/AppConfig/AppConfig.swift @@ -23,5 +23,4 @@ struct AppConfig: Codable, Equatable { var contentScannerUrl: String? = nil var pusherUrl: String? = nil var permalinkUrl: String? = nil - var analyticsURL: String? = nil } diff --git a/bwi/AppConfig/AppConfigService.swift b/bwi/AppConfig/AppConfigService.swift index 955c68e9d..54ec43b91 100644 --- a/bwi/AppConfig/AppConfigService.swift +++ b/bwi/AppConfig/AppConfigService.swift @@ -84,10 +84,6 @@ extension UserDefaults } func registerForAppConfig() { -// configObserver = UserDefaults.standard.observe(\.appConfigData, options:[.new,.old]) -// { (object, change) in -// self.handleAppConfig() -// } NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { [self] (note) in handleAppConfig() @@ -162,14 +158,4 @@ extension UserDefaults return BWIBuildSettings.shared.clientPermalinkBaseUrl } } - - func analyticsUrl() -> String { - if let url = appConfig.analyticsURL { - return "https://" + url - } else if let url = ServerURLHelper.shared.analytics() { - return url - } else { - return BWIBuildSettings.shared.bwiAnalyticsServerUrlString - } - } } diff --git a/bwi/MatomoAnalytics/AnalyticsConfiguration.swift b/bwi/MatomoAnalytics/AnalyticsConfiguration.swift new file mode 100644 index 000000000..9a50ef969 --- /dev/null +++ b/bwi/MatomoAnalytics/AnalyticsConfiguration.swift @@ -0,0 +1,99 @@ +// +/* + * Copyright (c) 2022 BWI GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + + +struct AnalyticsConfiguration { + + private enum ConfigType: String { + case productive, beta, test, userdefined, undefined + } + + private struct Config { + let baseUrl: String + let siteID: String + let sendMessageDimensionIndex: Int + } + + private var currentConfigs: [String:Config] = [:] + private var selectedConfigType: ConfigType = .undefined + + mutating func readConfig( jsonFile: String ) { + let fileURL = URL(fileURLWithPath: jsonFile) + + do { + let jsonData = try Data(contentsOf: fileURL) + let json = try JSONSerialization.jsonObject(with: jsonData, options: []) + + if let dictionary = json as? [String: Any] { + if let configArray = dictionary["config"] as? [[String: Any]] { + for configDict in configArray { + // Access the values in each dictionary + if let type = configDict["type"] as? String, + let baseURL = configDict["baseURL"] as? String, + let siteID = configDict["siteID"] as? String, + let sendMessageDimensionIndex = configDict["sendMessageDimensionIndex"] as? String { + currentConfigs[type] = Config(baseUrl: baseURL, siteID: siteID, sendMessageDimensionIndex: Int(sendMessageDimensionIndex)!) + } + } + } + } + } catch { + } + + selectedConfigType = self.computeConfigurationType() + } + + func selectedBaseURL() -> String? { + if let config = currentConfigs[selectedConfigType.rawValue] { + return config.baseUrl + } + return nil + } + + func selectedSiteID() -> String? { + if let config = currentConfigs[selectedConfigType.rawValue] { + return config.siteID + } + return nil + } + + func selectedSendMessageDimensionIndex() -> Int? { + if let config = currentConfigs[selectedConfigType.rawValue] { + return config.sendMessageDimensionIndex + } + return nil + } + + private func computeConfigurationType() -> ConfigType { + if currentConfigs[ConfigType.userdefined.rawValue] != nil { + return .userdefined + } + if AppInfo.current.displayName == BWIBuildSettings.shared.matomoNameProd { + return .productive + } + if AppInfo.current.displayName == BWIBuildSettings.shared.matomoNameBeta { + if AppConfigService.shared.serverUrl() == BWIBuildSettings.shared.matomoServerProd { + return .beta + } else { + return .test + } + } + return .undefined + } +} diff --git a/bwi/MatomoAnalytics/BWIAnalytics.swift b/bwi/MatomoAnalytics/BWIAnalytics.swift index 2cb973d36..e9d4d7f82 100644 --- a/bwi/MatomoAnalytics/BWIAnalytics.swift +++ b/bwi/MatomoAnalytics/BWIAnalytics.swift @@ -47,6 +47,8 @@ import MatomoTracker private var session: MXSession? = nil + private var analyticsConfig: AnalyticsConfiguration + private override init() { if !BWIBuildSettings.shared.secondaryAppName.isEmpty { appName = BWIBuildSettings.shared.secondaryAppName @@ -55,16 +57,26 @@ import MatomoTracker } appVersion = AppInfo.current.appVersion?.bundleShortVersion ?? "" + analyticsConfig = AnalyticsConfiguration() + if BWIBuildSettings.shared.bwiMatomoEnabled { + + if let path = Bundle.main.path(forResource: "trackingConfig", ofType: "json") { + analyticsConfig.readConfig(jsonFile: path) + } + // bwi: Analytics use custom config - guard let url = URL(string: AppConfigService.shared.analyticsUrl()) else { + guard let urlPath = analyticsConfig.selectedBaseURL(), + let url = URL(string: urlPath), + let siteID = analyticsConfig.selectedSiteID() else { matomo = nil return } - matomo = MatomoTracker.init(siteId: BWIBuildSettings.shared.bwiAnalyticsAppId, baseURL:url, userAgent: nil) + matomo = MatomoTracker.init(siteId: siteID, baseURL:url, userAgent: nil) matomo?.isOptedOut = false + matomo?.dispatchInterval = 5.0 matomo?.logger = DefaultLogger(minLevel: .verbose) @@ -91,19 +103,19 @@ import MatomoTracker // reset clientId on logout using internal matomo keys func resetUserdefaults() { // bwi: Analytics use custom config - let suiteName = BWIBuildSettings.shared.bwiAnalyticsAppId + AppConfigService.shared.analyticsUrl() - if let userdefaults = UserDefaults(suiteName: suiteName) { - userdefaults.removeObject(forKey: "PiwikTotalNumberOfVistsKey") - userdefaults.removeObject(forKey: "PiwikCurrentVisitTimestampKey") - userdefaults.removeObject(forKey: "PiwikPreviousVistsTimestampKey") - userdefaults.removeObject(forKey: "PiwikFirstVistsTimestampKey") - userdefaults.removeObject(forKey: "PiwikVisitorIDKey") - userdefaults.removeObject(forKey: "PiwikForcedVisitorIDKey") - userdefaults.removeObject(forKey: "PiwikVisitorUserIDKey") - userdefaults.removeObject(forKey: "PiwikOptOutKey") - userdefaults.removeObject(forKey: "PiwikLastOrderDateKey") - } - + if let siteID = analyticsConfig.selectedSiteID(), + let baseURL = analyticsConfig.selectedBaseURL(), + let userdefaults = UserDefaults(suiteName: siteID + baseURL) { + userdefaults.removeObject(forKey: "PiwikTotalNumberOfVistsKey") + userdefaults.removeObject(forKey: "PiwikCurrentVisitTimestampKey") + userdefaults.removeObject(forKey: "PiwikPreviousVistsTimestampKey") + userdefaults.removeObject(forKey: "PiwikFirstVistsTimestampKey") + userdefaults.removeObject(forKey: "PiwikVisitorIDKey") + userdefaults.removeObject(forKey: "PiwikForcedVisitorIDKey") + userdefaults.removeObject(forKey: "PiwikVisitorUserIDKey") + userdefaults.removeObject(forKey: "PiwikOptOutKey") + userdefaults.removeObject(forKey: "PiwikLastOrderDateKey") + } } // Uses Userdefaults instead of Account Data because it needs to be shown on every login @@ -158,9 +170,11 @@ import MatomoTracker func trackSlowMessage( dimension: String, value: Int) { if fastRunning { // bwi: Analytics use custom config - matomo?.setDimension(dimension, forIndex: 2) - matomo?.track(eventWithCategory: "Performance", action: "SendMessage", name: nil, number: NSNumber(value: value), url:nil) - matomo?.remove(dimensionAtIndex: 2) + if let dimensionIndex = analyticsConfig.selectedSendMessageDimensionIndex() { + matomo?.setDimension(dimension, forIndex: dimensionIndex) + matomo?.track(eventWithCategory: "Performance", action: "SendMessage", name: nil, number: NSNumber(value: value), url:nil) + matomo?.remove(dimensionAtIndex: dimensionIndex) + } } } } @@ -227,9 +241,9 @@ extension BWIAnalytics : MXAnalyticsDelegate { func trackE2EEError(_ errorCode: Int) { if let errorCode = AnalyticsE2EEErrorCode(rawValue: errorCode) { - self.trackBwiValue(NSNumber(value: 1), "Encryption", "SendMessage", errorCode.description) + self.trackBwiValue(NSNumber(value: 1), "Encryption", "ViewMessage", errorCode.description) } else { - self.trackBwiValue(NSNumber(value: 1), "Encryption", "SendMessage", "Unknown_Error") + self.trackBwiValue(NSNumber(value: 1), "Encryption", "ViewMessage", "Unknown_Error") } } @@ -237,11 +251,11 @@ extension BWIAnalytics : MXAnalyticsDelegate { func trackE2EEErrors(_ reason: DecryptionFailureReason, count: Int) { switch reason { case .unspecified: - self.trackBwiValue(NSNumber(value: count), "Encryption", "SendMessage", "Unknown_Error") + self.trackBwiValue(NSNumber(value: count), "Encryption", "ViewMessage", "Unknown_Error") case .olmIndexError: - self.trackBwiValue(NSNumber(value: count), "Encryption", "SendMessage", AnalyticsE2EEErrorCode(rawValue: 3)!.description) + self.trackBwiValue(NSNumber(value: count), "Encryption", "ViewMessage", AnalyticsE2EEErrorCode(rawValue: 3)!.description) case .olmKeysNotSent: - self.trackBwiValue(NSNumber(value: count), "Encryption", "SendMessage", AnalyticsE2EEErrorCode(rawValue: 4)!.description) + self.trackBwiValue(NSNumber(value: count), "Encryption", "ViewMessage", AnalyticsE2EEErrorCode(rawValue: 4)!.description) } } } diff --git a/bwi/ServerURLs/ServerURLHelper.swift b/bwi/ServerURLs/ServerURLHelper.swift index 81f7b34a8..026db48f5 100644 --- a/bwi/ServerURLs/ServerURLHelper.swift +++ b/bwi/ServerURLs/ServerURLHelper.swift @@ -51,9 +51,8 @@ import Foundation if let server = dict[serverUrlKey], let flavor = dict[flavorUrlKey], let name = dict[nameKey], - let permalink = dict[permalinkKey] , - let analytics = dict[analyticsKey] { - serverSettings.append(ServerSetting(name:name, serverUrl: server, pusherUrl: "", flavor: flavor, permalink:permalink, analytics: analytics)) + let permalink = dict[permalinkKey] { + serverSettings.append(ServerSetting(name:name, serverUrl: server, pusherUrl: "", flavor: flavor, permalink:permalink, analytics: "")) } } }