简体   繁体   English

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

[英]Swift - Detecting when app is sent to background but not when device is locked

I'm in the process of developing an iOS app where I need to track if the user leaves the app (presses the home button to use other apps) while they are 'in game' however the user should be able to lock and un-lock their device without this function being called. 我正在开发一个iOS应用程序,我需要跟踪用户是否离开应用程序(按下主页按钮以使用其他应用程序),而他们在“游戏中”但是用户应该能够锁定和取消在没有调用此函数的情况下锁定其设备。

func applicationDidEnterBackground(application: UIApplication) {

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

This, unfortunately, is triggered when the user locks their devices as well as when they exit the app. 不幸的是,当用户锁定他们的设备以及他们退出应用程序时,会触发此操作。

A little context about the app: The app encourages people to focus on their work and not become distracted by their phones for a preset time period. 关于应用程序的一些背景:该应用程序鼓励人们专注于他们的工作,而不是在预设的时间段内被手机分心。 Other suggestions of how I can encourage the users to reopen the app upon exit while the timer is still active but not when they lock their devices would be greatly welcomed! 关于如何鼓励用户在退出时重新打开应用程序的其他建议,当计时器仍处于活动状态但不是在他们锁定设备时,将非常受欢迎!

Well, there's no clean way to do this. 好吧,没有干净的方法来做到这一点。 But there is a hack that you can use. 但是有一个你可以使用的黑客。 It's not guaranteed to keep working though(I've tested up to iOS 9.3 and I'm pretty sure it works on the iOS 10 betas). 它不能保证继续工作(我已经测试了iOS 9.3,我很确定它适用于iOS 10测试版)。

The idea is that there's a system-wide notification for the phone being locked. 这个想法是有一个系统范围的电话被锁定通知。 You can listen to that and coupled with listening to background/foreground events on your app you can determine what's happening. 你可以听到它,再加上听你的应用程序上的背景/前景事件,你可以确定发生了什么。

This is a piece of code for an object that will watch for this stuff. 这是一个用于观察这些东西的对象的代码片段。 Create it from app delegate or wherever and keep a strong ref for as long as you need it. 从应用代表或任何地方创建它,并在您需要时保留强大的参考。 Give it a delegate it can call for whatever events you want to observer and react to(or put the code right there in checkState ). 给它一个委托,它可以调用你想要观察的任何事件并做出反应(或者将代码放在checkState )。 I haven't compiled this so I may have made some errors typing it up. 我没有编译这个,所以我可能会输入一些错误。 It's derived from code I use in an app, but the original has a lot more stuff I won't post here. 它源自我在应用程序中使用的代码,但原始文件中有更多我不会在此处发布的内容。 It's in objc but it shouldn't be too hard to convert to swift(someone feel free to post a second answer in swift or edit mine, but I don't have the time to do it right now) 这是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
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在后台或设备锁定时,iOS应用程序会使用电池吗? - Does an iOS app use battery when in the background or when the device is locked? 当应用程序在后台且设备被锁定时处理推送通知 - Handling push notification when app is in background and device is locked 当设备被锁定时,什么可以在后台唤醒 iOS 应用程序? - What can wake up an iOS app in the background when the device is locked? 当应用程序处于后台或设备锁定时,Airplay 停止播放视频流 - Airplay stop playing video streaming when app is in background or device locked swift:如何在手机锁定或后台应用程序时拨打电话 - swift: How to make a call when phone is locked or app in background Swift:锁定装置时继续播放声音 - Swift: Keep playing sounds when the device is locked 当应用程序在后台或设备被锁定时运行代码 - Running the code when application is in the background or device is locked 设备锁定时后台任务停止? - Background task stopping when device locked? 当音频在iOS应用中运行时,应在设备锁定但应用未置于后台时继续播放 - When audio runs in iOS app,it should continue playing when device is locked but not app put in background 设备锁定时,NSURLConnection应用程序崩溃 - NSURLConnection App Crash when the device is locked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM