How to make Xamarin.Mac app “Open at Login”?

2019-04-13 00:07发布

问题:

I have a Xamarin.Mac app that needs to open automatically at login. How do I have my application get this setting without having to manually click on it?

回答1:

I can give you a hint how to do it programmatically.

For this approach you need to make use of calls to native libraries via DllImport.

Following code will give you an idea how to proceed:

//needed library
const string DllName = "/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices";


static LSSharedFileList ()
{
    dllHandle = Dlfcn.dlopen (DllName, 0);

    kLSSharedFileListSessionLoginItems = Dlfcn.GetStringConstant (dllHandle, "kLSSharedFileListSessionLoginItems");
    kLSSharedFileListItemLast = Dlfcn.GetStringConstant (dllHandle, "kLSSharedFileListItemLast");
}


[DllImport(DllName)]
public static extern IntPtr LSSharedFileListCreate (
        IntPtr inAllocator,
        IntPtr inListType,
        IntPtr listOptions);

[DllImport(DllName, CharSet=CharSet.Unicode)]
public static extern void CFRelease (
    IntPtr cf
);


[DllImport(DllName)]
public extern static IntPtr LSSharedFileListInsertItemURL (
    IntPtr inList,
    IntPtr insertAfterThisItem,
    IntPtr inDisplayName,
    IntPtr inIconRef,
    IntPtr inURL,
    IntPtr inPropertiesToSet,
    IntPtr inPropertiesToClear);

And here the actual snippet:

public static void EnableLogInItem ()
{
    IntPtr pFileList = IntPtr.Zero;
    IntPtr pItem = IntPtr.Zero;
    try
    {
        pFileList = LSSharedFileListCreate (
             IntPtr.Zero,
             kLSSharedFileListSessionLoginItems,
             IntPtr.Zero);

        pItem = LSSharedFileListInsertItemURL (
            pFileList,
            kLSSharedFileListItemLast,
            IntPtr.Zero,
            IntPtr.Zero,
            NSBundle.MainBundle.BundleUrl.Handle,
            IntPtr.Zero,
            IntPtr.Zero);

    }
    finally
    {
        CFRelease (pItem);
        CFRelease (pFileList);
    }
}

Please keep in mind that it is not the whole solution, it is just a snippet to put an app in the login items list. Of course you have to handle errors, check for IntPtr.Zero after every call and so on, but this should give you an idea how it works.

Hope that helps!



回答2:

Since the LSSharedFileList library is not supported on Xamarin.Mac you have to create a dylib with Xcode and bind it in your Xamarin.Mac application.

1) Create a Dylib project on Xcode. Add This function:

-(BOOL)AddLoginItem:(NSString *) AppPath{
 // Your have to send this string as argument(i.e: on a textbox, write: /Applications/Calculator.app/)

 // Get Login Items
 LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);

        if (loginItems) {

            NSLog(@"[DEBUG]Your Application Path:%@",AppPath);

            // Covert String to CFURLRef (It adds "file://" to your itemUrl1)
            CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:(NSString*) AppPath];

            NSLog(@"[DEBUG] appUrl:%@", appUrl);

            // Now we add the requested Login Item
            LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);

            // Confirm that your path was correct and that you got a valid Login Item Reference
            NSLog(@"[DEBUG]Item:%@", itemRef);

            if (itemRef) CFRelease(itemRef);

            // Your item just got added to the user's Login Items List
            CFRelease(loginItems);
            return true;

        }
   return false;
}

2) Create a Cocoa project with an TextBox, a Push button and their Actions and Outlets controls in it. Use this link to help you with the C# bindings from a objective-c DLL.

3) On your Xamarin.Mac project, in MainWindow.cs, add the following code and make the necessary changes to fit on your code. Don't forget to add your .Net Assembly reference, created on the previous link and also your: using DLLloginItem; line.

 // Some variables
 private string TestItemName;
 private bool rem;

 // Button Click
    partial void AddItemButton (Foundation.NSObject sender) {

        LoginItemsDLL loginItem = new LoginItemsDLL();
        // Enter this string on your TextBox TxtName /Applications/Calculator.app/
        TestItemName = TxtName.StringValue;
        rem=loginItem.AddLoginItem(TestItemName);
        Console.WriteLine(rem);
    }

In order to get your application path entered, use another function that just receives the application name and returns its path into AddLoginItem argument. Hope it helps!