Skip to content

Commit

Permalink
add captureScreenViews
Browse files Browse the repository at this point in the history
  • Loading branch information
marandaneto committed Oct 23, 2023
1 parent 711ce92 commit 1233cf3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
4 changes: 4 additions & 0 deletions PostHog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
69261D232AD9784200232EC7 /* PostHogVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69261D222AD9784200232EC7 /* PostHogVersion.swift */; };
69261D252AD9787A00232EC7 /* PostHogExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69261D242AD9787A00232EC7 /* PostHogExtensions.swift */; };
6926DA8E2ADD2876005760D2 /* PostHogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6926DA8D2ADD2876005760D2 /* PostHogContext.swift */; };
69779BEC2AE68E6900D7A48E /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69779BEB2AE68E6900D7A48E /* UIViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -144,6 +145,7 @@
69261D222AD9784200232EC7 /* PostHogVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogVersion.swift; sourceTree = "<group>"; };
69261D242AD9787A00232EC7 /* PostHogExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogExtensions.swift; sourceTree = "<group>"; };
6926DA8D2ADD2876005760D2 /* PostHogContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogContext.swift; sourceTree = "<group>"; };
69779BEB2AE68E6900D7A48E /* UIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -278,6 +280,7 @@
69261D222AD9784200232EC7 /* PostHogVersion.swift */,
69261D242AD9787A00232EC7 /* PostHogExtensions.swift */,
6926DA8D2ADD2876005760D2 /* PostHogContext.swift */,
69779BEB2AE68E6900D7A48E /* UIViewController.swift */,
);
path = PostHog;
sourceTree = "<group>";
Expand Down Expand Up @@ -481,6 +484,7 @@
3AE3FB4E2993D1D600AFFC18 /* PostHogSessionManager.swift in Sources */,
3AE3FB49299391DF00AFFC18 /* PostHogStorage.swift in Sources */,
69261D232AD9784200232EC7 /* PostHogVersion.swift in Sources */,
69779BEC2AE68E6900D7A48E /* UIViewController.swift in Sources */,
3A0F108929C9BD76002C0084 /* Errors.swift in Sources */,
3AE3FB37299162EA00AFFC18 /* PostHogApi.swift in Sources */,
6926DA8E2ADD2876005760D2 /* PostHogContext.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion PostHog/PostHogSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ let maxRetryDelay = 30.0
queue?.start()

registerNotifications()
captureScreenViews()

DispatchQueue.main.async {
NotificationCenter.default.post(name: PostHogSDK.didStartNotification, object: nil)
Expand Down Expand Up @@ -562,7 +563,7 @@ let maxRetryDelay = 30.0

private func captureScreenViews() {
if config.captureScreenViews {
// swizzle(selector: #selector(), with: <#T##Selector#>, inClass: <#T##AnyClass#>, usingClass: <#T##AnyClass#>)
UIViewController.swizzleScreenView()
}
}

Expand Down
86 changes: 86 additions & 0 deletions PostHog/UIViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// UIViewController.swift
// PostHog
//
// Inspired by
// https://raw.githubusercontent.com/segmentio/analytics-swift/e613e09aa1b97144126a923ec408374f914a6f2e/Examples/other_plugins/UIKitScreenTracking.swift
//
// Created by Manoel Aranda Neto on 23.10.23.
//

import Foundation
import UIKit

extension UIViewController {
static func swizzle(forClass: AnyClass, original: Selector, new: Selector) {
guard let originalMethod = class_getInstanceMethod(forClass, original) else { return }
guard let swizzledMethod = class_getInstanceMethod(forClass, new) else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}

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

private func activeController() -> UIViewController? {
// if a view is being dismissed, this will return nil
if let root = viewIfLoaded?.window?.rootViewController {
return root
} else if #available(iOS 13.0, *) {
// preferred way to get active controller in ios 13+
for scene in UIApplication.shared.connectedScenes where scene.activationState == .foregroundActive {
let windowScene = scene as? UIWindowScene
let sceneDelegate = windowScene?.delegate as? UIWindowSceneDelegate
if let target = sceneDelegate, let window = target.window {
return window?.rootViewController
}
}
} else {
// this was deprecated in ios 13.0
return UIApplication.shared.keyWindow?.rootViewController
}
return nil
}

private func captureScreenView() {
var rootController = viewIfLoaded?.window?.rootViewController
if rootController == nil {
rootController = activeController()
}
guard let top = findVisibleViewController(activeController()) else { return }

var name = String(describing: top.classForCoder).replacingOccurrences(of: "ViewController", with: "")

if name.count == 0 {
name = top.title ?? "Unknown"
}

if name != "Unknown" {
PostHogSDK.shared.capture(name)
}
}

@objc func viewDidApperOverride(animated: Bool) {
captureScreenView()
// 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)
}

private func findVisibleViewController(_ controller: UIViewController?) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return findVisibleViewController(navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return findVisibleViewController(selected)
}
}
if let presented = controller?.presentedViewController {
return findVisibleViewController(presented)
}
return controller
}
}

0 comments on commit 1233cf3

Please sign in to comment.