2014-12-15 15 views
8

Vorrei sapere se esiste un metodo per riavviare la mia app a livello di programmazione. È un'app mac os e lavoro con Xcode 6 in swift.Riavviare l'applicazione a livello di programmazione

La procedura è semplice, in un dato momento voglio riavviare la mia app. Credo di aver bisogno di un semplice Helper, ma non ne sono sicuro.

+0

Si potrebbe trovare th it usa il wrapper Swift per le funzioni POSIX [exec *] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html) –

risposta

9

Sì, è necessario uno strumento di supporto. ecco la procedura:

  1. Crea un obiettivo "Strumento riga di comando" nel progetto. Ad esempio, chiamato "rilancio"

    rilancio/main.swift:

    import AppKit 
    
    // KVO helper 
    class Observer: NSObject { 
    
        let _callback:() -> Void 
    
        init(callback:() -> Void) { 
         _callback = callback 
        } 
    
        override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) { 
         _callback() 
        } 
    } 
    
    
    // main 
    autoreleasepool { 
    
        // the application pid 
        let parentPID = atoi(C_ARGV[1]) 
    
        // get the application instance 
        if let app = NSRunningApplication(processIdentifier: parentPID) { 
    
         // application URL 
         let bundleURL = app.bundleURL! 
    
         // terminate() and wait terminated. 
         let listener = Observer { CFRunLoopStop(CFRunLoopGetCurrent()) } 
         app.addObserver(listener, forKeyPath: "isTerminated", options: nil, context: nil) 
         app.terminate() 
         CFRunLoopRun() // wait KVO notification 
         app.removeObserver(listener, forKeyPath: "isTerminated", context: nil) 
    
         // relaunch 
         NSWorkspace.sharedWorkspace().launchApplicationAtURL(bundleURL, options: nil, configuration: [:], error: nil) 
        } 
    } 
    
  2. Aggiungi Products/relaunch binario di "copiare Bundle Risorse" nel target principale dell'applicazione.

  3. Aggiungi relaunch target a "Dipendenze di destinazione" nella destinazione principale dell'applicazione.

    screenshot

  4. Aggiungi relaunch funzione nella principale dell'applicazione.

    Ad esempio: NSApplication + Relaunch.swift:

    extension NSApplication { 
        func relaunch(sender: AnyObject?) { 
         let task = NSTask() 
         // helper tool path 
         task.launchPath = NSBundle.mainBundle().pathForResource("relaunch", ofType: nil)! 
         // self PID as a argument 
         task.arguments = [String(NSProcessInfo.processInfo().processIdentifier)] 
         task.launch() 
        } 
    } 
    

Poi, chiamata NSApplication.sharedApplication().relaunch(nil) come ti piace. il codice di

+0

Questo non funziona con Swift 2/3. Puoi aggiornarlo? – Matt

+0

@Matt Vedere la mia [risposta] (http: // StackOverflow.it/a/39591935/597020) –

+0

Non sono sicuro al 100%, ma non sono riuscito a terminare l'app nello strumento di riavvio con 'app.terminate()'. È stato negato dalla ** sandbox **. Output Console.app: 'AppleEvents/sandbox: restituisce errAEPrivilegeError/-10004 e nega l'invio di eventi aevt/quit dal processo ''/0x0-0x0, pid = 28376, perché non ha il diritto di inviare un AppleEvent a questo processo. Ho finito per chiudere l'applicazione nell'estensione NSApplication dopo aver avviato lo strumento di riavvio. 'NSApp.terminate (nil)' – Daniel

1

Soluzione Rintaro a Swift 2.

// the application pid 
let parentPID = atoi(C_ARGV[1]) 

a

// the application pid 
let parentPID = Int32(Process.arguments[1]) 

Si lavora per me.

3

Versione Swift 3, basata sul codice di Rintaro e sulla soluzione di Cenox Kang.
Vedi la risposta di Rintaro per le istruzioni.

rilancio/main.swift:

import AppKit 

// KVO helper 
class Observer: NSObject { 

    let _callback:() -> Void 

    init(callback: @escaping() -> Void) { 
     _callback = callback 
    } 

    override func observeValue(forKeyPath keyPath: String?, 
         of object: Any?, 
         change: [NSKeyValueChangeKey : Any]?, 
         context: UnsafeMutableRawPointer?) { 
     _callback() 
    } 
} 


// main 
autoreleasepool { 

    // the application pid 
    guard let parentPID = Int32(CommandLine.arguments[1]) else { 
     fatalError("Relaunch: parentPID == nil.") 
    } 

    // get the application instance 
    if let app = NSRunningApplication(processIdentifier: parentPID) { 

     // application URL 
     let bundleURL = app.bundleURL! 

     // terminate() and wait terminated. 
     let listener = Observer { CFRunLoopStop(CFRunLoopGetCurrent()) } 
     app.addObserver(listener, forKeyPath: "isTerminated", context: nil) 
     app.terminate() 
     CFRunLoopRun() // wait KVO notification 
     app.removeObserver(listener, forKeyPath: "isTerminated", context: nil) 

     // relaunch 
     do { 
      try NSWorkspace.shared().launchApplication(at: bundleURL, configuration: [:]) 
     } catch { 
      fatalError("Relaunch: NSWorkspace.shared().launchApplication failed.") 
     } 
    } 
} 

NSApplication + Relaunch.swift:

import AppKit 

extension NSApplication { 
    func relaunch(sender: AnyObject?) { 
     let task = Process() 
     // helper tool path 
     task.launchPath = Bundle.main.path(forResource: "relaunch", ofType: nil)! 
     // self PID as a argument 
     task.arguments = [String(ProcessInfo.processInfo.processIdentifier)] 
     task.launch() 
    } 
} 
+1

Non sono sicuro al 100%, ma non sono riuscito a terminare l'app nello strumento di riavvio con 'app.terminate()'. È stato negato dalla ** sandbox **. Output Console.app: 'AppleEvents/sandbox: restituisce errAEPrivilegeError/-10004 e nega l'invio di eventi aevt/quit dal processo ''/0x0-0x0, pid = 28376, perché non ha il diritto di inviare un AppleEvent a questo processo. Ho finito per chiudere l'applicazione nell'estensione NSApplication dopo aver avviato lo strumento di riavvio. 'NSApp.terminate (nil)' – Daniel

2

funzione swift4

@objc private func buttonClicked(_ sender: NSButton) { 
    if let path = Bundle.main.resourceURL?.deletingLastPathComponent().deletingLastPathComponent().absoluteString { 
     NSLog("restart \(path)") 
     _ = Process.launchedProcess(launchPath: "/usr/bin/open", arguments: [path]) 
     NSApp.terminate(self) 
    } 
} 
+0

Penso che dovresti spiegarti un po 'meglio! – IlGala

+1

Codice è chiaro, penso che nessuna spiegazione necessaria qui –

Problemi correlati