iOS设备进入睡眠模式(屏幕变暗)时,有没有一种方法可以检测到该事件?

14

这个问题是关于 iPhone 的私有 API 吗? - iDev
2
任何东西都可以,我不打算在应用商店上提交我的应用程序。 - Rohit Kashyap
2个回答

22

你已经基本上有了解决方案,我猜想你是从我的最近的回答中找到的 :)

使用com.apple.springboard.hasBlankedScreen事件。

当屏幕变黑时会出现多个事件,但这一个应该就足够了:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                NULL, // observer
                                hasBlankedScreen, // callback
                                CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
                                NULL, // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);

回调函数所在位置:

static void hasBlankedScreen(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    NSString* notifyName = (__bridge NSString*)name;
    // this check should really only be necessary if you reuse this one callback method
    //  for multiple Darwin notification events
    if ([notifyName isEqualToString:@"com.apple.springboard.hasBlankedScreen"]) {
       NSLog(@"screen has either gone dark, or been turned back on!");
    }
}

更新:正如@VictorRonin在下面的评论中所说,很容易自己跟踪屏幕当前是否打开或关闭。这样可以确定当屏幕打开或关闭时是否发生了“hasBlankedScreen”事件。例如,当您的应用程序启动时,请设置一个变量以指示屏幕已打开。此外,任何时候进行任何UI交互(按下按钮等),您都知道屏幕必须当前处于打开状态。因此,您收到的下一个“hasBlankedScreen”应该指示屏幕处于关闭状态。
另外,我想确保我们对术语清楚。当屏幕由于超时而自动变暗或用户手动按下电源按钮时,设备会锁定。无论用户是否配置了“密码”,都会发生这种情况。此时,您将看到“com.apple.springboard.hasBlankedScreen”和“com.apple.springboard.lockcomplete”事件。
当屏幕重新打开时,您将再次看到“com.apple.springboard.hasBlankedScreen”。但是,在用户使用滑动(和可能的密码)解锁设备之前,您不会看到“com.apple.springboard.lockstate”。
更新2:
还有另一种方法可以做到这一点。您可以使用另一组API来侦听此通知,并在通知到达时获取状态变量。请参见:获取状态变量
#import <notify.h>

int status = notify_register_dispatch("com.apple.springboard.hasBlankedScreen",
                                      &notifyToken,
                                      dispatch_get_main_queue(), ^(int t) {
                                          uint64_t state;
                                          int result = notify_get_state(notifyToken, &state);
                                          NSLog(@"lock state change = %llu", state);
                                          if (result != NOTIFY_STATUS_OK) {
                                              NSLog(@"notify_get_state() not returning NOTIFY_STATUS_OK");
                                          }
                                      });
if (status != NOTIFY_STATUS_OK) {
    NSLog(@"notify_register_dispatch() not returning NOTIFY_STATUS_OK");
}

你需要保留一个ivar或其他持久化变量来存储通知令牌(不要只将其作为注册方法中的本地变量!)

int notifyToken;

您应该看到通过notify_get_state()获取的state变量在0和1之间切换,这将使您区分屏幕开和关事件。
虽然此文档非常旧,但它列出了哪些通知事件具有可以通过notify_get_state()检索的关联状态。 警告:请参阅此相关问题以了解此最后一种技术的一些复杂性

1
你可以保持一个状态变量,表示设备当前是休眠还是唤醒状态。 - Victor Ronin
@SpencerWilliams,嗯。对我来说有效。我认为您可能需要发布一个新问题,并完全列出您的代码和用例描述。谢谢。 - Nate
@nate:有没有公共API可以实现相同的功能? - Sunil Adhyaru
@SunilAdhyaru,上面的答案确实使用了公共API。在iOS中,“CFNotificationCenterAddObserver()”是公开的。事件的字符串名称是未记录的。但是,它实际上并不是私有的。您应该能够在App Store应用程序中使用此代码。不过我已经有一段时间没有测试过了,所以请确保它仍然有效。 - Nate
@WilliamGrand 这个问题明确不是针对App Store的,但你的评论对其他人来说很有用。如果有人愿意的话,混淆可能会解决这个“问题” ;) - Nate
显示剩余9条评论

1
您还可以订阅通知:"com.apple.springboard.lockstate",并使用API SBGetScreenLockStatus 来确定设备是否已锁定。

如何调用和使用它?实际上我只想检测屏幕变黑的事件,即屏幕从开启到关闭的过渡。先行致谢。 - Rohit Kashyap
提示:不适用于越狱设备。 - Rohit Kashyap
第一条通知使用Nate编写的相同代码。SBGetScreenLockStatus在链接的文章中有描述。这些事件我作为“设备锁定/解锁”答案添加了进去。它适用于非越狱设备。 - Victor Ronin
1
@大家:请查看这个问题,因为它解释了这种方法可能存在的一些潜在陷阱:https://dev59.com/Fm7Xa4cB1Zd3GeqPolfa - Victor Ronin

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