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

feat: add support for uitextview autocapture #195

Merged
merged 24 commits into from
Jul 16, 2024
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1ee721a
Fix indentation issue
PouriaAmini Jul 2, 2024
c41a29b
feat: add user interactions capture
PouriaAmini Jul 5, 2024
0172e00
Merge branch 'autocapture' into feature-autocapture
PouriaAmini Jul 5, 2024
e2bad27
Merge pull request #1 from amplitude/feature-autocapture
PouriaAmini Jul 5, 2024
a374e75
fix: fix typo
PouriaAmini Jul 5, 2024
48c4383
fix: remove support for UITextField action message capture
PouriaAmini Jul 6, 2024
6466cac
refactor: add dispatch once for method swizzling
PouriaAmini Jul 6, 2024
88930ae
fix: remove support for UISlider to reduce noise
PouriaAmini Jul 8, 2024
162d79e
feat: add support for UITextField and UISlider event capture
PouriaAmini Jul 8, 2024
74ba02b
style: remove return keyword for one line functions
PouriaAmini Jul 8, 2024
6d2610f
fix: fix typo
PouriaAmini Jul 11, 2024
f5efd78
feat: add support for text field gained/lost focus
PouriaAmini Jul 11, 2024
6b57830
fix: fix lint
PouriaAmini Jul 11, 2024
ff80f77
fix: remove tag as textfield title
PouriaAmini Jul 11, 2024
8a5e074
refactor: refactor title and shouldTrack
PouriaAmini Jul 12, 2024
055e39f
refactor: add a protocol to track control elements
PouriaAmini Jul 12, 2024
d9f2f1c
refactor: guard on action name
PouriaAmini Jul 13, 2024
8e907af
Merge branch 'amplitude:main' into autocapture
PouriaAmini Jul 13, 2024
b340284
Merge remote-tracking branch 'refs/remotes/origin/autocapture'
PouriaAmini Jul 13, 2024
29e8149
feat: add support for uitextview capture
PouriaAmini Jul 13, 2024
3636504
Merge remote-tracking branch 'remote/feature-autocapture' into autoca…
PouriaAmini Jul 15, 2024
74fe70d
fix: disable action method tracking support for UITextView
PouriaAmini Jul 15, 2024
45aa46e
fix: fix lint issue
PouriaAmini Jul 15, 2024
d02c6af
style: remove amp_ prefix from objc methods
PouriaAmini Jul 15, 2024
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
56 changes: 30 additions & 26 deletions Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,14 @@ class UIKitUserInteractions {

private static let lock = NSLock()

private static let initializeSwizzle: () = {
swizzleSendAction()
private static let addNotificationObservers: () = {
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didBeginEditing), name: UITextField.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEndEditing), name: UITextField.textDidEndEditingNotification, object: nil)
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didBeginEditing), name: UITextView.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEndEditing), name: UITextView.textDidEndEditingNotification, object: nil)
}()

private static let initializeNotificationListeners: () = {
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(UIKitUserInteractions.amp_textFieldDidBeginEditing), name: UITextField.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(UIKitUserInteractions.amp_textFieldDidEndEditing), name: UITextField.textDidEndEditingNotification, object: nil)
}()

static func register(_ amplitude: Amplitude) {
lock.withLock {
amplitudeInstances.add(amplitude)
}
initializeSwizzle
initializeNotificationListeners
}

private static func swizzleSendAction() {
private static let swizzleSendAction: () = {
let applicationClass = UIApplication.self

let originalSelector = #selector(UIApplication.sendAction)
Expand All @@ -45,19 +35,27 @@ class UIKitUserInteractions {
originalSelector,
swizzledImp,
method_getTypeEncoding(swizzledMethod))
}()

static func register(_ amplitude: Amplitude) {
lock.withLock {
amplitudeInstances.add(amplitude)
}
swizzleSendAction
addNotificationObservers
}

@objc static func amp_textFieldDidBeginEditing(_ notification: NSNotification) {
guard let textField = notification.object as? UITextField else { return }
let userInteractionEvent = textField.eventFromData(with: "didBeginEditing")
@objc static func didBeginEditing(_ notification: NSNotification) {
guard let view = notification.object as? UIView else { return }
let userInteractionEvent = view.eventFromData(with: "didBeginEditing")
amplitudeInstances.allObjects.forEach {
$0.track(event: userInteractionEvent)
}
}

@objc static func amp_textFieldDidEndEditing(_ notification: NSNotification) {
guard let textField = notification.object as? UITextField else { return }
let userInteractionEvent = textField.eventFromData(with: "didEndEditing")
@objc static func didEndEditing(_ notification: NSNotification) {
guard let view = notification.object as? UIView else { return }
let userInteractionEvent = view.eventFromData(with: "didEndEditing")
amplitudeInstances.allObjects.forEach {
$0.track(event: userInteractionEvent)
}
Expand All @@ -68,13 +66,15 @@ extension UIApplication {
@objc func amp_sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool {
let sendActionResult = amp_sendAction(action, to: target, from: sender, for: event)

guard
sendActionResult,
guard sendActionResult,
let view = sender as? UIView,
view.amp_shouldTrack(action, for: event)
view.amp_shouldTrack(action, for: event),
let actionName = NSStringFromSelector(action)
.components(separatedBy: ":")
.first
PouriaAmini marked this conversation as resolved.
Show resolved Hide resolved
else { return sendActionResult }

let userInteractionEvent = view.eventFromData(with: NSStringFromSelector(action).components(separatedBy: ":").first ?? "")
let userInteractionEvent = view.eventFromData(with: actionName)

UIKitUserInteractions.amplitudeInstances.allObjects.forEach {
$0.track(event: userInteractionEvent)
Expand Down Expand Up @@ -156,6 +156,10 @@ extension UITextField {
override func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool { false }
}

extension UITextView {
override func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool { false }
}

#if !os(tvOS)
extension UISlider {
override func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool {
Expand Down
Loading