我在我的应用程序中使用了GPS位置更新。我想检测iOS设备是否处于睡眠模式,这样我就可以关闭GPS位置更新并优化电池使用。我已经在iOS 6中尝试了pausesLocationupdates,但它无法正常工作。 我想在设备进入睡眠模式后立即关闭GPS位置更新。 我想检测设备中的锁定/解锁事件。
有没有办法实现这个功能?
到目前为止,我收到了下面给出的达尔文通知
-(void)registerForall
{
//Screen lock notifications
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.iokit.hid.displayStatus"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockcomplete"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
}
//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
NSLog(@"IN Display status changed");
NSLog(@"Darwin notification NAME = %@",name);
}
当设备被锁定/解锁时,我能够获得达尔文通知,但真正的问题是如何识别通知是来自锁定还是解锁设备。控制台日志是:
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockcomplete
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockstate
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.hasBlankedScreen
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.iokit.hid.displayStatus
任何私有API也足够了。 提前谢谢。
答案 0 :(得分:16)
//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
// the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
CFStringRef nameCFString = (CFStringRef)name;
NSString *lockState = (NSString*)nameCFString;
NSLog(@"Darwin notification NAME = %@",name);
if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
{
NSLog(@"DEVICE LOCKED");
//Logic to disable the GPS
}
else
{
NSLog(@"LOCK STATUS CHANGED");
//Logic to enable the GPS
}
}
-(void)registerforDeviceLockNotif
{
//Screen lock notifications
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockcomplete"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
}
注意:“com.apple.springboard.lockcomplete”通知将始终位于“com.apple.springboard.lockstate”通知之后
从iOS的最新版本开始,无法再依赖两个通知的顺序
答案 1 :(得分:8)
现在不允许应用听设备锁定通知!。
我收到了这个:
亲爱的开发人员,
我们发现您最近提交的“xxxx”存在一个或多个问题。要处理您的提交,必须纠正以下问题:
不支持的操作 - 不允许应用程序收听设备锁定通知。
一旦纠正了这些问题,请使用Xcode或Application Loader将新二进制文件上传到iTunes Connect。在iTunes Connect上的“我的应用程序”中的应用程序“详细信息”页面上选择新的二进制文件,然后单击“提交以供审阅”。
此致
App Store团队
2017年4月26日10:56
答案 2 :(得分:6)
/ *注册用于检测锁定状态的应用程序* /
-(void)registerAppforDetectLockState {
int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_token,dispatch_get_main_queue(), ^(int token) {
uint64_t state = UINT64_MAX;
notify_get_state(token, &state);
if(state == 0) {
NSLog(@"unlock device");
} else {
NSLog(@"lock device");
}
NSLog(@"com.apple.springboard.lockstate = %llu", state);
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.repeatInterval = NSDayCalendarUnit;
[notification setAlertBody:@"Hello world!! I come becoz you lock/unlock your device :)"];
notification.alertAction = @"View";
notification.alertAction = @"Yes";
[notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]];
notification.soundName = UILocalNotificationDefaultSoundName;
[notification setTimeZone:[NSTimeZone defaultTimeZone]];
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
});
}
答案 3 :(得分:4)
这是一个更好的解决方案
#import <notify.h>
#define kNotificationNameDidChangeDisplayStatus @"com.apple.iokit.hid.displayStatus"
@interface YourClass ()
{
int _notifyTokenForDidChangeDisplayStatus;
}
@property (nonatomic, assign, getter = isDisplayOn) BOOL displayOn;
@property (nonatomic, assign, getter = isRegisteredForDarwinNotifications) BOOL registeredForDarwinNotifications;
@end
- (void)registerForSomeNotifications
{
//
// Display notifications
//
__weak YourClass *weakSelf = self;
uint32_t result = notify_register_dispatch(kNotificationNameDidChangeDisplayStatus.UTF8String,
&_notifyTokenForDidChangeDisplayStatus,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0l),
^(int info) {
__strong YourClass *strongSelf = weakSelf;
if (strongSelf)
{
uint64_t state;
notify_get_state(_notifyTokenForDidChangeDisplayStatus, &state);
strongSelf.displayOn = (BOOL)state;
}
});
if (result != NOTIFY_STATUS_OK)
{
self.registeredForDarwinNotifications = NO;
return;
}
self.registeredForDarwinNotifications = YES;
}
- (void)unregisterFromSomeNotifications
{
//
// Display notifications
//
uint32_t result = notify_cancel(_notifyTokenForDidChangeDisplayStatus);
if (result == NOTIFY_STATUS_OK)
{
self.registeredForDarwinNotifications = NO;
}
}
答案 4 :(得分:1)
对于您的特定用例,检查屏幕亮度可能很有用。
var isScreenLocked: Bool {
return UIScreen.main.brightness == 0.0
}
答案 5 :(得分:1)
我有一个解决方案,用于检查锁定按钮是否被按下或将应用置于后台模式。
锁定按键的应用周期并将应用置于后台模式-
锁定时
applicationWillResignActive
applicationDidEnterBackground
解锁时
applicationWillEnterForeground
applicationDidBecomeActive
////////////////////// 何时插入背景
applicationWillResignActive
applicationDidEnterBackground
何时放弃
applicationWillEnterForeground
applicationDidBecomeActive
在两种情况下,您都可以观察到相同的方法正在调用。在这种情况下,要按下锁定按钮或将应用置于后台,这是一项艰巨的任务。 按下锁定按钮
applicationWillResignActive
applicationDidEnterBackground
这些方法将立即调用,但是当我们将应用程序置于后台时,这两种方法之间的时间间隔为毫秒。我们可以得到时差并为其设置条件。 喜欢......
var dateResignActive : Date?
var dateAppDidBack : Date?
func applicationWillResignActive(_ application: UIApplication) {
dateResignActive = Date()
}
func applicationDidEnterBackground(_ application: UIApplication) {
dateAppDidBack = Date()
}
func applicationDidBecomeActive(_ application: UIApplication) {
let el1 = getCurrentMillis(date: dateResignActive!)
let el2 = getCurrentMillis(date: dateAppDidBack!)
let diff = el2 - el1
if diff < 10 { //// device was locked // 10 is aprox
// device was locked
}
else {
let elapsed = Int(Date().timeIntervalSince(date!))
if elapsed > 15 { // put app in background
}
}
}
func getCurrentMillis(date : Date)->Int64 {
return Int64(date.timeIntervalSince1970 * 1000)
}
**This code is tested in iPhone X(Notch) and iPhone 6(Home button device). Because notch device and home button device have small difference in above two method calling.**
答案 6 :(得分:0)
吉米提供了一个很好的解决方案,但作为观察者传递(__bridge const void *)(self)
更安全。
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
displayStatusChanged,
CFSTR("com.apple.springboard.lockcomplete"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
这允许您正确删除观察者。
答案 7 :(得分:0)
在使用内容保护的设备上,受保护的文件以加密形式存储,并且仅在特定时间(通常是在设备解锁时)才可用。此通知可让您的应用知道该设备即将被锁定,并且该设备当前正在访问的所有受保护文件可能很快将不可用。
您可以订阅applicationProtectedDataWillBecomeUnavailable
的通知,这很可能是在用户刚刚锁定iPhone时触发的。
我从来没有自己做过,但这只是一个替代解决方案...