Application backgrounding in Xamarin.Mac

2020-07-18 09:12发布

问题:

How do I achieve Application backgrounding in Xamarin.Mac. I want something that work similar as android services:

Android Services - A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface. Another application component can start a service, and it continues to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service can handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background. ~Android.com

Thanks in Advance.

回答1:

The proper way is to install your application as a LaunchAgent (instance-per-user) or a LaunchDaemon (instance-per-machine) using launchd, and the 'application type' setting (within "Xamarin Studio" or "Visual Studio for Mac" project options dialog) should be set to "Executable" instead of "Executable with a UI" (or similar.)

As a "LaunchAgent" you have the option of interacting with the desktop, and your code runs under the context of each logged in user instead of a system process account. You will not see a tile in the 'dock bar' (unless you allocate an NSApp), and you only see a 'status menu bar' if you explicitly call a Mac API to make it happen. Additionally, launchd will periodically check for and launch your process, ensuring that it is always running.) There is no requirement that you use any Cocoa/Mac APIs to implement an agent/daemon, you could run any console app under launchd and the above would still remain true.

Integration with launchd is non-trivial, but well documented for the macOS platform, and it applies equally to Xamarin.Mac-developed applications as it does any other platform/tool-chain (Java, C++, Obj-C, SWift, ...), if I had to guess learning how to use launchd is a 2-4 hour investment for most devs.

Because Xamarin.Mac does not itself have explicit support for launchd (and IMO should not) you will also be tasked with calling launchctl yourself. As a seasoned .NET developer I find that wrapping all of the 'launchctl ugliness' inside an "installer class" works well (then you only need to run installutil to install/uninstall your agent/service/application.) These installer classes can also be implemented to work on Windows and Linux, meaning cross-platform installs only ever require the use of installutil.

Separately, you can set particular properties in your app bundle Info.plist, but this is not necessary. However, most will find editing the existing plist easier than integrating with launchd. It's worth noting that one behavioral difference is that editing the plist to include either LSBackgroundOnly or LSUIElement doesn't guarantee your application is running, but using launchctl will.

HTH

References

  • Creating Launch Daemons and Agents Article on Apple.com
  • How to Create a Background Running Cocoa Application on StackOverflow.com
  • launchd Article on Wikipedia.org
  • launchctl Manual Page on Apple.com
  • LSBackgroundOnly Reference on Apple.com
  • LSUIElement Reference on Apple.com
  • installutil Reference on Microsoft.com (applies to Mono/Xamarin Linux/Mac platforms as well, though Windows uses its own 'Service Control Manager (SCM)' APIs instead of launchctl.)