美文网首页MAC OS
Mac端App 睡眠和唤醒的通知、实现‘App防睡眠’

Mac端App 睡眠和唤醒的通知、实现‘App防睡眠’

作者: goyohol | 来源:发表于2021-05-29 22:33 被阅读0次


    实现Mac端App的功能:a.睡眠和唤醒的通知、b.实现‘App防睡眠’
    (创建桥接头文件)

    参考:
    Registering and unregistering for sleep and wake notifications
    用IOKit阻止Mac进入睡眠模式


    Developer 开发者文档Documentation Archive




    Cocoa可以用来接收睡眠唤醒通知,而I/O Kit还可以防止延迟 闲置睡眠(idle sleep)。然而,即使有I/O Kit,也不可能防止强制睡眠(forced sleep),只能延迟它。

    注意: Mac OS X两种不同的情况下睡眠强制(forced)和闲置(idle)。

    • 当用户采取某种直接行动让机器进入睡眠状态时,就会发生强制睡眠合上笔记本电脑的盖子或从苹果顶部菜单栏选择'睡眠'都会导致强制睡眠。该系统还将在某些条件下诱导强制睡眠,例如热紧急情况电池电量不足
    • 闲置睡眠是闲置一段时间发生的,是机器闲置的一段时间内配置的节能系统首选项


    本文只实现了OC代码的睡眠/唤醒通知使用、‘App防睡眠’方法!
    关于相应C语言实现,具体可以参考《Registering and unregistering for sleep and wake notifications》~



    注册/注销 睡眠和唤醒的通知

    -(void)OC_registerNotications { //OC-注册通知
        //These notifications are filed on NSWorkspace's notification center, not the default
            // notification center. You will not receive sleep/wake notifications if you file
            //with the default notification center.
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(receiveSleepNote:) name:NSWorkspaceWillSleepNotification object:NULL];
        
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(receiveWakeNote:) name:NSWorkspaceDidWakeNotification object:NULL];
    }
    -(void)OC_removeNotifications { //OC-移除通知
        [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceWillSleepNotification object:NULL];
        [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidWakeNotification object:NULL];
    }
    -(void)receiveSleepNote:(NSNotification *)note {//睡眠的响应
        NSLog(@"receiveSleepNote: %@", [note name]);
    }
    -(void)receiveWakeNote:(NSNotification *)note { //唤醒的响应
        NSLog(@"receiveWakeNote: %@", [note name]);
    }
    



    实现‘App防睡眠’功能 :打开Mac App时,不进入睡眠模式!

    头文件:#import <IOKit/pwr_mgt/IOPMLib.h>
    实现代码如下:

    // kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
    // kIOPMAssertionTypeNoIdleSleep prevents idle sleep
     
    //reasonForActivity is a descriptive string used by the system whenever it needs
    //  to tell the user why the system is not sleeping. For example,
    //  "Mail Compacting Mailboxes" would be a useful string.
     
    //  NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
    CFStringRef reasonForActivity = CFSTR("Describle Activity Type");
    
    IOPMAssertionID assertionID;
    IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
    if (success == kIOReturnSuccess) {
        //Add the work you need to do without
        //  the system sleeping here.
        
        success = IOPMAssertionRelease(assertionID);
        //The system will be able to sleep again.
    }
    

    1.新旧IPA

    • 废弃的IPA:IOPMAssertionCreate(<#CFStringRef AssertionType#>, <#IOPMAssertionLevel AssertionLevel#>, <#IOPMAssertionID *AssertionID#>)
      使用提示信息:'IOPMAssertionCreate' is deprecated: first deprecated in macOS 10.6
    • 新的IPA:IOPMAssertionCreateWithName是Mac OS X 10.6雪豹中可用的新API。
      IOPMAssertionCreateWithName允许应用程序返回一个简短的字符串给用户,解释为什么该应用程序阻止了睡眠。


    2.关于AssertionType参数 —— kIOPMAssertionType...
    kIOPMAssertionTypeNoDisplaySleep 防止显示器睡眠(会防止系统睡眠);
    kIOPMAssertionTypeNoIdleSleep 防止系统睡眠(显示器会睡眠)。

    测试结果是:

    kIOPMAssertionTypeNoDisplaySleep 既能防止显示器睡眠又能防止系统睡眠,就像放视频或做幻灯片一样。



    封装 (根据个人需求)

    两个方法集成到一个OC类(MacSleepWakeObject)里面:均使用类方法执行相关操作~
    (😒 嫌弃在Swift中找相应IPA — 防止系统睡眠使用I/O Kit时有使用C语言的方法,翻译成Swift有点麻烦! 所以还是用OC类来进行桥接~)

    .h文件:

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MacSleepWakeObject : NSObject
    
    +(void)preventSystemSleep;//防止系统休眠
    
    +(void)OC_registerNotications;//OC-注册通知
    +(void)OC_removeNotifications;//OC-移除通知
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    .m文件:

    #import "MacSleepWakeObject.h"
    
    #import <IOKit/pwr_mgt/IOPMLib.h>//防止休眠
    
    @import Cocoa;//才可以 注册、移除通知
    
    
    @implementation MacSleepWakeObject
    
    //防止系统休眠
    +(void)preventSystemSleep {
        // kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
        // kIOPMAssertionTypeNoIdleSleep prevents idle sleep
         
        //reasonForActivity is a descriptive string used by the system whenever it needs
        //  to tell the user why the system is not sleeping. For example,
        //  "Mail Compacting Mailboxes" would be a useful string.
         
        //  NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
        CFStringRef reasonForActivity = CFSTR("Describle Activity Type");
        
        IOPMAssertionID assertionID;
        IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
        if (success == kIOReturnSuccess) {
            //Add the work you need to do without
            //  the system sleeping here.
            
            success = IOPMAssertionRelease(assertionID);
            //The system will be able to sleep again.
        }
    }
    
    +(void)OC_registerNotications { //OC-注册通知
        //These notifications are filed on NSWorkspace's notification center, not the default
            // notification center. You will not receive sleep/wake notifications if you file
            //with the default notification center.
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(receiveSleepNote:) name:NSWorkspaceWillSleepNotification object:NULL];
        
        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(receiveWakeNote:) name:NSWorkspaceDidWakeNotification object:NULL];
    }
    +(void)OC_removeNotifications { //OC-移除通知
        [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceWillSleepNotification object:NULL];
        [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidWakeNotification object:NULL];
    }
    +(void)receiveSleepNote:(NSNotification *)note {//睡眠的响应
        NSLog(@"receiveSleepNote: %@", [note name]);
    }
    +(void)receiveWakeNote:(NSNotification *)note { //唤醒的响应
        NSLog(@"receiveWakeNote: %@", [note name]);
    }
    
    
    @end
    


    手动创建 桥接头文件
    创建新文件时选择'Header File'项创建一个头文件,以'-Brigding-Header.h'结尾的格式命名(命名为"SwiftAndOC-Brigding-Header.h")!

    选择'Header File'项 将其命名为"SwiftAndOC-Brigding-Header.h"

    在该工程中找到该TARGET,在'Build Settings'中找到'Objective-C Bridging Header'项!并输入“${SRCROOT}/MacSleepWake/SwiftAndOC-Brigding-Header.h”——创建好桥接关系

    找到'Objective-C Bridging Header'项 输入“${SRCROOT}/MacSleepWake/SwiftAndOC-Brigding-Header.h”

    创建好桥接关系~


    创建好桥接关系之后,将该类(MacSleepWakeObject)引入桥接头文件("SwiftAndOC-Brigding-Header.h")中 — #import "MacSleepWakeObject.h"!就可以在Swift代码中使用该类(MacSleepWakeObject)的方法了:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Do any additional setup after loading the view.
        
        MacSleepWakeObject .preventSystemSleep()//防止系统休眠
        
        MacSleepWakeObject .oc_registerNotications()//OC-注册通知
        //DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 30.0) {//延时30s
        //MacSleepWakeObject .oc_removeNotifications()//OC-移除通知
        //}
    }
    






    以上便是关于“实现Mac端App的功能(a.睡眠和唤醒的通知、b.实现‘App防睡眠’)”的讨论~
    关于更多macOS系统状态相关讨论,请参考macOS系统的状态切换及其响应方法

    关于NSApp对应的App状态讨论,请参考NSApp — App状态及其通知










    goyohol's essay

    相关文章

      网友评论

        本文标题:Mac端App 睡眠和唤醒的通知、实现‘App防睡眠’

        本文链接:https://www.haomeiwen.com/subject/osccdctx.html