Skip to content

Commit

Permalink
fix: screen events and autocapture should ignore keyboard window (#269)
Browse files Browse the repository at this point in the history
* fix: screen events and autocapture should ignore keyboard window

* chore: update CHANGELOG

* fix: remove development team

* fix: format

* fix: address feedback
  • Loading branch information
ioannisj authored Dec 5, 2024
1 parent 5dceb9b commit be00f15
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next

- fix: ignore autocapture events from keyboard window ([#269](https://github.com/PostHog/posthog-ios/pull/269))

## 3.16.1 - 2024-12-04

- fix: screen flicker when capturing a screenshot when a sensitive text field is on screen ([#270](https://github.com/PostHog/posthog-ios/pull/270))
Expand Down
4 changes: 4 additions & 0 deletions PostHog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
69F5181A2BAC81FC00F52C14 /* UITextInputTraits+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F518192BAC81FC00F52C14 /* UITextInputTraits+Util.swift */; };
69F518382BB2BA0100F52C14 /* PostHogSwizzler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F518372BB2BA0100F52C14 /* PostHogSwizzler.swift */; };
69F5183A2BB2BA8300F52C14 /* UIApplicationTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F518392BB2BA8300F52C14 /* UIApplicationTracker.swift */; };
DA0CA6F12CFF6B6300AF9500 /* UIWindow+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0CA6F02CFF6B6300AF9500 /* UIWindow+.swift */; };
DA26419C2CC0499300CB427B /* PostHogAutocaptureEventTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA26419A2CC0499300CB427B /* PostHogAutocaptureEventTracker.swift */; };
DA5AA7192CE245D2004EFB99 /* UIApplication+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5AA7132CE245CD004EFB99 /* UIApplication+.swift */; };
DA5B85882CD21CBB00686389 /* AutocaptureEventProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5B85872CD21CBB00686389 /* AutocaptureEventProcessing.swift */; };
Expand Down Expand Up @@ -392,6 +393,7 @@
69F518192BAC81FC00F52C14 /* UITextInputTraits+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextInputTraits+Util.swift"; sourceTree = "<group>"; };
69F518372BB2BA0100F52C14 /* PostHogSwizzler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogSwizzler.swift; sourceTree = "<group>"; };
69F518392BB2BA8300F52C14 /* UIApplicationTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationTracker.swift; sourceTree = "<group>"; };
DA0CA6F02CFF6B6300AF9500 /* UIWindow+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+.swift"; sourceTree = "<group>"; };
DA26419A2CC0499300CB427B /* PostHogAutocaptureEventTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAutocaptureEventTracker.swift; sourceTree = "<group>"; };
DA5AA7132CE245CD004EFB99 /* UIApplication+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+.swift"; sourceTree = "<group>"; };
DA5B85872CD21CBB00686389 /* AutocaptureEventProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocaptureEventProcessing.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -510,6 +512,7 @@
3AA4C09B2988315D006C4731 /* Utils */ = {
isa = PBXGroup;
children = (
DA0CA6F02CFF6B6300AF9500 /* UIWindow+.swift */,
DA5AA7132CE245CD004EFB99 /* UIApplication+.swift */,
3AE3FB422992985A00AFFC18 /* Reachability.swift */,
3AE3FB462992AB0000AFFC18 /* Hedgelog.swift */,
Expand Down Expand Up @@ -1143,6 +1146,7 @@
69261D1F2AD9681300232EC7 /* PostHogConsumerPayload.swift in Sources */,
6955CB732C517651008EFD8D /* CGSize+Util.swift in Sources */,
69F517EA2BAC684F00F52C14 /* RRStyle.swift in Sources */,
DA0CA6F12CFF6B6300AF9500 /* UIWindow+.swift in Sources */,
69F23A782BB30991001194F6 /* NetworkSample.swift in Sources */,
69F23A762BB308AE001194F6 /* URLSessionInterceptor.swift in Sources */,
690FF0BF2AEFA97F00A0B06B /* FileUtils.swift in Sources */,
Expand Down
19 changes: 17 additions & 2 deletions PostHog/Autocapture/PostHogAutocaptureEventTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,23 @@
}

extension UIScrollView {
@objc func ph_swizzled_setContentOffset_Setter(_ contentOffset: CGPoint) {
@objc func ph_swizzled_setContentOffset_Setter(_ newContentOffset: CGPoint) {
// first, call original method
ph_swizzled_setContentOffset_Setter(contentOffset)
ph_swizzled_setContentOffset_Setter(newContentOffset)

guard shouldTrack(self) else {
return
}

// ignore all keyboard events
if let window, window.isKeyboardWindow {
return
}

// scrollview did not scroll (contentOffset didn't change)
guard contentOffset != newContentOffset else {
return
}

// block scrolls on UIPickerTableView. (captured via a forwarding delegate implementation)
if String(describing: type(of: self)) == "UIPickerTableView" {
Expand Down Expand Up @@ -476,6 +490,7 @@
if view.isHidden { return false }
if !view.isUserInteractionEnabled { return false }
if view.isNoCapture() { return false }
if view.window?.isKeyboardWindow == true { return false }

if let textField = view as? UITextField, textField.isSensitiveText() {
return false
Expand Down
15 changes: 10 additions & 5 deletions PostHog/UIViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
static func swizzleScreenView() {
swizzle(forClass: UIViewController.self,
original: #selector(UIViewController.viewDidAppear(_:)),
new: #selector(UIViewController.viewDidApperOverride))
new: #selector(UIViewController.viewDidAppearOverride))
}

static func unswizzleScreenView() {
swizzle(forClass: UIViewController.self,
original: #selector(UIViewController.viewDidApperOverride),
original: #selector(UIViewController.viewDidAppearOverride),
new: #selector(UIViewController.viewDidAppear(_:)))
}

Expand Down Expand Up @@ -58,11 +58,16 @@
}
}

@objc func viewDidApperOverride(animated: Bool) {
captureScreenView(viewIfLoaded?.window)
@objc func viewDidAppearOverride(animated: Bool) {
// ignore views from keyboard window
// these may include: UIInputWindowController, _UICursorAccessoryViewController, UICompatibilityInputViewController,UIKeyboardHiddenViewController_Autofill and others
if let window = viewIfLoaded?.window, !window.isKeyboardWindow {
captureScreenView(window)
}

// it looks like we're calling ourselves, but we're actually
// calling the original implementation of viewDidAppear since it's been swizzled.
viewDidApperOverride(animated: animated)
viewDidAppearOverride(animated: animated)
}

private func findVisibleViewController(_ controller: UIViewController?) -> UIViewController? {
Expand Down
17 changes: 17 additions & 0 deletions PostHog/Utils/UIWindow+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UIWindow+.swift
// PostHog
//
// Created by Yiannis Josephides on 03/12/2024.
//

#if os(iOS) || os(tvOS)
import Foundation
import UIKit

extension UIWindow {
var isKeyboardWindow: Bool {
String(describing: type(of: window)) == "UIRemoteKeyboardWindow"
}
}
#endif

0 comments on commit be00f15

Please sign in to comment.