From c29eb55799cfd414c4393ee2ef1a15411f0b8f41 Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Wed, 24 Jul 2024 09:02:55 -0700 Subject: [PATCH 1/6] fix: just track touchupinside and valuechanged for some elements --- .../Plugins/iOS/UIKitUserInteractions.swift | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index b767386..73eac3e 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -68,7 +68,7 @@ extension UIApplication { guard sendActionResult, let view = sender as? UIView, - view.amp_shouldTrack(action, for: event), + view.amp_shouldTrack(action, for: target), let actionName = NSStringFromSelector(action) .components(separatedBy: ":") .first @@ -178,41 +178,44 @@ extension NSObject { protocol ActionTrackable { var amp_title: String? { get } - func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool + func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool } extension UIView: ActionTrackable { @objc var amp_title: String? { nil } - @objc func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool { true } + @objc func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { false } } extension UIButton { override var amp_title: String? { currentTitle } + override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { + actions(forTarget: target, forControlEvent: .touchUpInside)?.contains(action.description) ?? false + } } extension UISegmentedControl { override var amp_title: String? { titleForSegment(at: selectedSegmentIndex) } + override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { + actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false + } } -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 } +extension UIDatePicker { + override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { + actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false + } } -#if !os(tvOS) -extension UISlider { - override func amp_shouldTrack(_ action: Selector, for event: UIEvent?) -> Bool { - event?.allTouches?.contains { $0.phase == .ended && $0.view === self } ?? false +extension UIPageControl { + override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { + actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false } } -@available(iOS 14.0, *) -extension UIColorWell { - override var amp_title: String? { title } +extension UISwitch { + override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { + actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false + } } -#endif #endif From 044f4fa7d98cc50eac7025ae976908fb56ae6ce3 Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Wed, 24 Jul 2024 09:14:12 -0700 Subject: [PATCH 2/6] fix: fix tvos issue --- Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index 73eac3e..4011e2e 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -200,13 +200,14 @@ extension UISegmentedControl { } } -extension UIDatePicker { +extension UIPageControl { override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false } } -extension UIPageControl { +#if !os(tvOS) +extension UIDatePicker { override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false } @@ -217,5 +218,6 @@ extension UISwitch { actions(forTarget: target, forControlEvent: .valueChanged)?.contains(action.description) ?? false } } +#endif #endif From 9b912c20134bbe53adaca6b69b8508d4a9a27bbc Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Thu, 25 Jul 2024 15:56:49 -0700 Subject: [PATCH 3/6] feat: capture control events --- Sources/Amplitude/Constants.swift | 5 +- .../Events/UserInteractionEvent.swift | 6 +- .../Plugins/iOS/UIKitUserInteractions.swift | 150 +++++++++++------- .../UIKitUserInteractionPluginTest.swift | 13 +- 4 files changed, 107 insertions(+), 67 deletions(-) diff --git a/Sources/Amplitude/Constants.swift b/Sources/Amplitude/Constants.swift index e8d9ca4..6d5b1e3 100644 --- a/Sources/Amplitude/Constants.swift +++ b/Sources/Amplitude/Constants.swift @@ -83,7 +83,8 @@ public struct Constants { static let AMP_APPLICATION_BACKGROUNDED_EVENT = "\(AMP_AMPLITUDE_PREFIX)Application Backgrounded" static let AMP_DEEP_LINK_OPENED_EVENT = "\(AMP_AMPLITUDE_PREFIX)Deep Link Opened" static let AMP_SCREEN_VIEWED_EVENT = "\(AMP_AMPLITUDE_PREFIX)Screen Viewed" - static let AMP_USER_INTERACTION_EVENT = "\(AMP_AMPLITUDE_PREFIX)User Interaction" + static let AMP_ELEMENT_INTERACTED_EVENT = "\(AMP_AMPLITUDE_PREFIX)Element Interacted" + static let AMP_REVENUE_EVENT = "revenue_amount" static let AMP_APP_VERSION_PROPERTY = "\(AMP_AMPLITUDE_PREFIX)Version" @@ -97,10 +98,12 @@ public struct Constants { static let AMP_APP_VIEW_CONTROLLER = "\(AMP_AMPLITUDE_PREFIX)View Controller" static let AMP_APP_TITLE = "\(AMP_AMPLITUDE_PREFIX)Title" static let AMP_APP_TARGET_ACCESSIBILITY_LABEL = "\(AMP_AMPLITUDE_PREFIX)Target Accessibility Label" + static let AMP_APP_TARGET_ACCESSIBILITY_IDENTIFIER = "\(AMP_AMPLITUDE_PREFIX)Target Accessibility Identifier" static let AMP_APP_ACTION = "\(AMP_AMPLITUDE_PREFIX)Action" static let AMP_APP_TARGET_VIEW_CLASS = "\(AMP_AMPLITUDE_PREFIX)Target View Class" static let AMP_APP_TARGET_TEXT = "\(AMP_AMPLITUDE_PREFIX)Target Text" static let AMP_APP_HIERARCHY = "\(AMP_AMPLITUDE_PREFIX)Hierarchy" + static let AMP_APP_ACTION_METHOD = "\(AMP_AMPLITUDE_PREFIX)Action Method" static let AMP_APP_GESTURE_RECOGNIZER = "\(AMP_AMPLITUDE_PREFIX)Gesture Recognizer" public struct Configuration { diff --git a/Sources/Amplitude/Events/UserInteractionEvent.swift b/Sources/Amplitude/Events/UserInteractionEvent.swift index b3579d3..f144630 100644 --- a/Sources/Amplitude/Events/UserInteractionEvent.swift +++ b/Sources/Amplitude/Events/UserInteractionEvent.swift @@ -5,20 +5,24 @@ public class UserInteractionEvent: BaseEvent { viewController: String? = nil, title: String? = nil, accessibilityLabel: String? = nil, + accessibilityIdentifier: String? = nil, action: String, targetViewClass: String, targetText: String? = nil, hierarchy: String, + actionMethod: String? = nil, gestureRecognizer: String? = nil ) { - self.init(eventType: Constants.AMP_USER_INTERACTION_EVENT, eventProperties: [ + self.init(eventType: Constants.AMP_ELEMENT_INTERACTED_EVENT, eventProperties: [ Constants.AMP_APP_VIEW_CONTROLLER: viewController, Constants.AMP_APP_TITLE: title, Constants.AMP_APP_TARGET_ACCESSIBILITY_LABEL: accessibilityLabel, + Constants.AMP_APP_TARGET_ACCESSIBILITY_IDENTIFIER: accessibilityIdentifier, Constants.AMP_APP_ACTION: action, Constants.AMP_APP_TARGET_VIEW_CLASS: targetViewClass, Constants.AMP_APP_TARGET_TEXT: targetText, Constants.AMP_APP_HIERARCHY: hierarchy, + Constants.AMP_APP_ACTION_METHOD: actionMethod, Constants.AMP_APP_GESTURE_RECOGNIZER: gestureRecognizer ]) } diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index 4011e2e..1813ce1 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -2,15 +2,51 @@ import UIKit class UIKitUserInteractions { + struct EventData { + enum Source { + case actionMethod + + case gestureRecognizer + } + + let viewController: String? + + let title: String? + + let accessibilityLabel: String? + + let accessibilityIdentifier: String? + + let targetViewClass: String + + let targetText: String? + + let hierarchy: String + + fileprivate func userInteractionEvent(for action: String, from source: Source? = nil, withName sourceName: String? = nil) -> UserInteractionEvent { + return UserInteractionEvent( + viewController: viewController, + title: title, + accessibilityLabel: accessibilityLabel, + accessibilityIdentifier: accessibilityIdentifier, + action: action, + targetViewClass: targetViewClass, + targetText: targetText, + hierarchy: hierarchy, + actionMethod: source == .actionMethod ? sourceName : nil, + gestureRecognizer: source == .gestureRecognizer ? sourceName : nil + ) + } + } + fileprivate static let amplitudeInstances = NSHashTable.weakObjects() private static let lock = NSLock() private static let addNotificationObservers: Void = { - 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) + NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEdit), name: UITextField.textDidEndEditingNotification, object: nil) + NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEdit), name: UITextView.textDidEndEditingNotification, object: nil) + NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didTouch), name: UITableView.selectionDidChangeNotification, object: nil) }() private static let setupMethodSwizzling: Void = { @@ -26,17 +62,17 @@ class UIKitUserInteractions { addNotificationObservers } - @objc static func didBeginEditing(_ notification: NSNotification) { + @objc static func didEdit(_ notification: NSNotification) { guard let view = notification.object as? UIView else { return } - let userInteractionEvent = view.eventFromData(with: "didBeginEditing") + let userInteractionEvent = view.eventData.userInteractionEvent(for: "Edit") amplitudeInstances.allObjects.forEach { $0.track(event: userInteractionEvent) } } - @objc static func didEndEditing(_ notification: NSNotification) { + @objc static func didTouch(_ notification: NSNotification) { guard let view = notification.object as? UIView else { return } - let userInteractionEvent = view.eventFromData(with: "didEndEditing") + let userInteractionEvent = view.eventData.userInteractionEvent(for: "Touch") amplitudeInstances.allObjects.forEach { $0.track(event: userInteractionEvent) } @@ -67,14 +103,12 @@ extension UIApplication { let sendActionResult = amp_sendAction(action, to: target, from: sender, for: event) guard sendActionResult, - let view = sender as? UIView, - view.amp_shouldTrack(action, for: target), - let actionName = NSStringFromSelector(action) - .components(separatedBy: ":") - .first + let control = sender as? UIControl, + control.amp_shouldTrack(action, for: target), + let actionEvent = control.event(for: action, to: target)?.description else { return sendActionResult } - let userInteractionEvent = view.eventFromData(with: actionName) + let userInteractionEvent = control.eventData.userInteractionEvent(for: actionEvent, from: .actionMethod, withName: NSStringFromSelector(action)) UIKitUserInteractions.amplitudeInstances.allObjects.forEach { $0.track(event: userInteractionEvent) @@ -90,7 +124,7 @@ extension UIGestureRecognizer { guard state == .ended, let view else { return } - let gestureType = switch self { + let gestureAction: String? = switch self { case is UITapGestureRecognizer: "Tap" case is UISwipeGestureRecognizer: "Swipe" case is UIPanGestureRecognizer: "Pan" @@ -100,62 +134,29 @@ extension UIGestureRecognizer { case is UIRotationGestureRecognizer: "Rotation" case is UIScreenEdgePanGestureRecognizer: "Screen Edge Pan" #endif - default: "Custom Gesture" + default: nil } - let userInteractionEvent = eventFromData(with: gestureType, from: view) + guard let gestureAction else { return } + + let userInteractionEvent = view.eventData.userInteractionEvent(for: gestureAction, from: .gestureRecognizer, withName: descriptiveTypeName) UIKitUserInteractions.amplitudeInstances.allObjects.forEach { $0.track(event: userInteractionEvent) } } - - func eventFromData(with action: String, from view: UIView) -> UserInteractionEvent { - let viewData = view.extractData(with: action) - return UserInteractionEvent( - viewController: viewData.viewController, - title: viewData.title, - accessibilityLabel: viewData.accessibilityLabel, - action: viewData.action, - targetViewClass: viewData.targetViewClass, - targetText: viewData.targetText, - hierarchy: viewData.hierarchy, - gestureRecognizer: descriptiveTypeName) - } } extension UIView { - private static let viewHierarchyDelimiter = " -> " - - struct ViewData { - let viewController: String? - let title: String? - let accessibilityLabel: String? - let action: String - let targetViewClass: String - let targetText: String? - let hierarchy: String - } - - func eventFromData(with action: String) -> UserInteractionEvent { - let viewData = extractData(with: action) - return UserInteractionEvent( - viewController: viewData.viewController, - title: viewData.title, - accessibilityLabel: viewData.accessibilityLabel, - action: viewData.action, - targetViewClass: viewData.targetViewClass, - targetText: viewData.targetText, - hierarchy: viewData.hierarchy) - } + private static let viewHierarchyDelimiter = " → " - func extractData(with action: String) -> ViewData { + var eventData: UIKitUserInteractions.EventData { let viewController = owningViewController - return ViewData( + return UIKitUserInteractions.EventData( viewController: viewController?.descriptiveTypeName, title: viewController?.title, accessibilityLabel: accessibilityLabel, - action: action, + accessibilityIdentifier: accessibilityIdentifier, targetViewClass: descriptiveTypeName, targetText: amp_title, hierarchy: sequence(first: self, next: \.superview) @@ -164,9 +165,44 @@ extension UIView { } } +extension UIControl { + func event(for action: Selector, to target: Any?) -> UIControl.Event? { + var events: [UIControl.Event] = [ + .touchDown, .touchDownRepeat, .touchDragInside, .touchDragOutside, + .touchDragEnter, .touchDragExit, .touchUpInside, .touchUpOutside, + .touchCancel, .valueChanged, .editingDidBegin, .editingChanged, + .editingDidEnd, .editingDidEndOnExit, .primaryActionTriggered + ] + if #available(iOS 14.0, tvOS 14.0, macCatalyst 14.0, *) { + events.append(.menuActionTriggered) + } + + return events.first { event in + self.actions(forTarget: target, forControlEvent: event)?.contains(action.description) ?? false + } + } +} + +extension UIControl.Event { + var description: String? { + if UIControl.Event.allTouchEvents.contains(self) { + return "Touch" + } else if UIControl.Event.allEditingEvents.contains(self) { + return "Edit" + } else if self == .valueChanged { + return "Value Change" + } else if self == .primaryActionTriggered { + return "Primary Action" + } else if #available(iOS 14.0, tvOS 14.0, macCatalyst 14.0, *), self == .menuActionTriggered { + return "Menu Action" + } + return nil + } +} + extension UIResponder { var owningViewController: UIViewController? { - return self as? UIViewController ?? next?.owningViewController + self as? UIViewController ?? next?.owningViewController } } diff --git a/Tests/AmplitudeTests/Plugins/UIKitUserInteractionPluginTest.swift b/Tests/AmplitudeTests/Plugins/UIKitUserInteractionPluginTest.swift index 4ad381d..4e67beb 100644 --- a/Tests/AmplitudeTests/Plugins/UIKitUserInteractionPluginTest.swift +++ b/Tests/AmplitudeTests/Plugins/UIKitUserInteractionPluginTest.swift @@ -14,15 +14,14 @@ class UIKitUserInteractionsTests: XCTestCase { button.accessibilityLabel = "Accessibility Button" mockVC.view.addSubview(button) - let buttonData = button.extractData(with: "action") + let buttonData = button.eventData XCTAssertEqual(buttonData.viewController, "UIViewController") XCTAssertEqual(buttonData.title, "Mock VC Title") XCTAssertEqual(buttonData.accessibilityLabel, "Accessibility Button") - XCTAssertEqual(buttonData.action, "action") XCTAssertEqual(buttonData.targetViewClass, "UIButton") XCTAssertEqual(buttonData.targetText, "Test Button") - XCTAssertTrue(buttonData.hierarchy.hasSuffix("UIButton -> UIView")) + XCTAssertTrue(buttonData.hierarchy.hasSuffix("UIButton → UIView")) } func testExtractDataForCustomView() { @@ -33,24 +32,22 @@ class UIKitUserInteractionsTests: XCTestCase { let customView = CustomView() mockVC.view.addSubview(customView) - let customViewData = customView.extractData(with: "action") + let customViewData = customView.eventData XCTAssertEqual(customViewData.viewController, "UIViewController") XCTAssertEqual(customViewData.title, "Mock VC Title") XCTAssertNil(customViewData.accessibilityLabel) - XCTAssertEqual(customViewData.action, "action") XCTAssertEqual(customViewData.targetViewClass, "CustomView") - XCTAssertTrue(customViewData.hierarchy.hasSuffix("CustomView -> UIView")) + XCTAssertTrue(customViewData.hierarchy.hasSuffix("CustomView → UIView")) } func testExtractDataForOrphanView() { let orphanView = UIView() - let orphanData = orphanView.extractData(with: "action") + let orphanData = orphanView.eventData XCTAssertNil(orphanData.viewController) XCTAssertNil(orphanData.title) XCTAssertNil(orphanData.accessibilityLabel) - XCTAssertEqual(orphanData.action, "action") XCTAssertEqual(orphanData.targetViewClass, "UIView") XCTAssertNil(orphanData.targetText) XCTAssertEqual(orphanData.hierarchy, "UIView") From c229eea03d0da6dd042fbe2e42d77c4f3897bc4e Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Fri, 26 Jul 2024 12:55:23 -0700 Subject: [PATCH 4/6] fix: remove row selected event --- .../Plugins/iOS/UIKitUserInteractions.swift | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index 1813ce1..99d0177 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -44,9 +44,8 @@ class UIKitUserInteractions { private static let lock = NSLock() private static let addNotificationObservers: Void = { - NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEdit), name: UITextField.textDidEndEditingNotification, object: nil) - NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEdit), name: UITextView.textDidEndEditingNotification, object: nil) - NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didTouch), name: UITableView.selectionDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEndEditing), name: UITextField.textDidEndEditingNotification, object: nil) + NotificationCenter.default.addObserver(UIKitUserInteractions.self, selector: #selector(didEndEditing), name: UITextView.textDidEndEditingNotification, object: nil) }() private static let setupMethodSwizzling: Void = { @@ -62,17 +61,9 @@ class UIKitUserInteractions { addNotificationObservers } - @objc static func didEdit(_ notification: NSNotification) { + @objc static func didEndEditing(_ notification: NSNotification) { guard let view = notification.object as? UIView else { return } - let userInteractionEvent = view.eventData.userInteractionEvent(for: "Edit") - amplitudeInstances.allObjects.forEach { - $0.track(event: userInteractionEvent) - } - } - - @objc static func didTouch(_ notification: NSNotification) { - guard let view = notification.object as? UIView else { return } - let userInteractionEvent = view.eventData.userInteractionEvent(for: "Touch") + let userInteractionEvent = view.eventData.userInteractionEvent(for: "didEndEditing") amplitudeInstances.allObjects.forEach { $0.track(event: userInteractionEvent) } From 0eb40538fb5779a82321d6cbe1afe5142ccd0912 Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Fri, 26 Jul 2024 13:51:58 -0700 Subject: [PATCH 5/6] fix: track any touchUpInside --- Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index 99d0177..ecf40eb 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -213,13 +213,16 @@ extension UIView: ActionTrackable { @objc func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { false } } -extension UIButton { - override var amp_title: String? { currentTitle } +extension UIControl { override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { actions(forTarget: target, forControlEvent: .touchUpInside)?.contains(action.description) ?? false } } +extension UIButton { + override var amp_title: String? { currentTitle } +} + extension UISegmentedControl { override var amp_title: String? { titleForSegment(at: selectedSegmentIndex) } override func amp_shouldTrack(_ action: Selector, for target: Any?) -> Bool { From 5ac7162e2c4505bc90521c2347cd575fd3bc4f23 Mon Sep 17 00:00:00 2001 From: "pouria.amini" Date: Fri, 26 Jul 2024 15:23:37 -0700 Subject: [PATCH 6/6] fix: capture image name as a fallback for buttons title --- Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift index ecf40eb..6e50e0c 100644 --- a/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift +++ b/Sources/Amplitude/Plugins/iOS/UIKitUserInteractions.swift @@ -220,7 +220,7 @@ extension UIControl { } extension UIButton { - override var amp_title: String? { currentTitle } + override var amp_title: String? { currentTitle ?? currentImage?.accessibilityIdentifier } } extension UISegmentedControl {