Search code examples
iosswiftswiftuiios14

How to track all touches across SwiftUI app


I'm trying to implement a lock screen in the SwiftUI app.

I need to track every event in order to restart the lock timer.

In UIKit app, I used this approach - overriding UIApplication, which allows being aware of any event across the app:

override func sendEvent(_ event: UIEvent) {
  super.sendEvent(event)

  switch event.type {
  case .touches:
    // Post Notification or Delegate here
  default:
    break
  }
}

But in SwiftUI it is not supported anymore. I tried to add

.onTapGesture {}

to the root ContentView, but it doesn't work as expected.

Is there any way to avoid adding

.onTapGesture {}

to every single view in the app?


Solution

  • Here is a possible solution:

    @main
    struct TestApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
            }
        }
    }
    
    extension UIApplication {
        func addTapGestureRecognizer() {
            guard let window = windows.first else { return }
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAction))
            tapGesture.requiresExclusiveTouchType = false
            tapGesture.cancelsTouchesInView = false
            tapGesture.delegate = self
            window.addGestureRecognizer(tapGesture)
        }
    
        @objc func tapAction(_ sender: UITapGestureRecognizer) {
            print("tapped")
        }
    }
    
    extension UIApplication: UIGestureRecognizerDelegate {
        public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
            return true // set to `false` if you don't want to detect tap during other gestures
        }
    }