2016-02-11 18 views
9

Potrzebuję napisać funkcję, która doda moją aplikację do elementów startowych na OS X 10.11. To co znalazłem w tej chwili:Uruchamiaj aplikację Swift Cocoa przy starcie na 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); 
      } 
     } 
    } 
} 

Ale LSSharedFileListCreate, LSSharedFileListInsertItemURL, LSSharedFileListItemRemove, kLSSharedFileListItemBeforeFirst, LSSharedFileListItemCopyResolvedURL, LSSharedFileListCopySnapshot, kLSSharedFileListSessionLoginItems były przestarzałe w OS X 10.11. Jak to działa w najnowszej wersji Mac OS? Jak zmienić lub przepisać ten kod?

Odpowiedz

5

W Swift 3.0 wygląda tak:

W głównej AppDelegate aplikacji:

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) 
    } 
} 

W zgłoszeniu AppDelegate wyrzutnia:

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) 
} 

Ostatecznie w głównej aplikacji I dodaje interfejs użytkownika przełącznik. Użytkownik może wybrać aplikację przy logowaniu, czy nie. Wybór jest przechowywany w UserDefaults. W kontrolerze widoku:

@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") 
     } 
    } 

} 

Mam nadzieję, że to może pomóc komuś.

+0

Miła i naprawdę pomocna odpowiedź, nawet po tak długim czasie! –

+0

Gdzie zdefiniowano 'NCConstants.KILLME'? –

+0

W programie uruchamiającym ORAZ w aplikacji głównej. Możesz go zdefiniować w ten sposób: klasa NCConstants { // Powiadom stałą statyczne niech KILLME = Powiadomienie.Nazwa ("killme")} – Thomas

10

Musisz teraz użyć struktury zarządzania usługami. Tworzysz aplikację pomocniczą, którą dodajesz do pakietu aplikacji, a jej zadaniem jest uruchomienie kodu, aby uruchomić główną aplikację. Niektóre zasoby dla Ciebie:

+0

Odpowiedź nie jest związana z językiem swift, ale daje ogólny kierunek. – zxcat

+0

Twój samouczek jest fantastyczny. Próbowałem już teraz i wszystko działa zgodnie z opisem, z wyjątkiem drobnego faktu, że nie działa. Mam ten błąd na konsoli 'Nie można rozwiązać CFBundleIdentifier określony przez usługę', a następnie identyfikator mojego pliku pomocy, który mam potrójnie sprawdzony jest wpisany poprawnie. Jest to oczekiwane, ponieważ z mojego doświadczenia wynika, że ​​żaden pojedynczy interfejs API firmy Apple nie działa zgodnie z oczekiwaniami przy pierwszej próbie. – SpaceDog

+0

@SpaceDog Czy próbowałeś pobrać źródło z GitHub i wypróbować ten projekt? –

Powiązane problemy