Swift - 检测应用程序何时发送到后台而不是设备锁定时

Posted

技术标签:

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

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

func applicationDidEnterBackground(application: UIApplication) 

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

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

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

【问题讨论】:

【参考方案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
    


【讨论】:

以上是关于Swift - 检测应用程序何时发送到后台而不是设备锁定时的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HTML 和 JavaScript 检测 iOS 应用何时进入后台

检测应用程序是不是从后台 Swift iOS 打开

如何使用 Swift 检测 iOS 应用程序何时出现在前台? [复制]

何时最好执行 iCloud 同步

快速,在后台检测 ibeacons 并在范围内发送通知

检测应用程序何时进入我的视图背景的最佳方法是啥?