Swift CoreMotion detects Tap or Knock on the device while in the background
I'm currently in the process of building my first iOS Swift app, with this app I want to take an action while the app is running in the background.
The action must be performed as soon as the user double-clicked on the device.
I have enabled Background Modes: Location Updates in the Features app
And set up the AccelerometerUpdatesToQueue function in the AppDelegate:
let manager = CMMotionManager()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if manager.accelerometerAvailable {
manager.accelerometerUpdateInterval = 0.01
manager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue()) {
[weak self] (data: CMAccelerometerData!, error: NSError!) in
println(data.acceleration.z)
}
}
return true
}
The console prints out the acceleration.z value as expected, but as soon as I hit the home button, the console prints stop.
I have searched the internet for sample code on how to do this and I know it is possible ... because we all know the "Knock Knock to unlock" application, but I cannot find a piece of sample code for Swift.
source to share
I got it to work! This is my solution, feel free to suggest improvements :)
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let manager = CMMotionManager()
var knocked : Bool = false
let motionUpdateInterval : Double = 0.05
var knockReset : Double = 2.0
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if manager.deviceMotionAvailable {
manager.deviceMotionUpdateInterval = motionUpdateInterval // seconds
manager.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue()) {
[weak self] (data: CMDeviceMotion!, error: NSError!) in
if (data.userAcceleration.z < -0.7) || (data.userAcceleration.z > 0.7) { // Check if device is knocked
// Check for double knock
if self!.knocked == false {
// First knock
println("First Knock")
self!.knocked = true
}else{
// Second knock
println("Double Knocked")
self!.knocked = false
self!.knockReset = 2.0
// Action:
}
}
// Countdown for reset action (second knock must be within the knockReset limit)
if (self!.knocked) && (self!.knockReset >= 0.0) {
self!.knockReset = self!.knockReset - self!.motionUpdateInterval
}else if self!.knocked == true {
self!.knocked = false
self!.knockReset = 2.0
println("Reset")
}
}
}
return true
}
source to share
Thanks for posting this. This helps me, although I need to figure out how to separate this data from regular traffic data. One suggestion ... use fabs to get the absolute value of userAcceleration.z.
if (data.userAcceleration.z < -0.7) || (data.userAcceleration.z > 0.7) { // Check if device is knocked
becomes
if (fabs(data.userAcceleration.z) > 0.7) { // Check if device is knocked
source to share