2016-02-11 29 views
9

Ho bisogno di scrivere una funzione che aggiunge la mia applicazione agli elementi di avvio su OS X 10.11. Questo è quello che ho trovato in questo momento:Avvia l'avvio di Swift Cocoa all'avvio su OS X 10.11

func applicationIsInStartUpItems() -> Bool { 
    return (itemReferencesInLoginItems().existingReference != nil) 
} 

func itemReferencesInLoginItems() -> (existingReference: LSSharedFileListItemRef?, lastReference: LSSharedFileListItemRef?) { 

    if let appUrl : NSURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) { 
     let loginItemsRef = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue() as LSSharedFileListRef? 
     if loginItemsRef != nil { 
      let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray 
      if(loginItems.count > 0) { 
       let lastItemRef: LSSharedFileListItemRef = loginItems.lastObject as! LSSharedFileListItemRef 
       for var i = 0; i < loginItems.count; ++i { 
        let currentItemRef: LSSharedFileListItemRef = loginItems.objectAtIndex(i) as! LSSharedFileListItemRef 
        if let itemURL = LSSharedFileListItemCopyResolvedURL(currentItemRef, 0, nil) { 
         if (itemURL.takeRetainedValue() as NSURL).isEqual(appUrl) { 
          return (currentItemRef, lastItemRef) 
         } 
        } 
       } 
       return (nil, lastItemRef) 
      } else { 
       let addatstart: LSSharedFileListItemRef = kLSSharedFileListItemBeforeFirst.takeRetainedValue() 
       return(nil,addatstart) 
      } 
     } 
    } 
    return (nil, nil) 
} 

func toggleLaunchAtStartup() { 
    let itemReferences = itemReferencesInLoginItems() 
    let shouldBeToggled = (itemReferences.existingReference == nil) 
    if let loginItemsRef = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue() as LSSharedFileListRef? { 
     if shouldBeToggled { 
      if let appUrl : CFURLRef = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) { 
       LSSharedFileListInsertItemURL(loginItemsRef, itemReferences.lastReference, nil, nil, appUrl, nil, nil) 
      } 
     } else { 
      if let itemRef = itemReferences.existingReference { 
       LSSharedFileListItemRemove(loginItemsRef,itemRef); 
      } 
     } 
    } 
} 

Ma LSSharedFileListCreate, LSSharedFileListInsertItemURL, LSSharedFileListItemRemove, kLSSharedFileListItemBeforeFirst, LSSharedFileListItemCopyResolvedURL, LSSharedFileListCopySnapshot, kLSSharedFileListSessionLoginItems stati deprecati in OS X 10.11. Come farlo funzionare sull'ultima versione di Mac OS? Come cambiare o riscrivere questo codice?

risposta

5

In Swift 3.0 sembra che questo:

Nella vostra AppDelegate principale:

func applicationDidFinishLaunching(_ aNotification: Notification) { 
    // Check if the launcher app is started 
    var startedAtLogin = false 
    for app in NSWorkspace.shared().runningApplications { 
     if app.bundleIdentifier == NCConstants.launcherApplicationIdentifier { 
      startedAtLogin = true 
     } 
    } 

    // If the app's started, post to the notification center to kill the launcher app 
    if startedAtLogin { 
     DistributedNotificationCenter.default().postNotificationName(NCConstants.KILLME, object: Bundle.main.bundleIdentifier, userInfo: nil, options: DistributedNotificationCenter.Options.deliverImmediately) 
    } 
} 

Nell'applicazione AppDelegate avvio:

func applicationDidFinishLaunching(_ aNotification: Notification) { 

    let mainAppIdentifier = "<main-app-bundle-id>" 
    let running = NSWorkspace.shared().runningApplications 
    var alreadyRunning = false 

    // loop through running apps - check if the Main application is running 
    for app in running { 
     if app.bundleIdentifier == mainAppIdentifier { 
      alreadyRunning = true 
      break 
     } 
    } 

    if !alreadyRunning { 
     // Register for the notification killme 
     DistributedNotificationCenter.default().addObserver(self, selector: #selector(self.terminate), name: NCConstants.KILLME, object: mainAppIdentifier) 

     // Get the path of the current app and navigate through them to find the Main Application 
     let path = Bundle.main.bundlePath as NSString 
     var components = path.pathComponents 
     components.removeLast(3) 
     components.append("MacOS") 
     components.append("<your-app-name>") 

     let newPath = NSString.path(withComponents: components) 

     // Launch the Main application 
     NSWorkspace.shared().launchApplication(newPath) 
    } 
    else { 
     // Main application is already running 
     self.terminate() 
    } 

} 

func terminate() { 
    print("Terminate application") 
    NSApp.terminate(nil) 
} 

Infine, nella domanda principale ho aggiunto un interfaccia utente con un interruttore. L'utente può scegliere di avviare l'app all'accesso o meno. La scelta è memorizzata in UserDefaults. Nel controller Vista:

@IBAction func toggleLaunchAtLogin(_ sender: Any) { 
    if toggleOpenAppLogin.selectedSegment == 0 { 
     if !SMLoginItemSetEnabled(NCConstants.launcherApplicationIdentifier as CFString, true) { 
      print("The login item was not successfull") 
      toggleOpenAppLogin.setSelected(true, forSegment: 1) 
     } 
     else { 
      UserDefaults.standard.set("true", forKey: "appLoginStart") 
     } 
    } 
    else { 
     if !SMLoginItemSetEnabled(NCConstants.launcherApplicationIdentifier as CFString, false) { 
      print("The login item was not successfull") 
      toggleOpenAppLogin.setSelected(true, forSegment: 0) 
     } 
     else { 
      UserDefaults.standard.set("false", forKey: "appLoginStart") 
     } 
    } 

} 

Spero che questo possa aiutare qualcuno.

+0

Bello e davvero di aiuto rispondere, anche dopo tanto tempo! –

+0

Dove è definito 'NCConstants.KILLME'? –

+0

Nell'applicazione di avvio AND l'applicazione principale. Puoi definirlo in questo modo: class NCConstants { // Notifica costante statico let KILLME = Notification.Name ("killme")} – Thomas

10

Ora è necessario utilizzare il framework Gestione servizi. Si crea un'applicazione di supporto che si aggiunge al pacchetto di applicazioni e il suo lavoro consiste nell'eseguire il codice per avviare l'applicazione principale. Alcune risorse per voi:

+0

La risposta non è relativa a Swift, ma dà la direzione generale – zxcat

+0

Il tuo tutorial è fantastico. L'ho provato ora e tutto funziona come descritto, tranne per un piccolo fatto che non funziona. Ho questo errore sulla console 'Impossibile risolvere CFBundleIdentifier specificato dal servizio' seguito dall'identificatore del mio file di aiuto che ho triplicato è stato digitato correttamente. Ciò è previsto perché nella mia esperienza non una singola API di Apple funziona come previsto al primo tentativo. – SpaceDog

+0

@SpaceDog Hai provato a prelevare il codice sorgente da GitHub e provare quel progetto? –