disattivare badge su icona preferenze

Qui potrete scambiare pareri, consigli, suggerimenti di programmazione su Swift, Java, SQL, C++, Pascal, VB, Basic, etc...

Moderatore: ModiMaccanici

Germinara
Stato: Non connesso
Apprendista Maccanico
Apprendista Maccanico
Iscritto il: dom, 06 giu 2010 21:22
Messaggi: 33

Top

Oggetto del messaggio: disattivare badge su icona preferenze

Messaggio da Germinara »

Incuriosito dal una discussione sul forum di qualche giorno, ho approfondito l'argomento e dato che con i metodi forniti dal sistema operativo, non c'è modo di far sparire il numerino che compare su icona preferenze di sistema, ho provato a tentare di risolvere via software.

L'idea è questa:
Un applicazione che controlla quando cambia il file delle preferenze del sistema

Codice: Seleziona tutto

com.apple.systempreferences.plist
, controllo il valore della chiave

Codice: Seleziona tutto

AttentionPrefBundleIDs
e se contiene degli elementi li rimuovo, quindi aggiorno il file delle preferenze.
Si qui tutto ok, però l'icona del dock rimaneva con il badge sino a quando non forzavo un riavvio con killall Dock ... allora ho indagato ancora è ho cercato se c'era un messaggio di notifica e ho trovato questo...

Codice: Seleziona tutto

francescogerminara@FGMACBOOKPRO01 ~ % strings /System/Applications/System\ Preferences.app/Contents/PlugIns/SystemPreferencesDockTile.docktileplugin/Contents/MacOS/SystemPreferencesDockTile | grep "com.apple"
com.apple.systempreferences
com.apple.systempreferences.refreshdocktile
francescogerminara@FGMACBOOKPRO01 ~ % 
quindi dopo la modifica del file della preferenza, devo segnalare la notifica di

Codice: Seleziona tutto

com.apple.systempreferences.refreshdocktile
tramite l'applicazione.

Qui in sintesi le funzioni realizzate

Monitoraggio del cambio file delle preferenze

Codice: Seleziona tutto

let filewatcher = FileWatcher([NSString(string: "~/Library/Preferences/com.apple.dock.plist").expandingTildeInPath,
                                    NSString(string: "~/Library/Preferences/com.apple.systempreferences.plist").expandingTildeInPath]
Cambio preferenza e segnalo modifica al SO

Codice: Seleziona tutto

func forceUpdateAttentionPrefBundleIDs(_ path: String) -> Void {
    if(path.contains( "com.apple.systempreferences.plist")){
        timestamp.printTimestamp()
        var nsDictionary: NSMutableDictionary?
        nsDictionary = NSMutableDictionary(contentsOfFile: path)
        
        let AttentionPref : NSMutableDictionary? = nsDictionary?.value(forKey: "AttentionPrefBundleIDs") as? NSMutableDictionary
        if((AttentionPref?.count ?? 0) > 0){
            AttentionPref?.removeAllObjects()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
              
                print("Modifico AttentionPrefBundleIDs in 0")
            
                    nsDictionary!.write(toFile: path, atomically: false)
       
                // let nameNotification = "com.apple.dock.prefchanged"
                 let nameNotification = "com.apple.systempreferences.refreshdocktile"
                 CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),  CFNotificationName(nameNotification as CFString) , nil, nil, true)
                 print("---prefchanged notify---")

            }
        }
    }
}
non è perfetto, ma sembra funzionare...

Germinara
Stato: Non connesso
Apprendista Maccanico
Apprendista Maccanico
Iscritto il: dom, 06 giu 2010 21:22
Messaggi: 33

Top

Oggetto del messaggio: Re: disattivare badge su icona preferenze

Messaggio da Germinara »

Ciao, ho fatto questa piccola utility https://www.germinara.it/disco/nobadgegrazie.app.zip che una volta mandata in esecuzione, provvede a disattivare il numerico del badge su icona preferenze.

L'applicazione una volta lanciata, rimane in esecuzione sino a quando non si riavvia il mac o si termina da monitoraggio attività.

Se si vuole attivare l'applicazione al riavvio del mac sarà sufficiente inserirla nell'elenco delle applicazioni di avviare al login tramite preferenze login utente o creare un launch agent/deamon.

L'applicazione non è notarizzata, di conseguenza dopo il download occorre aprirla da menu contestuale Apri.

Qui il funzionamento in breve:

1) per resettare il badge resetta la preferenza AttentionPrefBundleIDs (AttentionPrefBundleIDs = 0)
2) dopo aver modificato la preferenza segnala al processo Dock che c'è una modifica tramite notifica com.apple.systempreferences.refreshdocktile
3) monitoraggio del cambio del file della preferenza com.apple.systempreferences.plist

Ogni qual volta cambia il file di preferenza, vengono eseguite le operazioni 1) e 2)

Per i più curiosi:
La notifica è stata individuata disassemblando il programma

Codice: Seleziona tutto

        File: /System/Applications/System Preferences.app/Contents/PlugIns/SystemPreferencesDockTile.docktileplugin/Contents/MacOS/SystemPreferencesDockTile
che è responsabile della visualizzazione del badge nel Dock

Qui le info trovate https://www.germinara.it/disco/infobadge.pdf

Qui il codice in swift dell'applicazione sviluppata.

Codice: Seleziona tutto

//CHiamata ogni volta che sento un cambiamento nel file di preferenza com.apple.systempreferences.plist
func forceUpdateAttentionPrefBundleIDs(_ path: String) -> Void {
    if(path.contains( "com.apple.systempreferences.plist")){
        //Modifico la preferenza AttentionPrefBundleIDs
        guard
          let userDefaults = UserDefaults(suiteName: "com.apple.systempreferences")
          else { exit(EXIT_FAILURE) }
        userDefaults.set("0", forKey: "AttentionPrefBundleIDs")
        userDefaults.synchronize()
        timestamp.printTimestamp("AttentionPrefBundleIDs modificato.")

        //Invio notifica al sistema in modo che il processo Dock effettui il refresh delle informazioni
        let nameNotification = "com.apple.systempreferences.refreshdocktile"
        CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),  CFNotificationName(nameNotification as CFString) , nil, nil, true)
        timestamp.printTimestamp("refreshdocktile inviato.")
    }
}

//Callback
func fgCallBack(_ fileWatcherEvent: FileWatcherEvent) -> Void{
    timestamp.printTimestamp("File preferenze cambiato: \(fileWatcherEvent.path)")
    forceUpdateAttentionPrefBundleIDs(fileWatcherEvent.path)
}

Codice: Seleziona tutto

func applicationDidFinishLaunching(_ aNotification: Notification) {
        print("nobadgegrazie v.1.00 by Francesco germinara -  www.germinara.it")
        //Registro per ricevere notifica refreshdocktile
        addAsObserver()
        //Resetto il contatore del badge
        resetBadge()
        //Attivo monitoraggio del file della preferenza
        let filewatcher = FileWatcher([NSString(string: "~/Library/Preferences/com.apple.systempreferences.plist").expandingTildeInPath]
            )
        //Funzione da chiamare al cambiamento di dati del file di preferenza
        filewatcher.callback = fgCallBack(_:)
        
        //Avvio monitoraggio
        filewatcher.start()

Codice: Seleziona tutto

//Reset della preferenza la prima volta che il programma si avvia
func resetBadge()
{
    guard
      let userDefaults = UserDefaults(suiteName: "com.apple.systempreferences")
      else { exit(EXIT_FAILURE) }
    userDefaults.set("0", forKey: "AttentionPrefBundleIDs")
    userDefaults.synchronize()
    let nameNotification = "com.apple.systempreferences.refreshdocktile"
    CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),  CFNotificationName(nameNotification as CFString) , nil, nil, true)
}

Codice: Seleziona tutto

func addAsObserver(){
    let nameNotification = "com.apple.systempreferences.refreshdocktile"
    let nc = DistributedNotificationCenter.default()
    let nnm = NSNotification.Name(nameNotification)
    nc.addObserver(forName: nnm, object: nil, queue: nil) { notification in
        print("ricevuto Notifica:" + notification.description)
    }

}

Codice: Seleziona tutto

//Callback
func fgCallBack(_ fileWatcherEvent: FileWatcherEvent) -> Void{
    timestamp.printTimestamp("File preferenze cambiato: \(fileWatcherEvent.path)")
    forceUpdateAttentionPrefBundleIDs(fileWatcherEvent.path)
}
Io l'ho provato sul mio mac con Catalina, ma dovrebbe funzionare anche con Big Sur e (forse) Monterey...
fg