Swift CoreMotion检测设备在后台中的轻敲或敲击

6

我目前正在构建我的第一个iOS Swift应用程序,我想在应用程序在后台运行时执行一个操作。

当用户在设备上轻击两次时,需要执行该操作。

我已经在应用程序功能中启用了背景模式:位置更新

并在AppDelegate中设置了AccelerometerUpdatesToQueue函数:

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
}

控制台按预期打印出加速度.z值,但一旦我按下主页按钮,控制台会打印“停止”。 我在网上搜索了如何做到这一点的示例代码,我知道这是可能的...因为我们都知道应用程序“敲门解锁”,但我似乎找不到Swift的示例代码片段。
3个回答

9

我把它搞定了!这是我的解决方案,欢迎提出改进意见 :)

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
    }

需要使用背景模式 - Individual11
@Individual11,我们如何在后台模式下使CoreMotion仍然工作?您能否给我更多信息?CoreMotion在Kill App状态下是否可用?非常感谢您的帮助。 - Rawan
1
@svh1985 你好,你怎么让你的应用在后台状态下工作?我没有很明白你的回答,能否请你给我更多的细节呢?我也遇到了同样的问题,不知道该如何解决。还有一个问题,如果应用程序被杀死,你知道CoreMotion是否会继续工作吗?谢谢你的帮助 :) - Rawan
我从未完全按照自己的意愿使其正常工作。有一些方法可以让你的应用程序在后台运行,例如网络和蓝牙等,但如果我的应用程序实际上不需要它,我不想使用它作为一种欺骗手段。 - Individual11

1

In Swift 5.1 this line:

manager.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue()) { [weak self] (data: CMDeviceMotion!, error: NSError!) in

需要是:

manager.startDeviceMotionUpdates(to: .main) { [weak self] (data, error) in

1
感谢您发布这篇文章。虽然我需要弄清楚如何将这些数据与常规移动数据分开,但这对我很有帮助。一个建议是使用fabs来获取userAcceleration.z的绝对值。
 if (data.userAcceleration.z < -0.7) || (data.userAcceleration.z > 0.7) { // Check if device is knocked

变成了

if (fabs(data.userAcceleration.z) > 0.7) { // Check if device is knocked

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接