MacOS Swift: how to correctly add an application as an input element

I spent about one day (maybe a little more) trying to add my application to the login element in the order in which it starts when macOS starts (user login).

So, following these steps, I did:

  • Add a new project inside my main project, which I called Launcher
  • I use Automatic Signing (as the version of my Xcode) is different enter image description here

  • In the section "Project Settings"> "Features" I switched to "Sandbox" in the "ON" position.

  • In the build phases, I added the following: enter image description here

  • My launcher has Skip Install = YES enter image description here

  • Launcher ( Swift, )

      - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
    {
        // Insert code here to initialize your application
    
        NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents];
        pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 4)];
        NSString *path = [NSString pathWithComponents:pathComponents];
        [[NSWorkspace sharedWorkspace] launchApplication:path];
        [NSApp terminate:nil];
    } 
    
  • , ,

  if(!SMLoginItemSetEnabled("click.remotely.Remotely-Click-Server-Launcher"
 as CFString, Bool(checkboxButton.state as NSNumber) ) ) {
            let alert: NSAlert = NSAlert()
            alert.messageText = "Remotely.Click Server - Error";
            alert.informativeText = "Application couldn't be added as 
        Login Item to macOS System Preferences > Users & Groups.";
            alert.alertStyle = NSAlertStyle.warning;
            alert.addButton(withTitle:"OK");
            alert.runModal();
   }
  1. , :

enter image description here

, , . " Mac App Store Deployment" - , /Applications/, . " ", " ", "MacOS App" , , .

  1. "", (Launcher program). , , Launcher . ( ), ( ) . , , Launcher , Launcher . , /Applications/Main.app/Contents/Library/LoginItems/Launcher.app , Launcher Main () ( ).

  2. , ?

, kLSSharedFileListSessionLoginItems

, , - System Preferences this   .

enter image description here

!

  • Swift ( /, , Objective-C). - :

     class LoginItemsList : NSObject {
    
    let loginItemsList : LSSharedFileList = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue();
    
    
    
    func addLoginItem(_ path: CFURL) -> Bool {
    
        if(getLoginItem(path) != nil) {
            print("Login Item has already been added to the list."); 
            return true;
        }
    
        var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
        print("Path adding to Login Item list is: ", path);
    
        // add new Login Item at the end of Login Items list
        if let loginItem = LSSharedFileListInsertItemURL(loginItemsList,
                                                          getLastLoginItemInList(),
                                                          nil, nil,
                                                          path,
                                                          nil, nil) {
            print("Added login item is: ", loginItem);
            return true;
        }
    
        return false;
    }
    
    
    func removeLoginItem(_ path: CFURL) -> Bool {
    
        // remove Login Item from the Login Items list 
        if let oldLoginItem = getLoginItem(path) {
            print("Old login item is: ", oldLoginItem);
            if(LSSharedFileListItemRemove(loginItemsList, oldLoginItem) == noErr) {
                return true;
            }
            return false;
        }
        print("Login Item for given path not found in the list."); 
        return true;
    }
    
    
    func getLoginItem(_ path : CFURL) -> LSSharedFileListItem! {
    
        var path : CFURL = CFURLCreateWithString(nil, "file:///Applications/Safari.app" as CFString, nil);
    
    
        // Copy all login items in the list
        let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue();
    
        var foundLoginItem : LSSharedFileListItem?;
        var nextItemUrl : Unmanaged<CFURL>?;
    
        // Iterate through login items to find one for given path
        print("App URL: ", path);
        for var i in (0..<loginItems.count)  // CFArrayGetCount(loginItems)
        {
    
            var nextLoginItem : LSSharedFileListItem = loginItems.object(at: i) as! LSSharedFileListItem; // CFArrayGetValueAtIndex(loginItems, i).;
    
    
            if(LSSharedFileListItemResolve(nextLoginItem, 0, &nextItemUrl, nil) == noErr) {
    
    
    
                print("Next login item URL: ", nextItemUrl!.takeUnretainedValue());
                // compare searched item URL passed in argument with next item URL
                if(nextItemUrl!.takeRetainedValue() == path) {
                    foundLoginItem = nextLoginItem;
                }
            }
        }
    
        return foundLoginItem;
    }
    
    func getLastLoginItemInList() -> LSSharedFileListItem! {
    
        // Copy all login items in the list
        let loginItems : NSArray = LSSharedFileListCopySnapshot(loginItemsList, nil).takeRetainedValue() as NSArray;
        if(loginItems.count > 0) {
            let lastLoginItem = loginItems.lastObject as! LSSharedFileListItem;
    
            print("Last login item is: ", lastLoginItem);
            return lastLoginItem
        }
    
        return kLSSharedFileListItemBeforeFirst.takeRetainedValue();
    }
    
    func isLoginItemInList(_ path : CFURL) -> Bool {
    
        if(getLoginItem(path) != nil) {
            return true;
        }
    
        return false;
    }
    
    static func appPath() -> CFURL {
    
        return NSURL.fileURL(withPath: Bundle.main.bundlePath) as CFURL;
    }
    
     }
    
  • , / ,

      let loginItemsList = LoginItemsList();
    
        if( checkboxButton.state == 0) {
            if(!loginItemsList.removeLoginItem(LoginItemsList.appPath())) {
                print("Error while removing Login Item from the list.");
            }
        } else {
            if(!loginItemsList.addLoginItem(LoginItemsList.appPath())) {
                print("Error while adding Login Item to the list.");
            }
        }
    
  • ( Xcode Play) /Applications, , .

  • . , Inserting Login Item nil.

enter image description here

, ( stackoverflow) Objective-C ( Unix < > Swift) .m .h Bridging-Header.h, :

- (void)enableLoginItemWithURL:(NSURL *)itemURL
{
    LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);

    if (loginListRef) {
        // Insert the item at the bottom of Login Items list.
        LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef,
                                                                             kLSSharedFileListItemLast,
                                                                             NULL,
                                                                             NULL,
                                                                             (__bridge CFURLRef) itemURL,
                                                                             NULL,
                                                                             NULL);
        if (loginItemRef) {
            CFRelease(loginItemRef);
        }
        CFRelease(loginListRef);
    }
}

( ) - . , LSSharedFileListInsertItemURL nil, > > .

, , ?

1

, ( Launcher ) iMac (MacOS Sierra XCode 8.3), , , , , , - Xcode ( , - ) MacBook Air, , OS X El Capitan 10.11.5 Xcode 8.0.

, : https://youtu.be/6fnLzkh5Rbs https://www.youtube.com/watch?v=sUE7Estju0U

iMac, nil LSSharedFileListInsertItemURL. , .

, : https://youtu.be/S_7ctQLkIuA

2

MacOS Sierra 10.12.5 El Capitan 10.11.5 Xcode 8.3.2 Xcode 8.0.0 > > ! LSSharedFileListInsertItemURL Sandboxing ! : https://youtu.be/UvDkby0t_WI

+4
3

ServiceManagement.framework, () > > . . UPDATE 1 UPDATE 2.

0

. . ; LSSharedFileListItemRef, , , , ServiceManagement.

, -:

:

, , , .

0

ServiceManagement , Xcode DerivedData . , . ~/Library/Developer/Xcode/DerivedData , .

0

Source: https://habr.com/ru/post/1677370/


All Articles