问题
ALL,
Does OSX sends any notification when the power cord is plugged/unplugged in the Mac laptop? Or plugging/unplugging the laptop from the docking station?
It does send something on shutdown/reboot/wake-up/etc, but I didn't find anything for that specific event.
Am I missing something? Or this is not available?
TIA!
回答1:
There are no high-level notifications, but the IOPowerSources framework can post a message to your run loop whenever the power state changes.
My project has multiple PowerCondition
objects that monitor various aspects of the current power (A/C vs. Battery, how much battery is left, and so on).
Here's a fragment of the PowerCondition
class that shows how to observe power source change events via the run loop and turn that into a notification that multiple objects can observe (this is fairly old Obj-C):
#define kPowerConditionChangedNotification @"PowerConditionChanged"
static NSUInteger PowerChangeListenerCount = 0;
static CFRunLoopSourceRef PowerChangeSource = NULL;
static void PowerChangeCallback(void *context)
{
// Called by CFRunLoopSourceRef when something changes
// Post a notification so that all PowerCondition observers can reevaluate
[[NSNotificationCenter defaultCenter] postNotificationName:kPowerConditionChangedNotification object:nil];
}
@interface PowerCondition
{
BOOL listening;
//...
}
- (void)powerStateDidChangeNotification:(NSNotification*)notification;
@end
// ...
@implementation PowerCondition
- (void)startMonitoringCondition
{
if (!listening)
{
// Observe the power condition change notification
DebugLogger(@"condition '%@'",[self description]);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(powerStateDidChangeNotification:)
name:kPowerConditionChangedNotification
object:nil];
if (PowerChangeListenerCount++==0)
{
// This is the first observer: create and install the run loop source that will fire the notification
BetaAssert(PowerChangeSource==NULL,@"zero PowerChangeListenerCount, but PowerChangeSource!=NULL");
PowerChangeSource = IOPSNotificationCreateRunLoopSource(PowerChangeCallback,NULL);
CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop],PowerChangeSource,kCFRunLoopCommonModes);
DebugLoggerMessage(@"installed PowerChangeSource(PowerChangeCallback) in run loop");
}
listening = YES;
previousTestState = -1; // neither YES nor NO
}
}
- (void)stopMonitoringCondition
{
if (listening)
{
// Stop observing power condition change notifications
PowerLogger(@"condition '%@'",[self description]);
[[NSNotificationCenter defaultCenter] removeObserver:self];
BetaAssert(PowerChangeListenerCount!=0,@"PowerChangeListenerCount==0");
if (--PowerChangeListenerCount==0)
{
// This was the last power change observer: remove the run loop source the fires the notifications
BetaAssertNotNil(PowerChangeSource);
CFRunLoopRemoveSource([[NSRunLoop mainRunLoop] getCFRunLoop],PowerChangeSource,kCFRunLoopCommonModes);
CFRelease(PowerChangeSource);
PowerChangeSource = NULL;
DebugLoggerMessage(@"removed PowerChangeSource(PowerChangeCallback) from run loop");
}
listening = NO;
}
}
- (void)powerStateDidChangeNotification:(NSNotification*)notification
{
// Evaluate power state here
BOOL battery = NO; // assume unlimited/external power
double capacityRemaining = 1.0; // assume 100%
// First, determine if the system's active power source is AC or battery
CFTypeRef powerBlob = IOPSCopyPowerSourcesInfo();
CFArrayRef powerSourcesRef = IOPSCopyPowerSourcesList(powerBlob);
CFIndex count = CFArrayGetCount(powerSourcesRef);
if (count!=0)
{
// There's precious little explination what the meaning of the different power sources
// are or why there would be more than one. As far as I can tell, everything can be
// determined by obtaining the first (and probably only) power source description.
NSDictionary* powerInfo = (__bridge id)IOPSGetPowerSourceDescription(powerBlob,CFArrayGetValueAtIndex(powerSourcesRef,0));
if (![powerInfo[@kIOPSPowerSourceStateKey] isEqualToString:@kIOPSACPowerValue])
{
// Power source is not AC (must be battery or UPS)
battery = YES;
// Calculate the remaining capacity, as a fraction
NSNumber* capacityValue = powerInfo[@kIOPSCurrentCapacityKey];
NSNumber* maxValue = powerInfo[@kIOPSMaxCapacityKey];
if (capacityValue!=nil && maxValue!=nil)
capacityRemaining = [capacityValue doubleValue]/[maxValue doubleValue];
DebugLogger(@"power source is '%@', battery=%d, capacity=%@, max=%@, remaining=%f%%",
powerInfo[@kIOPSPowerSourceStateKey],
(int)battery,
capacityValue,maxValue,capacityRemaining*100);
}
}
// ...
}
Note that the callback is installed on the main run loop, so the notification will always be posted on the main thread.
来源:https://stackoverflow.com/questions/57788386/receive-notification-for-power-cord-on-off-in-osx-cocoa-for-the-laptop