Python + OSX : interagir avec le centre de notifications OSX

Python + OSX : interagir avec le centre de notifications OSX

Dans cet article plutôt court, il sera abordé une passerelle logicielle peu connue mais néanmoins très utile que permet OSX. Mac OSX possède une fonctionnalité des plus intéressante lorsqu'il s'agit notifier à l'utilisateur qu'un évènement quelconque s'est produit. Le développeur peut tout à fait créer des notifications à afficher dans le Notification Center d'OSX directement au sein d'un programme en exploitant l'une des nombreuses classes du Framework Cocoa permettant de créer des évènements graphiques.

Un point rapide sur Cocoa

Le Framework Cocoa est le runtime dans lequel s'éxecute toute application développée en Objective-C/Swift ou autre langage pouvant exploiter les classes spécifiques de Cocoa. Sous Mac OS, à partir du moment où le développeur veut créer une application exploitant des fonctionnalités de Mac OS, il est nécessaire pour lui d'utiliser des composants logiciels du Framework.

Une des particularité de Cocoa est qu'il a été développé en Objective-C, ce qui rend toutes les instances de tous les objets du runtime visible du point de vue du développeur et de son code. Une des conséquences de cette particularité est que l'on peut dynamiquement, et ce au runtime, modifier/supprimer/ajouter des morceaux d'interfaces. L'autre conséquence est que l'on peut de fait créer des éléments du Framework à partir de n'importe quel langage de programmation: e.g Python.

Python

Python est un langage de programmation objet, multi-paradigme et multiplateformes. Il favorise la programmation impérative structurée, fonctionnelle et orientée objet. Il est doté d'un typage dynamique fort, d'une gestion automatique de la mémoire par Garbage-Collection et d'un système de gestion d'exceptions ; il est ainsi similaire à Perl, Ruby, Scheme, Smalltalk et Tcl.

Ici, Python est juste utilisé à titre d'exemple didactique pour sa rapidité de mise en oeuvre. La portabilité ici ne nous concerne que peu, puisqu'il s'agit d'interagir avec des entités logicielles présentes uniquement sous Mac OS.

Codons un peu!

Tout d'abord il est nécessaire d'importer les composants dont nous aurons besoin:

import Foundation
import objc
import AppKit
import sys

Ensuite de créer des variables permettant de récuperer les classes du Framework permettant de créer une notification et d'acceder au centre de notification:

NSUserNotification = objc.lookUpClass('NSUserNotification')
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')

Pour faire un peu propre, nous allons définir une méthode notify qui prend un certain nombre de paramètres title, subtitle, info_text, delay=0, sound=False, userInfo={} qui permettent de définir titre, texte, délai d'apparition etc.

def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}):
	notification = NSUserNotification.alloc().init()
	notification.setTitle_(title)
	notification.setSubtitle_(subtitle)
	notification.setInformativeText_(info_text)
	notification.setUserInfo_(userInfo)
    
	if sound:
			notification.setSoundName_("NSUserNotificationDefaultSoundName")
	notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(delay, Foundation.NSDate.date()))
	NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)

Les dernières instructions permettent de spécifier les timestamp et de placer la notification dans la file d'attente du centre de notifications.

Il ne reste plus ensuite qu'à appeler cette méthode
notify("Message", "Blablabla", "This message should appear instantly", sound=False)
dans notre code pour afficher la notification et/ou sa bannière ou pastille dans l'interface principale de Mac OS.

N'oubliez pas que Python est un langage dont la structure et les blocs d'instructions sont basés sur l'indentation. Garder cela en tête est utile pour s'éviter du debug inutile.

Source de l'exemple

import Foundation
import objc
import AppKit
import sys

NSUserNotification = objc.lookUpClass('NSUserNotification')
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')

def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}):
	notification = NSUserNotification.alloc().init()
	notification.setTitle_(title)
	notification.setSubtitle_(subtitle)
	notification.setInformativeText_(info_text)
	notification.setUserInfo_(userInfo)
	if sound:
		notification.setSoundName_("NSUserNotificationDefaultSoundName")
	
    notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(delay, Foundation.NSDate.date()))
	NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)


notify("Message", "BlaBlaBla", "This message should appear instantly", sound=False)

Cheers!