像Dropbox这样安装后如何使应用程序从登录时开始或添加到登录项? Xcode 11,Swift 5,MacOS 10.13+

问题描述

我正在尝试让我的应用程序在用户注销并重新登录或重启后自动启动。目的是无限期地将应用保留在那里,除非用户关闭,但是在重新启动时重新启动它。

我遵循了一些教程,并且已经阅读了线程,但是它们似乎都已经过时了。我正在3个不同的OS(包括10.13、10.14和10.15)上使用此应用程序。我似乎在10.15机器上有大多数问题。我无法弄清楚为什么该应用程序是否在登录时被命中或丢失,以及为什么有时没有登录

https://martiancraft.com/blog/2015/01/login-items/

https://theswiftdev.com/how-to-launch-a-macos-app-at-login/

我已经对应用程序进行了代码签名,启用了沙箱,但是也许由于我发现的教程和信息已经过时,所以我在代码之外缺少了一些东西。该应用程序仅供公司内部使用,因此,我不会提交给Apple。我打算使用我们的管理软件部署到计算机上,并已构建了一个.pkg文件,以将应用程序+启动器部署到应用程序文件夹中,并在安装后自动运行。

欢迎和赞赏任何帮助,清理,解释或建议。

主应用程序:

extension Notification.Name{
static let killLauncher = Notification.Name("killLauncher")
}

extension AppDelegate: NSApplicationDelegate{
func applicationDidFinishLaunching(_ aNotification: Notification) {
      // Insert code here to initialize your application

          //assign variables for launcherhelper
          let launcherappid = "Kinetic.KTGHelperLauncher"
          let runningApps = NSWorkspace.shared.runningApplications
          let isRunning = !runningApps.filter {$0.bundleIdentifier == launcherappid }.isEmpty
          //set launcher to login item
          SMLoginItemSetEnabled(launcherappid as CFString,true)
          //status check if running or not running
          if isRunning {
              distributedNotificationCenter.default().post(name: .killLauncher,object: Bundle.main.bundleIdentifier!)
          }
      
      
      
      //configure button to display button in assets
      if let button = statusItem.button {
          button.image = NSImage(named:NSImage.Name("kinetic_websitemain_red"))
          
      }
      //builds menu on start
      constructMenu()
  }
}

@NSApplicationMain
class AppDelegate: NSObject {


let statusItem = NsstatusBar.system.statusItem(withLength:NsstatusItem.squareLength)



func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
}


@objc func TakeScreenshot(_ sender: Any){
    
    //get path to user download folder
    let dirPath = FileManager().urls(for:.downloadsDirectory,in:.userDomainMask)[0]
     
    //create time stamp of when picture is taken
    func CreateTimeStamp() -> Int32
    {
        return Int32(Date().timeIntervalSince1970)
    }
    
    
    var displayCount: UInt32 = 0;
    var result = CGGetActivedisplayList(0,nil,&displayCount)
        if (result != CGError.success) {
            print("error: \(result)")
            return
        }
        let allocated = Int(displayCount)
        let activedisplays = UnsafeMutablePointer<CGDirectdisplayID>.allocate(capacity: allocated)
        result = CGGetActivedisplayList(displayCount,activedisplays,&displayCount)

        if (result != CGError.success) {
            print("error: \(result)")
            return
        }

        for i in 1...displayCount {
            let unixTimestamp = CreateTimeStamp()
            let fileUrl = dirPath.appendingPathComponent("\(unixTimestamp)" + "_" + "\(i)" + ".jpg",isDirectory:false)
            let screenShot:CGImage = CGdisplayCreateImage(activedisplays[Int(i-1)])!
            let bitmapRep = NSBitmapImageRep(cgImage: screenShot)
            let jpegData = bitmapRep.representation(using: NSBitmapImageRep.FileType.jpeg,properties: [:])!


            do {
                try jpegData.write(to: fileUrl,options: .atomic)
            }
            catch {print("error: \(error)")}
        }
    
}

@objc func kineticSelf(_ sender: Any){
    let kineticSelfUrl = URL(string: "/Library/Addigy/macmanage/MacManage.app")
    NSWorkspace.shared.openFile(kineticSelfUrl!.path)
    // NSWorkspace.shared.open(URL(fileURLWithPath: "/Library/Addigy/macmanage/MacManage.app"))
    
}


//function that opens kinetic helpdesk website
@objc func kineticHelpdesk(_ sender: Any){
    let kineticHelpdeskUrl = URL(string: "http://helpdesk.kinetictg.com")!
    NSWorkspace.shared.open(kineticHelpdeskUrl)
    
}
//function that takes user to teamviewer ktg site
@objc func kineticRemote(_ sender: Any){
    let kineticRemoteUrl = URL(string: "https://get.teamviewer.com/ktgsupport")!
    NSWorkspace.shared.open(kineticRemoteUrl)
    
}
//call kinetic
@objc func kineticHomepage(_ sender: Any){
    let url = URL(string: "https://kinetictg.com")!
    NSWorkspace.shared.open(url)
}


//function to build menu
func constructMenu(){
    let menu = NSMenu()
    
    
    
    //section for "Request Support"
    menu.addItem(NSMenuItem.separator())
    menu.addItem(NSMenuItem(title: "Request Support",action: nil,keyEquivalent:""))
        //support ticket
    menu.addItem(NSMenuItem(title: "Support Ticket",action:
        #selector(AppDelegate.kineticHelpdesk(_:)),keyEquivalent: ""))
        //remote support
    menu.addItem(NSMenuItem(title: "Remote Support",action:
         #selector(AppDelegate.kineticRemote(_:)),keyEquivalent: ""))
    
    //section for "Tools"
    menu.addItem(NSMenuItem.separator( ))
    menu.addItem(NSMenuItem(title: "Tools",keyEquivalent:""))
        //start agent installation audit
    menu.addItem(NSMenuItem(title: "Take Screenshot",action:
        #selector(AppDelegate.TakeScreenshot(_:)),keyEquivalent: ""))
        //open self service
    menu.addItem(NSMenuItem(title: "Open Self Service",action:
        #selector(AppDelegate.kineticSelf(_:)),keyEquivalent: ""))
    
    //Section for "Info"
    menu.addItem(NSMenuItem.separator( ))
    menu.addItem(NSMenuItem(title: "Info",keyEquivalent:""))
        //contact info
    menu.addItem(NSMenuItem(title: "Kinetic Homepage",action:
        #selector(AppDelegate.kineticHomepage(_:)),keyEquivalent: ""))
        //quit app
    menu.addItem(NSMenuItem(title: "Quit",action:
        #selector(NSApplication.terminate(_:)),keyEquivalent: "q"))
    
    statusItem.menu = menu
    
    
}
}

启动器应用程序

import Cocoa
//extension variable for launcher to kill launcher

extension Notification.Name {
static let killLauncher = Notification.Name("killLauncher")
}

@NSApplicationMain
class HelperAppDelegate: NSObject {

//terminate object
@objc func terminate(){
    NSApp.terminate(nil)
}

}

extension HelperAppDelegate: NSApplicationDelegate{

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Insert code here to initialize your application
 //main app identifier
    let mainAppIdentifier = "Kinetic.KTG-Helper"
    let runningApps = NSWorkspace.shared.runningApplications
    let isRunning = !runningApps.filter { $0.bundleIdentifier == mainAppIdentifier }.isEmpty
    //if app is running kill launcher entity and reset status of killlauncher
    if !isRunning {
        distributedNotificationCenter.default().addobserver(self,selector: #selector(self.terminate),name: .killLauncher,object: mainAppIdentifier)
        
        let path = Bundle.main.bundlePath as Nsstring
        var components = path.pathComponents
        components.removeLast(3)
        components.append("MacOS")
        components.append("KTG Helper")
        
        let newPath = Nsstring.path(withComponents: components)
        
        NSWorkspace.shared.launchApplication(newPath)
    }
    else{
        self.terminate()
    }
}

//func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
//}
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)