【问题标题】:How to listen to lock / unlock phone event while application is running in the background?如何在应用程序在后台运行时收听锁定/解锁手机事件?
【发布时间】:2015-12-17 22:45:53
【问题描述】:

我想让我的应用程序在手机被锁定和解锁时监控,以及当它变成空白时(长时间不活动后),而这一切都是在我的应用程序没有集中注意力,而是在后台运行的时候。

我可以在应用获得焦点时轻松接收锁定/解锁/空白事件:

-(void) startListeningForPhoneLockEvent
{
    NSLog(@"Start listening to lock/unlock and screen-goes-black events.");

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (void*)self,
                                lockStateChanged,
                                CFSTR("com.apple.springboard.lockstate"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (void*)self,
                                hasBlankedScreen,
                                CFSTR("com.apple.springboard.hasBlankedScreen"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);
}

还有回调函数:

static void lockStateChanged( CFNotificationCenterRef center, void*observer, CFStringRef name, const void *object, CFDictionaryRef userInfo )
{
    NSLog(@"Lock event received!");
}

static void hasBlankedScreen( CFNotificationCenterRef center, void*observer, CFStringRef name, const void *object, CFDictionaryRef userInfo )
{
    NSLog(@"Blanked screen event received!");
}

我已启用后台模式:

  • 后台提取。

但是,一旦应用进入后台,它就不会收到锁定/解锁/黑屏事件。

我已尝试使用其他后台模式,例如声音播放、位置更新等,但应用在后台时仍无法接收锁定/解锁/黑屏事件。

我不确定这是否真的可行,或者我做错了什么。

我正在使用最新的 XCode 和 iOS9 SDK 在更新到 iOS9 的真实设备上对其进行测试。

【问题讨论】:

  • 我也不介意 Swift 中的解决方案。
  • 仅在应用程序中启用后台模式并没有帮助,应用程序实际上应该在后台运行。当您锁定/解锁手机时,您能否确认您的应用程序确实在后台运行?
  • @SumantHanumante,Apple 对后台运行、监听锁定、解锁事件有任何限制吗?
  • 不幸的是,我目前无法访问物理设备,因此无法对其进行测试。但是您是否尝试让应用程序在后台运行,然后检查回调。让应用程序在后台运行的一种快速方法是在前台启动位置更新,然后在“位置更新”模式开启的情况下将应用程序置于后台。
  • 那你搞清楚了吗?有什么方法可以监控设备锁屏吗?我的意思是当用户输入错误的密码时,我们的应用程序应该在后台状态下做出反应或输入一些通知或方法。是否可以在 iOS 中实现该功能?在android中是可能的,所以。有人知道该怎么做吗?请指导我完成这个。

标签: ios objective-c multithreading events


【解决方案1】:

即使您的应用程序被配置为在后台运行,如果它没有任何工作要做,它也不会真正运行。要让它在后台运行并更新位置信息,请关注these instructions by Ricky

  1. 我在函数 didUpdateLocations 中每 1 分钟重新启动一次位置管理器。
  2. 我允许位置管理器在关闭设备前 10 秒从设备获取位置(以节省电池)。

部分代码如下:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

for(int i=0;i<locations.count;i++){
    CLLocation * newLocation = [locations objectAtIndex:i];
    CLLocationCoordinate2D theLocation = newLocation.coordinate;
    CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];

    if (locationAge > 30.0)
        continue;

    //Select only valid location and also location with good accuracy
    if(newLocation!=nil&&theAccuracy>0
       &&theAccuracy<2000
       &&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
        self.myLastLocation = theLocation;
        self.myLastLocationAccuracy= theAccuracy;
        NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
        [dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@"latitude"];
        [dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@"longitude"];
        [dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@"theAccuracy"];
        //Add the vallid location with good accuracy into an array
        //Every 1 minute, I will select the best location based on accuracy and send to server
        [self.shareModel.myLocationArray addObject:dict];
    }
}

//If the timer still valid, return it (Will not run the code below)
if (self.shareModel.timer)
    return;

self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
[self.shareModel.bgTask beginNewBackgroundTask];

//Restart the locationMaanger after 1 minute
self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self
                                                      selector:@selector(restartLocationUpdates)
                                                       userInfo:nil
                                                        repeats:NO];

//Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
//The location manager will only operate for 10 seconds to save battery
NSTimer * delay10Seconds;
delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target:self
                                                selector:@selector(stopLocationDelayBy10Seconds)
                                                userInfo:nil
                                                 repeats:NO];
 }

我能够在其中引用的 github 项目中使用您的代码,使用最新的 XCode 在运行 ios 9 的设备上监听锁定和解锁事件。以下是日志:

2015-12-18 13:31:44.777 位置[16185:3796448] startLocationTracking
2015-12-18 13:31:44.780 位置[16185:3796448] 授权状态已授权
2015-12-18 13:31:44.788 Location[16185:3796448] 开始监听锁定/解锁和屏幕变黑事件。
2015-12-18 13:31:44.834 位置[16185:3796448] locationManager didUpdateLocations
2015-12-18 13:31:44.837 Location[16185:3796448] 开始主任务1
2015-12-18 13:31:45.197 Location[16185:3796448] locationManager didUpdateLocations
2015-12-18 13:31:48.079 位置[16185:3796448] 收到黑屏事件!
2015-12-18 13:31:48.215 位置[16185:3796448] 收到锁定事件!

【讨论】:

  • 有人可以解释为什么这个答案被否决了吗?我尝试添加评论,它说我没有足够的业力,只能添加答案
猜你喜欢
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多