Sign in Join
Wiki copytemporary

macOS User Notifications: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: macOS User Notifications

OldNewLine
1+*(macOS only)*
2+
3+> **Warning:** The NSUserNotification class was deprecated in macOS 10.14 (Mojave); the code still works in macOS 10.15 (Catalina); in macOS 11.0 (Big Sur) and in macOS 12 (Monterey), the notification daemon ignores the action and logs "error usernoted Denying message 3 from connection \<LegacyConnection identifier: com.company.project1 type: Application\>". The replacement appears to be the UserNotifications framework introduced in macOS 10.14. See below for Apple documentation.
4+
5+## User notification unit
6+
7+This is the user notification unit which can be used by an application to deliver notifications to the user:
8+
9+``` pascal
10+unit UserNotification;
11+
12+interface
13+
14+{$ifdef Darwin}
15+{$mode objfpc}{$H+}
16+{$modeswitch objectivec1}
17+{$linkframework Foundation}
18+
19+uses
20+ Classes,
21+ MacOSAll,
22+ CocoaUtils,
23+ CocoaAll;
24+
25+const
26+ NSUserNotificationActivationTypeNone = 0;
27+ NSUserNotificationActivationTypeContentsClicked = 1;
28+ NSUserNotificationActivationTypeActionButtonClicked = 2;
29+
30+type
31+ NSUserNotificationPtr = ^NSUserNotification;
32+ NSUserNotificationCenterPtr = ^NSUserNotificationCenter;
33+ NSUserNotificationCenterDelegateProtocolPtr = ^NSUserNotificationCenterDelegateProtocol;
34+
35+ NSUserNotificationActivationType = NSInteger;
36+ NSUserNotificationActivationTypePtr = ^NSUserNotificationActivationType;
37+
38+ NSUserNotification = objcclass external (NSObject)
39+ private
40+ _internal: id;
41+ public
42+ procedure setTitle(newValue: NSString); message 'setTitle:';
43+ function title: NSString; message 'title';
44+ procedure setSubtitle(newValue: NSString); message 'setSubtitle:';
45+ function subtitle: NSString; message 'subtitle';
46+ procedure setInformativeText(newValue: NSString); message 'setInformativeText:';
47+ function informativeText: NSString; message 'informativeText';
48+ procedure setActionButtonTitle(newValue: NSString); message 'setActionButtonTitle:';
49+ function actionButtonTitle: NSString; message 'actionButtonTitle';
50+ procedure setUserInfo(newValue: NSDictionary); message 'setUserInfo:';
51+ function userInfo: NSDictionary; message 'userInfo';
52+ procedure setDeliveryDate(newValue: NSDate); message 'setDeliveryDate:';
53+ function deliveryDate: NSDate; message 'deliveryDate';
54+ procedure setDeliveryTimeZone(newValue: NSTimeZone); message 'setDeliveryTimeZone:';
55+ function deliveryTimeZone: NSTimeZone; message 'deliveryTimeZone';
56+ procedure setDeliveryRepeatInterval(newValue: NSDateComponents); message 'setDeliveryRepeatInterval:';
57+ function deliveryRepeatInterval: NSDateComponents; message 'deliveryRepeatInterval';
58+ function actualDeliveryDate: NSDate; message 'actualDeliveryDate';
59+ function isPresented: boolean; message 'isPresented';
60+ function isRemote: boolean; message 'isRemote';
61+ procedure setSoundName(newValue: NSString); message 'setSoundName:';
62+ function soundName: NSString; message 'soundName';
63+ procedure setHasActionButton(newValue: boolean); message 'setHasActionButton:';
64+ function hasActionButton: boolean; message 'hasActionButton';
65+ function activationType: NSUserNotificationActivationType; message 'activationType';
66+ procedure setOtherButtonTitle(newValue: NSString); message 'setOtherButtonTitle:';
67+ function otherButtonTitle: NSString; message 'otherButtonTitle';
68+ end;
69+
70+ NSUserNotificationCenter = objcclass external (NSObject)
71+ private
72+ _internal: id;
73+ public
74+ class function defaultUserNotificationCenter: NSUserNotificationCenter; message 'defaultUserNotificationCenter';
75+ procedure setDelegate(newValue: NSObject); message 'setDelegate:';
76+ function delegate: NSUserNotificationCenterDelegateProtocol; message 'delegate';
77+ procedure setScheduledNotifications(newValue: NSArray); message 'setScheduledNotifications:';
78+ function scheduledNotifications: NSArray; message 'scheduledNotifications';
79+ procedure scheduleNotification (notification: NSUserNotification); message 'scheduleNotification:';
80+ procedure removeScheduledNotification (notification: NSUserNotification); message 'removeScheduledNotification:';
81+ function deliveredNotifications: NSArray; message 'deliveredNotifications';
82+ procedure deliverNotification (notification: NSUserNotification); message 'deliverNotification:';
83+ procedure removeDeliveredNotification (notification: NSUserNotification); message 'removeDeliveredNotification:';
84+ procedure removeAllDeliveredNotifications; message 'removeAllDeliveredNotifications';
85+ end;
86+
87+ NSUserNotificationCenterDelegateProtocol = objcprotocol external name 'NSUserNotificationCenterDelegate' (NSObjectProtocol)
88+ optional
89+ procedure userNotificationCenter_didDeliverNotification (center: NSUserNotificationCenter; notification: NSUserNotification); message 'userNotificationCenter:didDeliverNotification:';
90+ procedure userNotificationCenter_didActivateNotification (center: NSUserNotificationCenter; notification: NSUserNotification); message 'userNotificationCenter:didActivateNotification:';
91+ function userNotificationCenter_shouldPresentNotification (center: NSUserNotificationCenter; notification: NSUserNotification): boolean; message 'userNotificationCenter:shouldPresentNotification:';
92+ end;
93+
94+ NSUserNotificationCenterAlwaysShowDelegate = objcclass(NSObject)
95+ public
96+ function shouldPresentNotification ({%H-}center: NSUserNotificationCenter; {%H-}notification: NSUserNotification): boolean; message 'userNotificationCenter:shouldPresentNotification:';
97+ end;
98+
99+// Procedure to call - without sound
100+procedure DeliverUserNotification(const Title, Subtitle, Message: string);
101+
102+// Procedure to call - with sound
103+procedure DeliverUserNotification(const Title, Subtitle, Message, Sound: string);
104+
105+var
106+ NSUserNotificationDefaultSoundName: NSString { available in 10_8, NA }; cvar; external;
107+
108+{$endif}
109+
110+implementation
111+
112+{$ifdef Darwin}
113+
114+var
115+ UserNotificationCenterDelegate: NSUserNotificationCenterAlwaysShowDelegate;
116+
117+function NSUserNotificationCenterAlwaysShowDelegate.shouldPresentNotification (center: NSUserNotificationCenter; notification: NSUserNotification): boolean;
118+begin
119+ Result := True;
120+end;
121+
122+procedure DeliverUserNotification(const Title, Subtitle, Message: string);
123+begin
124+ DeliverUserNotification(Title, Subtitle, Message, CFStringToStr(CFStringRef(NSUserNotificationDefaultSoundName)));
125+end;
126+
127+procedure DeliverUserNotification(const Title, Subtitle, Message, Sound: string);
128+var
129+ Notification: NSUserNotification;
130+ TmpNSStr: NSString;
131+
132+begin
133+ Notification := NSUserNotification.alloc.init;
134+
135+ try
136+ TmpNSStr := NSString(CFStringCreateWithPascalString(kCFAllocatorDefault, Title, kCFStringEncodingUTF8));
137+
138+ try
139+ Notification.setTitle(TmpNSStr);
140+
141+ finally
142+ TmpNSStr.release;
143+ end;
144+
145+ TmpNSStr := NSString(CFStringCreateWithPascalString(kCFAllocatorDefault, Subtitle, kCFStringEncodingUTF8));
146+
147+ try
148+ Notification.setSubtitle(TmpNSStr);
149+
150+ finally
151+ TmpNSStr.release;
152+ end;
153+
154+ TmpNSStr := NSString(CFStringCreateWithPascalString(kCFAllocatorDefault, Message, kCFStringEncodingUTF8));
155+
156+ try
157+ Notification.setInformativeText(TmpNSStr);
158+
159+ finally
160+ TmpNSStr.release;
161+ end;
162+
163+ if Sound <> '' then
164+ begin
165+ TmpNSStr := NSString(CFStringCreateWithPascalString(kCFAllocatorDefault, Sound, kCFStringEncodingUTF8));
166+
167+ try
168+ Notification.setSoundName(TmpNSStr);
169+
170+ finally
171+ TmpNSStr.release;
172+ end;
173+ end;
174+
175+ NSUserNotificationCenter.defaultUserNotificationCenter.deliverNotification(Notification);
176+
177+ finally
178+ Notification.release;
179+ end;
180+end;
181+
182+initialization
183+ UserNotificationCenterDelegate := NSUserNotificationCenterAlwaysShowDelegate.alloc.init;
184+ NSUserNotificationCenter.defaultUserNotificationCenter.setDelegate(UserNotificationCenterDelegate);
185+
186+finalization
187+ NSUserNotificationCenter.defaultUserNotificationCenter.setDelegate(nil);
188+ UserNotificationCenterDelegate.release;
189+
190+{$endif}
191+
192+end.
193+```
194+
195+## How to use the unit
196+
197+You can deliver notifications to the user:
198+
199+- With the default notification sound, call: *procedure DeliverUserNotification(const Title, Subtitle, Message: string);*
200+
201+- With a custom notification sound, call: *procedure DeliverUserNotification(const Title, Subtitle, Message, Sound: string);*
202+
203+- With no notification sound, call: *procedure DeliverUserNotification(const Title, Subtitle, Message, Sound: string);* and pass an empty Sound string.
204+
205+### Examples
206+
207+``` pascal
208+...
209+
210+procedure TForm1.Button1Click(Sender: TObject);
211+begin
212+ DeliverUserNotification('Title Test', 'Subtitle Test', 'Message', ''); // No sound
213+end;
214+
215+...
216+
217+procedure TForm1.Button2Click(Sender: TObject);
218+begin
219+ DeliverUserNotification('Title Test', 'Subtitle Test', 'Message', 'Submarine'); // Custom sound from Sound Preferences
220+end;
221+
222+...
223+
224+procedure TForm1.Button3Click(Sender: TObject);
225+begin
226+ DeliverUserNotification('Title Test', 'Subtitle Test', 'Message'); // Default Notification Alert sound
227+end;
228+
229+...
230+```
231+
232+## Preferences \> Notifications
233+
234+Be aware that in this user-centric world that is macOS, the user has the ability to override many of your carefully crafted notification attributes via the Notifications Preference pane. This includes the ability to turn notifications from your application off completely by choosing "None" and unchecking all the checkboxes.
235+
236+![](/wiki-images/3/3a/MacOS_Prefs_Notifications.png)
237+
238+## External links
239+
240+- [Apple: NSUserNotification](https://developer.apple.com/documentation/foundation/nsusernotification) - deprecated in macOS 10.14 (Mojave).
241+- [Apple: UNUserNotificationCenter](https://developer.apple.com/documentation/usernotifications) - debuted in macOS 10.14 (Mojave).
242+
243+---
244+*From the Free Pascal wiki, page "macOS User Notifications", as it stood on 2021-10-28 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
245+Category: Audio
246+Category: Code Snippets
247+Category: Platform-sensitive development
248+Category: macOS

Back to history