MESSENGER-4101 matomo consent changes

This commit is contained in:
Frank Rotermund
2023-03-23 13:34:30 +01:00
parent 57de18502d
commit 41479d6629
9 changed files with 127 additions and 34 deletions

View File

@@ -74,7 +74,7 @@ abstract_target 'RiotPods' do
pod 'WeakDictionary', '~> 2.0'
# Piwik for analytics
pod 'MatomoTracker', '~> 7.4.1'
pod 'MatomoTracker', '~> 7.5.2'
# PostHog for analytics
pod 'PostHog', '~> 2.0.0'

View File

@@ -1867,7 +1867,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
MXSession *mxSession = (MXSession*)notif.object;
[BWIAnalytics.sharedTracker trackEvent:@"initMatrixSessions" action:[NSString stringWithFormat:@"%ld", mxSession.state]];
//[BWIAnalytics.sharedTracker trackEvent:@"initMatrixSessions" action:[NSString stringWithFormat:@"%ld", mxSession.state]];
// Check whether the concerned session is a new one
if (mxSession.state == MXSessionStateInitialised)
@@ -2251,6 +2251,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[topVC startActivityIndicator];
}
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
[self logoutSendingRequestServer:YES completion:^(BOOL isLoggedOut) {
if (completion)
{
@@ -2258,7 +2260,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
//[RiotSettings.shared reset];
[BWIBuildSettings.shared reset];
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
[BWIAnalytics.sharedTracker resetUserdefaults];
}
completion (YES);
@@ -2329,6 +2331,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[topVC startActivityIndicator];
}
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
[self logoutSendingRequestServer:YES completion:^(BOOL isLoggedOut) {
if (completion)
{
@@ -2336,7 +2340,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
//[RiotSettings.shared reset];
[BWIBuildSettings.shared reset];
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Logout"];
[BWIAnalytics.sharedTracker resetUserdefaults];
}
completion (YES);
@@ -2431,7 +2435,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (mainSession)
{
[BWIAnalytics.sharedTracker trackEvent:@"handleAppState" action:[MXTools readableSessionState:mainSession.state]];
//[BWIAnalytics.sharedTracker trackEvent:@"handleAppState" action:[MXTools readableSessionState:mainSession.state]];
switch (mainSession.state)
{
@@ -2616,7 +2620,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
MXLogDebug(@"[AppDelegate] hideLaunchAnimation: LaunchAnimation was shown for %.3fms", launchTaskProfile.duration * 1000);
}
[BWIAnalytics.sharedTracker trackEvent:@"hideLaunchAnimation" action:@"Hide"];
//[BWIAnalytics.sharedTracker trackEvent:@"hideLaunchAnimation" action:@"Hide"];
[self->launchAnimationContainerView removeFromSuperview];
self->launchAnimationContainerView = nil;
}
@@ -3980,7 +3984,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
[(MXLegacyCrypto *)crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil];
}
[self dismissKeyVerificationCoordinatorBridgePresenter];
[BWIAnalytics.sharedTracker trackEvent:@"Session" action:@"Login"];
}
- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter

View File

@@ -154,6 +154,8 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
})
}
}
self.bwiCheckForMatomoPromt()
}
func bwiOnUnlockedByPin() {
@@ -702,6 +704,13 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol {
service.createPersonalNotesRoomIfNeeded()
}
}
// bwi: check if matomo promt was shown for this session
private func bwiCheckForMatomoPromt() {
if BWIBuildSettings.shared.bwiMatomoEnabled && BWIAnalytics.sharedTracker.needsToShowPromt() {
self.allChatsViewController.bwiPresentMatomoConsentAlert()
}
}
}
extension AllChatsCoordinator: SignOutFlowPresenterDelegate {
@@ -724,6 +733,7 @@ extension AllChatsCoordinator: SignOutFlowPresenterDelegate {
extension AllChatsCoordinator: AllChatsViewControllerDelegate {
func allChatsViewControllerDidCompleteAuthentication(_ allChatsViewController: AllChatsViewController) {
self.delegate?.splitViewMasterCoordinatorDidCompleteAuthentication(self)
self.bwiCheckForMatomoPromt()
}
func allChatsViewController(_ allChatsViewController: AllChatsViewController, didSelectRoomWithParameters roomNavigationParameters: RoomNavigationParameters, completion: @escaping () -> Void) {

View File

@@ -292,6 +292,37 @@ class AllChatsViewController: HomeViewController {
super.startActivityIndicator()
}
func bwiPresentMatomoConsentAlert() {
let alert = UIAlertController(title: BWIL10n.bwiAnalyticsAlertTitle,
message: BWIL10n.bwiAnalyticsAlertBody(AppInfo.current.displayName),
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertInfoButton,
style: .default,
handler: { action in
if let webviewController = WebViewViewController(url: BWIBuildSettings.shared.applicationPrivacyPolicyUrlString) {
webviewController.title = VectorL10n.settingsPrivacyPolicy
self.present(webviewController, animated: true)
}
}))
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertCancelButton,
style: .default,
handler: { action in
BWIAnalytics.sharedTracker.running = false
}))
alert.addAction(UIAlertAction(title: BWIL10n.bwiAnalyticsAlertOkButton,
style: .cancel,
handler: { action in
BWIAnalytics.sharedTracker.running = true
BWIAnalytics.sharedTracker.trackBwiValue(0, "General", "ConsentGiven", "popup")
}))
self.present(alert, animated: true)
}
// MARK: - Actions
@objc private func showSpaceSelectorAction(sender: AnyObject) {

View File

@@ -1916,6 +1916,10 @@ TableViewSectionsDelegate>
BOOL isOn = sender.on;
BWIAnalytics.sharedTracker.running = isOn;
if (isOn) {
[BWIAnalytics.sharedTracker trackBwiValue:@0 :@"General" :@"ConsentGiven" :@"settings"];
}
}
@end

View File

@@ -1123,9 +1123,7 @@
[alert addAction:[UIAlertAction actionWithTitle:BWIL10n.bwiAnalyticsAlertOkButton style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
BWIAnalytics.sharedTracker.running = YES;
}]];
[self presentViewController:alert animated:YES completion:^() {
[BWIAnalytics.sharedTracker setPromtShown:YES];
}];
[self presentViewController:alert animated:YES completion:nil];
}
@end

View File

@@ -48,7 +48,7 @@ struct DeveloperSettingsView: View {
Alert(title: Text(BWIL10n.bwiSettingsDeveloper), dismissButton: .default(Text("Ok")))
}
Button(action: { showAlert = resetMatomoInfoScreen() }) {
Button(action: { showAlert = resetMatomoInfoScreen(mxSession: session) }) {
Text(BWIL10n.bwiSettingsDeveloperResetMatomoInfo)
.foregroundColor(Color(ThemeService.shared().theme.tintColor))
.font(.system(size: 17))
@@ -122,8 +122,12 @@ fileprivate func createNewPersonalNotesRoom(mxSession: MXSession?) -> Bool {
return true
}
fileprivate func resetMatomoInfoScreen() -> Bool {
BWIAnalytics.sharedTracker.setPromtShown(false)
fileprivate func resetMatomoInfoScreen(mxSession: MXSession?) -> Bool {
guard let mxSession = mxSession else {
return false
}
// FRROT
BWIAnalyticsAccountDataService(mxSession: mxSession)
return true
}

View File

@@ -26,13 +26,13 @@ import MatomoTracker
guard let session = session else {
return false
}
return BWIAnalyticsAccountDataService(mxSession: session).isEnabled()
}
set(enabled) {
guard let session = session else {
return
}
fastRunning = enabled
BWIAnalyticsAccountDataService(mxSession: session).setEnabled(enabled)
}
}
@@ -42,6 +42,9 @@ import MatomoTracker
private let appVersion: String
private let appPlattform = "iOS"
// use internally to not always check for Account data
private var fastRunning: Bool = false
var session: MXSession? = nil
private override init() {
@@ -66,6 +69,7 @@ import MatomoTracker
matomo?.setCustomVariable(withIndex: 1, name: "App Platform", value: appPlattform)
matomo?.setCustomVariable(withIndex: 2, name: "App Version", value: appVersion)
} else {
matomo = nil
}
@@ -75,6 +79,24 @@ import MatomoTracker
return matomo != nil
}
// reset clientId on logout using internal matomo keys
func resetUserdefaults() {
if let userdefaults = UserDefaults(suiteName: "1https://matomo.example.com/matomo.php") {
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
func needsToShowPromt() -> Bool {
if !BWIBuildSettings.shared.bwiEnableErrorTracking {
return false
@@ -84,43 +106,35 @@ import MatomoTracker
return false
}
return !BWIAccountNotificationService(mxSession: session).isNotificationShown(BWIAccountNotificationService.AccountNotifications.CodingKeys.analyticsPromt.rawValue)
}
func setPromtShown(_ shown: Bool) {
guard let session = session else {
return
}
BWIAccountNotificationService(mxSession: session).setNotification(BWIAccountNotificationService.AccountNotifications.CodingKeys.analyticsPromt.rawValue, shown: shown)
return BWIAnalyticsAccountDataService(mxSession: session).needsToShowPromt()
}
func trackScreen(_ screenName: String) {
if running {
if fastRunning {
matomo?.track(view: ["ios", appName, appVersion, screenName], url: nil)
}
}
func trackEvent(_ category: String, action: String) {
if running {
if fastRunning {
matomo?.track(eventWithCategory: category, action: action, url:nil)
}
}
func trackBwiDuration(_ duration: TimeInterval, _ category: String, _ name: String) {
if running {
if fastRunning {
matomo?.track(eventWithCategory: "Metrics", action: category, name: name, number: NSNumber(value: duration), url:nil)
}
}
func trackBwiValue(_ value: NSNumber, _ category: String, _ action: String) {
if running {
if fastRunning {
matomo?.track(eventWithCategory: category, action: action, name: nil, number: value, url:nil)
}
}
func trackBwiValue(_ value: NSNumber, _ category: String, _ action: String, _ name: String) {
if running {
if fastRunning {
matomo?.track(eventWithCategory: category, action: action, name: name, number: value, url:nil)
}
}

View File

@@ -22,10 +22,21 @@ import Foundation
private struct AccountAnalytics: Codable {
enum CodingKeys: String, CodingKey {
case analyticsEnabled = "enabled"
case consent
case time
case platform
case appVersion = "app_version"
}
let consent: Bool
let time: Int
let platform: String
let appVersion: String
func toJsonDict() -> [String : Any] {
return [CodingKeys.consent.rawValue:consent, CodingKeys.time.rawValue:time, CodingKeys.platform.rawValue:platform, CodingKeys.appVersion.rawValue:appVersion]
}
let analyticsEnabled: Bool
}
private enum AccountDataTypes {
@@ -36,17 +47,32 @@ import Foundation
private lazy var serializationService: SerializationServiceType = SerializationService()
init(mxSession: MXSession) {
self.session = mxSession
session = mxSession
}
func needsToShowPromt() -> Bool {
guard let analyticsArray = session.accountData.accountData(forEventType: AccountDataTypes.analytics) as? [String: Any] else {
return true
}
guard analyticsArray[session.myDeviceId] is [String: Any] else {
return true
}
return false
}
func isEnabled() -> Bool {
guard let analyticsDict = session.accountData.accountData(forEventType: AccountDataTypes.analytics) as? [String: Any] else {
guard let analyticsArray = session.accountData.accountData(forEventType: AccountDataTypes.analytics) as? [String: Any] else {
return false
}
guard let deviceId = session.myDeviceId, let analyticsDict = analyticsArray[deviceId] as? [String: Any] else {
return false
}
do {
let analytics: AccountAnalytics = try serializationService.deserialize(analyticsDict)
return analytics.analyticsEnabled
return analytics.consent
} catch {
}
@@ -56,8 +82,11 @@ import Foundation
func setEnabled(_ enabled: Bool) {
var analyticsDict = session.accountData.accountData(forEventType: AccountDataTypes.analytics) ?? [:]
analyticsDict[AccountAnalytics.CodingKeys.analyticsEnabled.rawValue] = enabled
let currentConsent = AccountAnalytics(consent: enabled, time: Int(Date().timeIntervalSince1970*1000), platform: "ios", appVersion: AppInfo.current.appVersion?.bundleShortVersion ?? "")
analyticsDict[session.myDeviceId] = currentConsent.toJsonDict()
session.setAccountData(analyticsDict, forType: AccountDataTypes.analytics, success: nil, failure: nil)
}
}