【问题标题】:Swift - Detecting when app is sent to background but not when device is lockedSwift - 检测应用程序何时发送到后台而不是设备锁定时
【发布时间】:2016-08-24 11:23:24
【问题描述】:

我正在开发一个 iOS 应用程序,我需要跟踪用户在“游戏中”时是否离开应用程序(按下主页按钮以使用其他应用程序),但用户应该能够锁定并在不调用此函数的情况下解锁他们的设备。

func applicationDidEnterBackground(application: UIApplication) {

    if defaults.boolForKey("TimerActive"){
        defaults.setBool(true, forKey: "Failed")
    }
}

不幸的是,当用户锁定他们的设备以及退出应用程序时会触发此事件。

关于该应用的一些背景信息:该应用鼓励人们专注于他们的工作,并且在预设的时间段内不要被手机分心。 其他关于我如何鼓励用户在计时器仍处于活动状态但在他们锁定设备时退出时重新打开应用程序的其他建议将非常受欢迎!

【问题讨论】:

    标签: ios swift appdelegate


    【解决方案1】:

    嗯,没有干净的方法可以做到这一点。但是有一个黑客可以使用。但不能保证它可以继续工作(我已经测试到 iOS 9.3,我很确定它可以在 iOS 10 测试版上运行)。

    这个想法是有一个关于手机被锁定的系统范围的通知。您可以收听它,并结合收听应用上的背景/前台事件,您可以确定正在发生的事情。

    这是一段代码,用于监视这些内容的对象。从应用程序委托或任何地方创建它,并在需要时保持强大的引用。给它一个委托,它可以调用您想要观察和响应的任何事件(或将代码放在checkState 中)。我还没有编译这个,所以我可能在输入它时犯了一些错误。它源自我在应用程序中使用的代码,但原始代码还有很多我不会在这里发布的内容。它在 objc 中,但转换为 swift 应该不会太难(有人可以在 swift 中发布第二个答案或编辑我的,但我现在没有时间这样做)

    @interface LockStateDetector : NSObject {
        int _notify_token;
    }
    
    @property BOOL deviceIsLocked;
    @property BOOL appIsInBackground;
    @property NSTimer * checkStateTimer;
    
    @end
    
    @implementation LockStateDetector
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
           [self registerForNotifications];
        }
        return self;
    }
    
    - (void)dealloc
    {
       [[NSNotificationCenter defaultCenter] removeObserver:self];
       notify_cancel(_notify_token);
    }
    
    - (void)registerForNotifications
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMoveToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
        __weak__ LockStateDector * wSelf = self;
        notify_register_dispatch("com.apple.springboard.lockstate", &_notify_token, dispatch_get_main_queue(), ^(int token) {
            __strong__ LockStateDetector sSelf = wSelf;
            if (!sSelf) { 
                return;
            }
            uint64_t state = UINT64_MAX;
            notify_get_state(token, &state);
            sSelf.deviceIsLocked = state != 0;
            NSLog(@"device lock state changed: %@", @(state));
            [sSelf checkState];
        });
    }
    
    - (void)didBecomeActive
    {
        self.appIsInBackground = NO;
        [self checkState];
    }
    
    - (void)didMoveToBackground
    {
        self.appIsInBackground = YES;
        [self checkState];
    }
    
    - (void)checkState
    {
        [self.checkStateTimer invalidate];
        self.checkStateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(_checkState) userInfo:nil repeats:NO];
    }
    
    - (void)_checkState
    {
        [self.checkStateTimer invalidate];
        self.checkStateTimer = nil;
    
        if (!self.appIsInBackground) {
            return;
        }
    
        if (!self.deviceIsLocked) {
            // app is in background because device was locked
        } else {
           // app is in background because user pressed home and switched to something else
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-06
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      相关资源
      最近更新 更多