アプリケーションで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でも十分です。前もって感謝します。
私はそれを次のように解決しました:
//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の最近のバージョンでは、2つの通知のorderは信頼できなくなりました
現在、アプリはデバイスロック通知をリッスンできません。
私はこれを受け取りました:
親愛なる開発者、
最近の「xxxx」の送信で1つ以上の問題が見つかりました。提出物を処理するには、次の問題を修正する必要があります。
サポートされていない操作-アプリはデバイスロック通知をリッスンできません。
これらの問題が修正されたら、XcodeまたはApplicationLoaderを使用して新しいバイナリをiTunesConnectにアップロードします。 iTunes Connectの[マイアプリ]のアプリの[詳細]ページで新しいバイナリを選択し、[レビューのために送信]をクリックします。
よろしく、
AppStoreチーム
2017年4月26日10:56
/ *ロック状態を検出するためのアプリを登録します* /
-(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];
});
}
これがより良い解決策です
#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;
}
}
チェックロックボタンの解決策は、アプリを押すか、バックグラウンドモードにすることでした。
ロックを押してアプリをバックグラウンドモードにするためのアプリサイクル-
ロックを押すと
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.**
特定のユースケースでは、画面の明るさを確認すると便利です。
var isScreenLocked: Bool {
return UIScreen.main.brightness == 0.0
}
ジミーは素晴らしい解決策を提供しましたが、オブザーバーとして(__bridge const void *)(self)
を渡す方が安全です。
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
displayStatusChanged,
CFSTR("com.Apple.springboard.lockcomplete"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
これにより、オブザーバーを適切に削除できます。