12

How can I detect a device shake in the AppDelegate (across the entire app) in Swift?

I've found answers that describe how to do so in a view controller, but looking to do so across my app.

Rashwan L
  • 38,237
  • 7
  • 103
  • 107
Liran Cohen
  • 194
  • 2
  • 9
  • 2
    Possible duplicate of [How do I detect when someone shakes an iPhone?](http://stackoverflow.com/questions/150446/how-do-i-detect-when-someone-shakes-an-iphone) – fishinear Jan 13 '16 at 17:21

3 Answers3

32

If you want to globally detect shake motion, the UIWindow implements UIResponder that can receive shake motion event. You can add the following snippet to AppDelegate

extension UIWindow {
    open override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
        if motion == .motionShake {
            print("Device shaken")
        }
    }
}
jk2K
  • 4,279
  • 3
  • 37
  • 40
  • This worked for me. Just adding it (without the UIWindow extension) didn't work when I put it in the app delegate. Had to add `open` in front of func for iOS 10.3/Xcode8.3. – Chris Prince Jul 26 '17 at 21:24
  • 1
    Quite strange, motionBegan get called, but motionEnded doesn't. – DàChún Jan 09 '18 at 08:35
  • 2
    After trying many other solutions, this is the only one that works for me. Also, I learned that I can override functions in extensions. Awesome! – Lensflare Feb 08 '19 at 10:15
  • Bad idea to use the extension. Provide your own subclass, define the method in it. See https://stackoverflow.com/a/10580083/1633251 . You can then pass the events to super - maybe they are needed there. – David H May 21 '20 at 19:16
8

Add the following snippet in your AppDelegate:

override func motionBegan(motion: UIEvent.EventSubtype, withEvent event: UIEvent?) {
    if motion == .MotionShake {
        print("Device shaken")
    }
}

Swift 3.0 version:

override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
    if motion == .motionShake {
        print("Device shaken")
    }
}

As for later versions this does not seem to work anymore. You need to add the above code in your view controller instead

Community
  • 1
  • 1
Rashwan L
  • 38,237
  • 7
  • 103
  • 107
0

As of Swift 4 or 5, it's UIEvent.EventSubtype, not UIEventSubtype.

Also don't forget to add a call to super.motionEnded(motion, with: event). This preserves any motionEnded customizations on your view controllers.

extension UIWindow {
    open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        super.motionEnded(motion, with: event)
        
        if motion == .motionShake {
            print("Device shaken")
        }
    }
}
spnkr
  • 952
  • 9
  • 18