Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: flutter session replay #266

Merged
merged 4 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
ioannisj marked this conversation as resolved.
Show resolved Hide resolved

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 {
marandaneto marked this conversation as resolved.
Show resolved Hide resolved
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
Loading