Вызов метода каждый раз, когда приложение запускается в swift 5 mac - PullRequest
0 голосов
/ 16 июня 2019

Я пытаюсь создавать и добавлять наблюдателя каждый раз, когда приложение запускается на Mac в Swift 5. Я успешно сделал это с pyobjc, и он работает нормально, однако я сдался, потому что слишком сложно конвертировать NSFileManagerметоды получения текущего пользователя, вошедшего в систему, так как инструмент запускается с правами root через LaunchDaemon.

Я уже пытался преобразовать код Python Objective C в Swift, но мне не хватает опыта.Я пробовал следующие учебные пособия: http://cocoaapi.hatenablog.com/entry/AppKit/NSWorkspace/NSWorkspaceWillLaunchApplicationNotification и NSNotificationCenter addObserver в Swift .

//
//  main.swift
//  AppBlocker
//
//  Created by jayke on 6/16/19.
//  Copyright © 2019 Jayke Peters. All rights reserved.
//

import Foundation
import AppKit

// Custom Notification Center Object
let nc = NSWorkspace.shared.notificationCenter

func notifyNSWorkspaceWillLaunchApplicationNotification(notify:NSNotification) {

    let bundleID : String = (notify.userInfo! as Dictionary)["NSApplicationBundleIdentifier"]! as! String
    NSLog("Bundle ID = %@",bundleID)

    let appName : String = (notify.userInfo! as Dictionary)["NSApplicationName"]! as! String
    NSLog("application name = %@",appName)

    let appPath : String = (notify.userInfo! as Dictionary)["NSApplicationPath"]! as! String
    NSLog("application path = %@",appPath)

    let appProcessID : NSNumber = (notify.userInfo! as Dictionary)["NSApplicationProcessIdentifier"]! as! NSNumber
    NSLog("process id = %d",appProcessID.intValue)

    let runningApp : NSRunningApplication = (notify.userInfo! as Dictionary)["NSWorkspaceApplicationKey"]! as! NSRunningApplication
    NSLog("runningApp = %@",runningApp.description)
    NSLog("runningApp = %@",runningApp.launchDate!.description)
}

nc.addObserver(forName: application, object: <#T##Any?#>, queue: <#T##OperationQueue?#>, using: <#T##(Notification) -> Void#>)

// Keep the application running
//CFRunLoopRun()

Код Python (существует и работает)

#!/usr/bin/python
print("Status: Starting AppBlocker")
import Foundation
from AppKit import *
from PyObjCTools import AppHelper
import signal
import re
import os
import sys
import shutil
import json
import threading
print("Status: AppBlocker Ready")

### CONFIG FILE LOCATION ###
config = "/.AppBlocker.json"
############################

def combineBundleIdentifiers(BundleIdentifiers):
    return "(" + ")|(".join(BundleIdentifiers.keys()) + ")"

def loadConfig():
    global blockedBundleIdentifiers, blockedBundleIdentifiersCombined
    try:
        blockedBundleIdentifiers = json.load(open(config))
    except IOError:
        print("Error: Could not open config file {}".format(config))
        exit(1)
    except ValueError:
        print("Error: Invalid JSON")
        exit(1)
    blockedBundleIdentifiersCombined = combineBundleIdentifiers(blockedBundleIdentifiers)

def refreshConfig():
    global blockedBundleIdentifiers, blockedBundleIdentifiersCombined
    _blockedBundleIdentifiers = blockedBundleIdentifiers.copy()
    threading.Timer(15, refreshConfig).start()
    try:
        blockedBundleIdentifiers = json.load(open(config))
    except IOError:
        print("Error: Code 5")
    except ValueError:
        print("Error: Invalid JSON Config, using previous config instead")
    if _blockedBundleIdentifiers != blockedBundleIdentifiers:
        print("Status: Config Changed")
        blockedBundleIdentifiersCombined = combineBundleIdentifiers(blockedBundleIdentifiers)

## Match Regex Identifier Options
def matchIdentifier(dictionary, substr):
    result = {}
    for key in dictionary.keys():
        if re.match(key, substr):
            result = dictionary[key]
            break
    return result

## Defaults
deleteBlockedApplication = False

# Whether the user should be alerted that the launched applicaion was blocked
alertUser = False

# Message displayed to the user when application is blocked
alertMessage = "The application \"{appname}\" has been blocked by IT"
alertInformativeText = "Contact your administrator for more information"

# Use a custom Icon for the alert. If none is defined here, the Python rocketship will be shown.
alertIconPath = "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Actions.icns"

# Define callback for notification
class AppLaunch(NSObject):
    def appLaunched_(self, notification):
        # Store the userInfo dict from the notification
        userInfo = notification.userInfo

        # Get the laucnhed applications bundle identifier
        bundleIdentifier = userInfo()['NSApplicationBundleIdentifier']

        # Check if launched app's bundle identifier matches any 'blockedBundleIdentifiers'
        matched = re.match(blockedBundleIdentifiersCombined, bundleIdentifier)
        if matched:     
            # Get PID of launchd app
            pid = userInfo()['NSApplicationProcessIdentifier']

            # Quit launched app
            try:
                os.kill(pid, signal.SIGKILL)
            except OSError:
                print("Error: Could not kill process " + str(pid))

            ## OPTIONS
            try:
                # Verbatim Identifier
                options = blockedBundleIdentifiers[bundleIdentifier]
            except:
                # Regex Identifier
                options = matchIdentifier(blockedBundleIdentifiers, matched.group())

            # Get path of launched app
            path = userInfo()['NSApplicationPath']

            if 'deleteBlockedApplication' in options:
                if options['deleteBlockedApplication']:
                    try:
                        shutil.rmtree(path)
                    except OSError, e:
                        print("Error: %s - %s." % (e.filename,e.strerror))

            # Alert user
            if 'alertUser' in options:
                if options['alertUser']:
                    if 'alertMessage' in options:
                        alert(options['alertMessage'], alertInformativeText, ["OK"])
            else:
                alert(alertMessage.format(appname=userInfo()['NSApplicationName']), alertInformativeText, ["OK"])

# Define alert class
class Alert(object):

    def __init__(self, messageText):
        super(Alert, self).__init__()
        self.messageText = messageText
        self.informativeText = ""
        self.buttons = []

    def displayAlert(self):
        alert = NSAlert.alloc().init()
        alert.setMessageText_(self.messageText)
        alert.setInformativeText_(self.informativeText)
        alert.setAlertStyle_(NSInformationalAlertStyle)
        for button in self.buttons:
            alert.addButtonWithTitle_(button)

        if os.path.exists(alertIconPath):
            icon = NSImage.alloc().initWithContentsOfFile_(alertIconPath)
            alert.setIcon_(icon)

        # Don't show the Python rocketship in the dock
        NSApp.setActivationPolicy_(1)

        NSApp.activateIgnoringOtherApps_(True)
        alert.runModal()

# Define an alert
def alert(message="Default Message", info_text="", buttons=["OK"]):    
    ap = Alert(message)
    ap.informativeText = info_text
    ap.buttons = buttons
    ap.displayAlert()

# Load the config
loadConfig()

# Start the refresher
refreshConfig()

# Register for 'NSWorkspaceDidLaunchApplicationNotification' notifications
nc = Foundation.NSWorkspace.sharedWorkspace().notificationCenter()
AppLaunch = AppLaunch.new()
nc.addObserver_selector_name_object_(AppLaunch, 'appLaunched:', 'NSWorkspaceWillLaunchApplicationNotification',None)

# Launch "app"
AppHelper.runConsoleEventLoop()
// // main.swift // AppBlocker // // Created by jayke on 6/16/19. // Copyright © 2019 Jayke Peters. All rights reserved. // import Foundation import AppKit // New Shared Notification Center Object let nc = NSWorkspace.shared.notificationCenter // Observer class class Observer { init() { nc.addObserver(self, selector: #selector(notificationDidTrigger), name: NSWorkspace.willLaunchApplicationNotification, object: nil) } // Blacklisted Process Names let blackListedProcessNames = ["com.apple.AppStore"] // Kill Process Method private func killProcess(_ processId: Int) { if let process = NSRunningApplication.init(processIdentifier: pid_t(processId)) { print("Killing \(processId): \(String(describing: process.localizedName!))") process.forceTerminate() } } // Application Launch Method @objc func notificationDidTrigger(notification: Notification) { // NOTIFICATION USER INFORMATION let userInfo = notification.userInfo if let processBundleIdentifier: String = notification.userInfo?["NSApplicationBundleIdentifier"] as? String { if let processId = userInfo?["NSApplicationProcessIdentifier"] as? Int { if (blackListedProcessNames.contains(processBundleIdentifier)) { killProcess(processId) } } } } } // Create a new observer let obj = Observer() // Keep the tool running CFRunLoopRun() ->
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...