gpt4 book ai didi

ios - 在 iOS 和 OS X 中获取系统范围通知的状态

转载 作者:可可西里 更新时间:2023-11-01 04:31:02 29 4
gpt4 key购买 nike

我正在尝试编写一个代码来处理 iOS 上的打开/关闭屏幕(您可以查看讨论类似问题的 this 问题)。我为这个问题包含了 OSX 标签,因为 OSX 具有相同的系统范围的通知工具。下面描述的问题是继承到通知工具(与 iOS 或 OSX 相比)。

有一种众所周知的注册系统范围通知的方法 com.apple.springboard.hasBlankedScreen 在屏幕关闭或打开时接收通知。

仅供引用(这里是用于注册系统范围通知的 API):

  • notify_post、notify_check_notify_get_state 和 friends
  • CFNotificationCenterPostNotification、CFNotificationCenterAddObserver 和 friends (在内部使用 notify_post 等)

  • 但是,这种方法存在两个相互关联的问题:
  • 屏幕关闭和打开的通知具有相同的名称 (com.apple.springboard.hasBlankedScreen)
  • 观察者不会收到作为通知一部分的状态。

  • 因此,我们需要实现一些不同的屏幕打开和关闭的解决方案(因为将调用相同的通知回调并且没有任何参数具有状态)。

    一般来说,核心问题是状态与通知回调解耦。我不知道如何优雅地处理这个问题。

    我提出了两种直接的方法(每个方法都有缺陷)。并寻找另一种方法的想法或对这种方法的改进。

    计数解决方案

    我们可以实现一个计数器来计算我们已经收到了多少通知,并根据此信息我们将知道它是打开还是关闭屏幕的通知(基于我们计数器的奇怪程度)。

    但是,它有两个缺点:

    1) 在这种情况下,如果系统(由于设计时原因未知)将发送具有相同名称的附加通知,我们的逻辑将被搞砸,因为它会破坏奇数检查。

    2)另外,我们需要正确设置初始状态。所以在代码中的某个地方,我们会有这样的东西:

    counter = getInitialState(); 
    registerForNotification();


    在这种情况下,我们有一个竞争条件。如果系统会在我们执行 getInitialState() 之后发送通知并更改状态,但在 registerForNotification() 之前,我们最终会得到错误的计数器值。

    如果我们将执行以下代码:

    registerForNotification();
    counter = getInitialState();


    在这种情况下,我们有另一个竞争条件。如果在我们执行 registerForNotification() 之后系统会发送通知并更改状态,但在 getInitialState() 之前,我们将获得一个计数器,将进入通知回调并增加一个计数器(这会导致错误)。

    收到通知时确定状态解决方案

    在这种情况下,我们不存储任何计数器,而是在通知回调中使用 API notify_get_state 来获取当前状态。

    这有它自己的问题:

    1) 异步传递给应用程序的通知。因此,如果您非常快速地关闭和打开屏幕,您可以在屏幕已经打开时收到这两个通知。因此,notify_check 将获得当前状态(与发送通知时的状态相比)。

    因此,当应用程序将在通知回调中使用 notify_get_state 时,它​​将确定有两个通知“屏幕已打开”,而不是一个通知“屏幕已关闭”和另一个“屏幕已打开”。

    附言一般来说,所有描述的问题并非特定于屏幕开/关情况。它们对于任何具有独特状态并使用相同通知名称发送的系统范围通知都是实际的。

    更新 1

    我没有测试非常快速地打开/关闭屏幕并从notify_get_state() 获得相同结果的场景。

    但是,当我收到两个通知 com.apple.springboard.lockstate(通过 CFNotificationCenterAddObserver 订阅)并且我使用另一个 API 来获取当前设备锁定状态并收到两个通知的相同值时,我有一种类似的情况。

    所以这只是我的假设,notify_get_state 也会返回相同的值。但是,我认为这是有根据的猜测。对于两次调用,notify_get_state 的输入参数将相同(它不会改变)。而且我认为系统不会存储应由 notify_get_state 返回的状态的 FIFO 队列。

    最佳答案

    所以,我建立了一个非常简单的实验。我在调试器之外的越狱 iOS 6.1 iPhone 5 上运行它。

    代码

    我使用以下代码构建了一个消费者应用程序:

    #define EVENT "com.mycompany.bs"

    - (void)registerForNotifications {
    int result = notify_register_dispatch(EVENT,
    &notifyToken,
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0l),
    ^(int info) {
    uint64_t state;
    notify_get_state(notifyToken, &state);
    NSLog(@"notify_register_dispatch() : %d", (int)state);
    });
    if (result != NOTIFY_STATUS_OK) {
    NSLog(@"register failure = %d", result);
    }
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
    NULL, // observer
    notifyCallback, // callback
    CFSTR(EVENT), // event name
    NULL, // object
    CFNotificationSuspensionBehaviorDeliverImmediately);
    }

    static void notifyCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    uint64_t state;
    notify_get_state(notifyToken, &state);
    NSLog(@"notifyCallback(): %d", (int)state);
    }

    因此,如您所见,它使用两种不同的方法来注册同一个自定义事件。我启动这个应用程序,让它注册事件,然后把它放到后台(按下主页按钮)。

    然后,生产者应用程序,它让我通过按下按钮生成事件:
    double delayInSeconds = 0.001;

    dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0l);
    dispatch_async(q, ^(void) {
    notify_set_state(notifyToken, 2);
    notify_post(EVENT);
    });

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, q, ^(void){
    notify_set_state(notifyToken, 3);
    notify_post(EVENT);
    });

    结果

    然后我运行生产者应用程序,大约每两秒手动生成一对事件。如您所见,生产者快速发布了状态为 2 的事件。 ,然后立即发布另一个状态为 3 的事件.所以,消费者应该打印出 2然后 3 , 为 两者 回调方法,如果这工作完美。它不会(正如您所担心的那样):
    Feb 13 21:46:12 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3
    Feb 13 21:46:12 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:12 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:12 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:18 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3
    Feb 13 21:46:18 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:18 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:18 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:22 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3
    Feb 13 21:46:22 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:22 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:22 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:26 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 2
    Feb 13 21:46:26 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:26 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:26 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:30 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3
    Feb 13 21:46:30 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:30 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:30 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:33 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3
    Feb 13 21:46:33 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:33 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:33 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    Feb 13 21:46:36 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 2
    Feb 13 21:46:36 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:36 iPhone5 MyApp[1971] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:46:36 iPhone5 MyApp[1971] <Warning>: notifyCallback(): 3

    我尝试将一种消费者注册方法更改为使用 CFNotificationSuspensionBehaviorCoalesce (而不是立即交付)。结果:
    Feb 13 21:48:17 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3
    Feb 13 21:48:17 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:17 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:17 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:20 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:20 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:20 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:20 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:24 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:24 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:48:24 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:24 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:29 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:29 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:29 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:29 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:32 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:32 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:48:32 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:32 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:35 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:35 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:48:35 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:35 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:38 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:38 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:48:38 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:38 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    Feb 13 21:48:39 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 2
    Feb 13 21:48:39 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:39 iPhone5 MyApp[1990] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:48:39 iPhone5 MyApp[1990] <Warning>: notifyCallback(): 3

    然后我尝试更改 notify_register_dispatch() 的队列优先级消费者到 , 而不是 背景优先事项。结果:
    Feb 13 21:49:51 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3
    Feb 13 21:49:51 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:49:51 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:49:51 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:49:53 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:49:53 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:49:53 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3
    Feb 13 21:49:53 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3

    Feb 13 21:49:55 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:49:55 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:49:55 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:49:55 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:49:59 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:49:59 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:49:59 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:49:59 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:50:01 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:50:01 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:01 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:01 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:50:04 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:50:04 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:50:04 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:04 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:50:06 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:50:06 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:50:06 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:06 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:50:09 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:50:09 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 2
    Feb 13 21:50:09 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:09 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    Feb 13 21:50:10 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 2
    Feb 13 21:50:10 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:10 iPhone5 MyApp[2006] <Warning>: notify_register_dispatch() : 3
    Feb 13 21:50:10 iPhone5 MyApp[2006] <Warning>: notifyCallback(): 3

    结论(?)
  • 您怀疑存在问题,而且不仅仅是 SBGetScreenLockStatus称呼。有时,消费者从未看到状态设置为 2 .
  • 如果我将生产者时间延迟增加到 5 毫秒,我从未发现问题。因此,这可能只是时间非常接近的事件的问题。屏幕锁定/解锁可能没什么大不了的。显然,速度较慢的手机(iPhone < 5)会有不同的 react 。
  • notifyCallback()方法似乎被回调了 第一 , 除非 GCD 回调块被放在高优先级队列中。即便如此,通常首先调用静态回调函数。很多时候,第一个回调的方法得到了正确的状态( 2 ),而第二个没有。所以,如果你不得不忍受这个问题,你可能会选择看起来性能最好的回调机制(或者至少,在你的应用程序中自己做原型(prototype))。
  • 我不能说 suspensionBehavior参数有很大的不同。也就是说,取决于 iOS 的方式 发帖 事件,他们可能正在使用类似 CFNotificationCenterPostNotification 的电话可能会忽略消费者的行为请求。
  • 如果你看 this Apple document ,你会看到两件事。
  • 一、notify_set_state不是原始 API 的一部分
  • 其次,该文件的第一段说

  • Darwin Notification API Reference

    These routines allow processes to exchange stateless notification events.



    所以,也许我们只是想做一些与原始设计不一致的事情:(
  • 如果您还查看 Apple's NotificationPoster example ,你看他们不使用 notify_get_statenotify_set_state传达状态。他们通过了 与通知 作为用户信息字典。显然,如果您正在观察 Apple 的 iOS 事件,则无法控制事件的发布方式。但是,在您可以创建生产者的应用程序中 消费者,我会远离notify_set_state .
  • 关于ios - 在 iOS 和 OS X 中获取系统范围通知的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14820249/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com