diff --git a/Podfile b/Podfile index a2e54f0e92..3fb43f4179 100644 --- a/Podfile +++ b/Podfile @@ -69,8 +69,6 @@ abstract_target 'RiotPods' do pod 'KeychainAccess', '~> 4.2.2' pod 'WeakDictionary', '~> 2.0' - # PostHog for analytics - pod 'PostHog', '~> 2.0.0' pod 'Sentry', '~> 7.15.0' pod 'OLMKit' diff --git a/Podfile.lock b/Podfile.lock index 99552b3211..b830adadb2 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -58,7 +58,6 @@ PODS: - OLMKit/olmcpp (= 3.2.12) - OLMKit/olmc (3.2.12) - OLMKit/olmcpp (3.2.12) - - PostHog (2.0.0) - ReadMoreTextView (3.0.1) - Realm (10.27.0): - Realm/Headers (= 10.27.0) @@ -105,7 +104,6 @@ DEPENDENCIES: - MatrixSDK (= 0.27.8) - MatrixSDK/JingleCallStack (= 0.27.8) - OLMKit - - PostHog (~> 2.0.0) - ReadMoreTextView (~> 3.0.1) - Reusable (~> 4.1) - Sentry (~> 7.15.0) @@ -147,7 +145,6 @@ SPEC REPOS: - MatrixSDK - MatrixSDKCrypto - OLMKit - - PostHog - ReadMoreTextView - Realm - Reusable @@ -190,7 +187,6 @@ SPEC CHECKSUMS: MatrixSDK: 4c5a8572a481340ab233451ad36c1322d371fae5 MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 - PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 @@ -208,6 +204,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: b6073389caf93d20d47c9e511f4b9c3e1ad6dc5d +PODFILE CHECKSUM: 3bbda8faf037705f421dad839d6f5b1aef399f99 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2d8489845b..bb13eadb22 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/devicekit/DeviceKit", "state" : { - "revision" : "20e0991f3975916ab0f6d58db84d8bc64f883537", - "version" : "4.7.0" + "revision" : "d37e70cb2646666dcf276d7d3d4a9760a41ff8a6", + "version" : "4.9.0" } }, { @@ -72,13 +72,22 @@ "version" : "0.8.4" } }, + { + "identity" : "posthog-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/PostHog/posthog-ios", + "state" : { + "revision" : "8b2508444962d67aa5f8770074f32d493383dafd", + "version" : "3.2.5" + } + }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections", "state" : { - "revision" : "48254824bb4248676bf7ce56014ff57b142b77eb", - "version" : "1.0.2" + "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", + "version" : "1.1.0" } }, { diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index d9d68e2f85..270f1b3ef9 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -14,7 +14,6 @@ // limitations under the License. // -import PostHog import AnalyticsEvents /// A class responsible for managing a variety of analytics clients diff --git a/Riot/Modules/Analytics/PHGPostHogConfiguration.swift b/Riot/Modules/Analytics/PHGPostHogConfiguration.swift index 8bed049201..875de74e48 100644 --- a/Riot/Modules/Analytics/PHGPostHogConfiguration.swift +++ b/Riot/Modules/Analytics/PHGPostHogConfiguration.swift @@ -16,14 +16,16 @@ import PostHog -extension PHGPostHogConfiguration { - static var standard: PHGPostHogConfiguration? { +extension PostHogConfig { + static var standard: PostHogConfig? { let analyticsConfiguration = BuildSettings.analyticsConfiguration guard analyticsConfiguration.isEnabled else { return nil } - let postHogConfiguration = PHGPostHogConfiguration(apiKey: analyticsConfiguration.apiKey, host: analyticsConfiguration.host) - postHogConfiguration.shouldSendDeviceID = false - + let postHogConfiguration = PostHogConfig(apiKey: analyticsConfiguration.apiKey, host: analyticsConfiguration.host) + // We capture screens manually + postHogConfiguration.captureScreenViews = false + + return postHogConfiguration } } diff --git a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift index ec49716bed..ac22db68f3 100644 --- a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift +++ b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift @@ -20,30 +20,31 @@ import AnalyticsEvents /// An analytics client that reports events to a PostHog server. class PostHogAnalyticsClient: AnalyticsClientProtocol { /// The PHGPostHog object used to report events. - private var postHog: PHGPostHog? + private var postHog: PostHogSDK? /// Any user properties to be included with the next captured event. private(set) var pendingUserProperties: AnalyticsEvent.UserProperties? static let shared = PostHogAnalyticsClient() - var isRunning: Bool { postHog?.enabled ?? false } + var isRunning: Bool { postHog != nil && !postHog!.isOptOut() } func start() { // Only start if analytics have been configured in BuildSettings - guard let configuration = PHGPostHogConfiguration.standard else { return } + guard let configuration = PostHogConfig.standard else { return } if postHog == nil { - postHog = PHGPostHog(configuration: configuration) + PostHogSDK.shared.setup(configuration) + postHog = PostHogSDK.shared } - postHog?.enable() + postHog?.optIn() } func identify(id: String) { if let userProperties = pendingUserProperties { // As user properties overwrite old ones, compactMap the dictionary to avoid resetting any missing properties - postHog?.identify(id, properties: userProperties.properties.compactMapValues { $0 }) + postHog?.identify(id, userProperties: userProperties.properties.compactMapValues { $0 }) pendingUserProperties = nil } else { postHog?.identify(id) @@ -56,10 +57,9 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func stop() { - postHog?.disable() + postHog?.optOut() - // As of PostHog 1.4.4, setting the client to nil here doesn't release - // it. Keep it around to avoid having multiple instances if the user re-enables + self.postHog = nil } func flush() { @@ -67,11 +67,13 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func capture(_ event: AnalyticsEventProtocol) { - postHog?.capture(event.eventName, properties: attachUserProperties(to: event.properties)) + postHog?.capture(event.eventName, properties: event.properties, userProperties: pendingUserProperties?.properties.compactMapValues { $0 }) + // Pending user properties have been added + self.pendingUserProperties = nil } func screen(_ event: AnalyticsScreenProtocol) { - postHog?.screen(event.screenName.rawValue, properties: attachUserProperties(to: event.properties)) + postHog?.screen(event.screenName.rawValue, properties: event.properties) } func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) { @@ -87,22 +89,6 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { numSpaces: userProperties.numSpaces ?? pendingUserProperties.numSpaces) } - // MARK: - Private - - /// Given a dictionary containing properties from an event, this method will return those properties - /// with any pending user properties included under the `$set` key. - /// - Parameter properties: A dictionary of properties from an event. - /// - Returns: The `properties` dictionary with any user properties included. - private func attachUserProperties(to properties: [String: Any]) -> [String: Any] { - guard isRunning, let userProperties = pendingUserProperties else { return properties } - - var properties = properties - - // As user properties overwrite old ones via $set, compactMap the dictionary to avoid resetting any missing properties - properties["$set"] = userProperties.properties.compactMapValues { $0 } - pendingUserProperties = nil - return properties - } } extension PostHogAnalyticsClient: RemoteFeaturesClientProtocol { diff --git a/Riot/target.yml b/Riot/target.yml index 352988bf33..c95d3cb3aa 100644 --- a/Riot/target.yml +++ b/Riot/target.yml @@ -49,6 +49,7 @@ targets: - package: WysiwygComposer - package: DeviceKit - package: DTCoreText + - package: PostHog configFiles: Debug: Debug.xcconfig diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 6bc5a474dc..f046bc0fde 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -35,6 +35,7 @@ targets: - package: AnalyticsEvents - package: DeviceKit - package: DTCoreText + - package: PostHog configFiles: Debug: Debug.xcconfig diff --git a/RiotTests/AnalyticsTests.swift b/RiotTests/AnalyticsTests.swift index 33ed283895..73f3f66b1c 100644 --- a/RiotTests/AnalyticsTests.swift +++ b/RiotTests/AnalyticsTests.swift @@ -127,7 +127,8 @@ class AnalyticsTests: XCTestCase { XCTAssertEqual(client.pendingUserProperties?.ftueUseCaseSelection, .PersonalMessaging, "The use case selection should match.") // When sending an event (tests run under Debug configuration so this is sent to the development instance) - client.screen(AnalyticsEvent.MobileScreen(durationMs: nil, screenName: .Home)) + let event = AnalyticsEvent.Signup(authenticationType: .Other) + client.capture(event) // Then the properties should be cleared XCTAssertNil(client.pendingUserProperties, "The user properties should be cleared.") diff --git a/project.yml b/project.yml index c442193824..a666fb1b76 100644 --- a/project.yml +++ b/project.yml @@ -66,3 +66,6 @@ packages: DTCoreText: url: https://github.com/Cocoanetics/DTCoreText version: 1.6.26 + PostHog: + url: https://github.com/PostHog/posthog-ios + minorVersion: 3.2.5