Skip to content

Commit

Permalink
fix: flutter session replay (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
marandaneto authored Nov 28, 2024
1 parent 23103cf commit ff05a7a
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next

- no user facing changes

## 3.15.7 - 2024-11-25

- fix: detect and mask out system photo library and user photos ([#261](https://github.com/PostHog/posthog-ios/pull/261))
Expand Down
4 changes: 4 additions & 0 deletions PostHog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
6999919A2AFE1BAB000DCB78 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 699991992AFE1BAB000DCB78 /* AppDelegate.swift */; };
699C5FE62C20178E007DB818 /* UUIDUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 699C5FE52C20178E007DB818 /* UUIDUtils.swift */; };
699C5FEF2C20242A007DB818 /* UUIDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 699C5FEE2C20242A007DB818 /* UUIDTest.swift */; };
69B7F60C2CF7703400A48BCC /* UIImage+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B7F6062CF7702D00A48BCC /* UIImage+Util.swift */; };
69BA38D72B888E8500AA69D6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 69BA38D62B888E8500AA69D6 /* PrivacyInfo.xcprivacy */; };
69ED1A5C2C7F15F300FE7A91 /* PostHogSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69ED1A5B2C7F15F300FE7A91 /* PostHogSessionManager.swift */; };
69ED1A882C89B73100FE7A91 /* PostHogSwiftUIViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69ED1A872C89B73100FE7A91 /* PostHogSwiftUIViewModifiers.swift */; };
Expand Down Expand Up @@ -358,6 +359,7 @@
699991992AFE1BAB000DCB78 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
699C5FE52C20178E007DB818 /* UUIDUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UUIDUtils.swift; sourceTree = "<group>"; };
699C5FEE2C20242A007DB818 /* UUIDTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UUIDTest.swift; sourceTree = "<group>"; };
69B7F6062CF7702D00A48BCC /* UIImage+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Util.swift"; sourceTree = "<group>"; };
69BA38D62B888E8500AA69D6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
69ED1A5B2C7F15F300FE7A91 /* PostHogSessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogSessionManager.swift; sourceTree = "<group>"; };
69ED1A872C89B73100FE7A91 /* PostHogSwiftUIViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogSwiftUIViewModifiers.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -723,6 +725,7 @@
69EE82B82BA9C4DA00EB9542 /* Replay */ = {
isa = PBXGroup;
children = (
69B7F6062CF7702D00A48BCC /* UIImage+Util.swift */,
69EE82B92BA9C50400EB9542 /* PostHogReplayIntegration.swift */,
69EE82BB2BA9C53000EB9542 /* PostHogSessionReplayConfig.swift */,
69EE82BD2BA9C8AA00EB9542 /* ViewLayoutTracker.swift */,
Expand Down Expand Up @@ -1185,6 +1188,7 @@
69ED1A9F2C8F451B00FE7A91 /* PostHogPersonProfiles.swift in Sources */,
69EE82BA2BA9C50400EB9542 /* PostHogReplayIntegration.swift in Sources */,
3AE3FB472992AB0000AFFC18 /* Hedgelog.swift in Sources */,
69B7F60C2CF7703400A48BCC /* UIImage+Util.swift in Sources */,
69261D132AD5685B00232EC7 /* PostHogFeatureFlags.swift in Sources */,
699C5FE62C20178E007DB818 /* UUIDUtils.swift in Sources */,
690B2DF32C205B5600AE3B45 /* TimeBasedEpochGenerator.swift in Sources */,
Expand Down
15 changes: 6 additions & 9 deletions PostHog/PostHogSessionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,13 @@ import Foundation
timeNow - sessionLastTimestamp > sessionChangeThreshold
}

private func isiOSNativeSdk() -> Bool {
// postHogSdkName will be set to eg posthog-react-native if not
postHogSdkName == postHogiOSSdkName
private func isNotReactNative() -> Bool {
// for the RN SDK, the session is handled by the RN SDK itself
postHogSdkName != "posthog-react-native"
}

func resetSessionIfExpired(_ completion: () -> Void) {
// for hybrid SDKs, the session is handled by the hybrid SDK
guard isiOSNativeSdk() else {
guard isNotReactNative() else {
return
}

Expand Down Expand Up @@ -89,8 +88,7 @@ import Foundation
}

func rotateSessionIdIfRequired(_ completion: @escaping (() -> Void)) {
// for hybrid SDKs, the session is handled by the hybrid SDK
guard isiOSNativeSdk() else {
guard isNotReactNative() else {
return
}

Expand All @@ -109,8 +107,7 @@ import Foundation
}

func updateSessionLastTime() {
// for hybrid SDKs, the session is handled by the hybrid SDK
guard isiOSNativeSdk() else {
guard isNotReactNative() else {
return
}

Expand Down
4 changes: 4 additions & 0 deletions PostHog/Replay/Date+Util.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ extension Date {
Int64(timeIntervalSince1970 * 1000)
}
}

public func dateToMillis(_ date: Date) -> Int64 {
date.toMillis()
}
18 changes: 13 additions & 5 deletions PostHog/Replay/PostHogReplayIntegration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,22 @@
}
}

private func isNotFlutter() -> Bool {
postHogSdkName != "posthog-flutter"
}

func start() {
stopTimer()
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(withTimeInterval: self.config.sessionReplayConfig.debouncerDelay, repeats: true, block: { _ in
self.snapshot()
})

// flutter captures snapshots, so we don't need to capture them here
if isNotFlutter() {
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(withTimeInterval: self.config.sessionReplayConfig.debouncerDelay, repeats: true, block: { _ in
self.snapshot()
})
}
ViewLayoutTracker.swizzleLayoutSubviews()
}
ViewLayoutTracker.swizzleLayoutSubviews()

UIApplicationTracker.swizzleSendEvent()

Expand Down
15 changes: 2 additions & 13 deletions PostHog/Replay/RRWireframe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,6 @@ class RRWireframe {
var parentId: Int?

#if os(iOS)
private func imageToBase64(_ image: UIImage) -> String? {
let jpegData = image.jpegData(compressionQuality: 0.3)
let base64 = jpegData?.base64EncodedString()

if let base64 = base64 {
return "data:image/jpeg;base64,\(base64)"
}

return nil
}

private func maskImage() -> UIImage? {
if let image = image {
// the scale also affects the image size/resolution, from usually 100kb to 15kb each
Expand Down Expand Up @@ -106,9 +95,9 @@ class RRWireframe {
#if os(iOS)
if let image = image {
if let maskedImage = maskImage() {
base64 = imageToBase64(maskedImage)
base64 = maskedImage.toBase64()
} else {
base64 = imageToBase64(image)
base64 = image.toBase64()
}
}
#endif
Expand Down
28 changes: 28 additions & 0 deletions PostHog/Replay/UIImage+Util.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// UIImage+Util.swift
// PostHog
//
// Created by Manoel Aranda Neto on 27.11.24.
//

#if os(iOS)
import Foundation
import UIKit

extension UIImage {
func toBase64(_ compressionQuality: CGFloat = 0.3) -> String? {
let jpegData = jpegData(compressionQuality: compressionQuality)
let base64 = jpegData?.base64EncodedString()

if let base64 = base64 {
return "data:image/jpeg;base64,\(base64)"
}

return nil
}
}

public func imageToBase64(_ image: UIImage, _ compressionQuality: CGFloat = 0.3) -> String? {
image.toBase64(compressionQuality)
}
#endif
2 changes: 1 addition & 1 deletion PostHog/Utils/Data+Gzip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private extension GzipError.Kind {
}
}

public extension Data {
extension Data {
/// Whether the receiver is compressed in gzip format.
var isGzipped: Bool {
starts(with: [0x1F, 0x8B]) // check magic number
Expand Down
4 changes: 2 additions & 2 deletions PostHog/Utils/Reachability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import Foundation
@available(*, unavailable, renamed: "Notification.Name.reachabilityChanged")
public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification")

public extension Notification.Name {
extension Notification.Name {
static let reachabilityChanged = Notification.Name("reachabilityChanged")
}

Expand Down Expand Up @@ -162,7 +162,7 @@ import Foundation
}
}

public extension Reachability {
extension Reachability {
// MARK: - *** Notifier methods ***

func startNotifier() throws {
Expand Down
2 changes: 1 addition & 1 deletion PostHog/Utils/UUIDUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import Foundation

public extension UUID {
extension UUID {
static func v7() -> Self {
TimeBasedEpochGenerator.shared.v7()
}
Expand Down

0 comments on commit ff05a7a

Please sign in to comment.