Recent

Author Topic: [Solved] How add login items (using SMAppService, macOS 13+)  (Read 951 times)

Hansaplast

  • Hero Member
  • *****
  • Posts: 711
  • Tweaking4All.com
    • Tweaking4All
[Solved] How add login items (using SMAppService, macOS 13+)
« on: March 18, 2025, 11:38:19 am »
Trying to work with the new SMAppService option to add my application to the Login-Items for an App Store test project and find myself in need for the support for the macOS 13 SDK (this new approach has been made available since macOS 13).


Does anyone know where I can find the appropriate files or how to build these myself?
So far I have only found the proper Free Pascal files for macOS 11 and wasn't able to find anything in this forum.
« Last Edit: March 29, 2025, 09:35:47 pm by Hansaplast »

Hansaplast

  • Hero Member
  • *****
  • Posts: 711
  • Tweaking4All.com
    • Tweaking4All
Re: How to get and use the macOS 13 API headers?
« Reply #1 on: March 20, 2025, 09:46:21 am »
I've tried several conversion tools including ObjCParser.
However, I'm not sure what to do with the result (an .inc file), not to mention that the code seems not entirely complete and the tool not supporting ObjC 2. Another tool, OctDroid, seems to do a good job for Delphi, but is of course not very usefull for Lazarus (please correct me if I'm wrong).


Does anyone know what tool was used for SDK 10?
Do I need to use ObjCParser for the entire SDK?

cdbc

  • Hero Member
  • *****
  • Posts: 2095
    • http://www.cdbc.dk
Re: How to get and use the macOS 13 API headers?
« Reply #2 on: March 20, 2025, 10:01:45 am »
Hi
Quote
OctDroid, seems to do a good job for Delphi, but is of course not very usefull for Lazarus
Hmmm... Why the h*ll not?!?
Regardless of which tool you might use, you still (always) have to have human supervision, with the process!
NO automated tool, that I know of, will perform perfect on everything you might throw at it...
So - If you have to do a couple of minor adjustments of the code, to go from 'Delphi' to 'Lazarus', what would it matter, as long as you get the job done?
Just my 2 cent's worth.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Hansaplast

  • Hero Member
  • *****
  • Posts: 711
  • Tweaking4All.com
    • Tweaking4All
Re: How to get and use the macOS 13 API headers?
« Reply #3 on: March 20, 2025, 10:41:57 am »
Thanks for replying Benny!


I'm sure you're right, but my knowledge is somewhat limited on the topic. Especially on the topic of Delphi 😞
Code looks very different than all the other includes/units I have seen.


Example (not expecting anyone to do the work for me);


Code: Pascal  [Select][+][-]
  1. unit Macapi.ServiceManagement;
  2.  
  3.  
  4. {$MODE Delphi}
  5. {$modeswitch objectivec1}
  6.  
  7.  
  8. interface
  9.  
  10.  
  11. uses
  12.   Macapi.ObjectiveC, Macapi.CoreFoundation, Macapi.CocoaTypes, Macapi.Foundation, Macapi.Security;
  13.  
  14.  
  15. const
  16.   { TODO : Macro probably use invalid symbol "kSMRightBlessPrivilegedHelper": }
  17.   (* kSMRightBlessPrivilegedHelper "com.apple.ServiceManagement.blesshelper" *)
  18.   { TODO : Macro probably use invalid symbol "kSMRightModifySystemDaemons": }
  19.   (* kSMRightModifySystemDaemons "com.apple.ServiceManagement.daemons.modify" *)
  20.   kSMErrorInternalFailure = 2;
  21.   kSMErrorInvalidSignature = 3;
  22.   kSMErrorAuthorizationFailure = 4;
  23.   kSMErrorToolNotValid = 5;
  24.   kSMErrorJobNotFound = 6;
  25.   kSMErrorServiceUnavailable = 7;
  26.   kSMErrorJobPlistNotFound = 8;
  27.   kSMErrorJobMustBeEnabled = 9;
  28.   kSMErrorInvalidPlist = 10;
  29.   kSMErrorLaunchDeniedByUser = 11;
  30.   kSMErrorAlreadyRegistered = 12;
  31.   SMAppServiceStatusNotRegistered = 0;
  32.   SMAppServiceStatusEnabled = 1;
  33.   SMAppServiceStatusRequiresApproval = 2;
  34.   SMAppServiceStatusNotFound = 3;
  35.  
  36.  
  37. type
  38.   SMAppService = interface;
  39.  
  40.  
  41.   SMAppServiceStatus = NSInteger;
  42.   TSMAppServiceBlockMethod1 = procedure(error: NSError) of object;
  43.  
  44.  
  45.   SMAppServiceClass = objcclass(NSObject)
  46.   SMAppServiceClass = interface(NSObjectClass)
  47.     ['{A4BDE3B3-3167-43B5-A5B3-4D441AFC9FC4}']
  48.     {class} function agentServiceWithPlistName(plistName: NSString): Pointer; cdecl;
  49.     {class} function daemonServiceWithPlistName(plistName: NSString): Pointer; cdecl;
  50.     {class} function loginItemServiceWithIdentifier(identifier: NSString): Pointer; cdecl;
  51.     {class} function mainAppService: SMAppService; cdecl;
  52.     {class} procedure openSystemSettingsLoginItems; cdecl;
  53.     {class} function statusForLegacyURL(url: NSURL): SMAppServiceStatus; cdecl;
  54.   end;
  55.  
  56.  
  57.   SMAppService = interface(NSObject)
  58.     ['{997656A2-2E6A-4BAE-B2F3-248CD99993AD}']
  59.     function registerAndReturnError(error: PPointer): Boolean; cdecl;
  60.     function status: SMAppServiceStatus; cdecl;
  61.     function unregisterAndReturnError(error: PPointer): Boolean; cdecl;
  62.     procedure unregisterWithCompletionHandler(handler: TSMAppServiceBlockMethod1); cdecl;
  63.   end;
  64.   TSMAppService = class(TOCGenericImport<SMAppServiceClass, SMAppService>) end;
  65.  
  66.  
  67. const
  68.   libServiceManagement = '/System/Library/Frameworks/ServiceManagement.framework/ServiceManagement';
  69.  
  70.  
  71. function SMLoginItemSetEnabled(identifier: CFStringRef; enabled: Boolean): Boolean; cdecl;
  72.   external libServiceManagement name _PU + 'SMLoginItemSetEnabled';
  73.  
  74.  
  75. function SMJobCopyDictionary(domain: CFStringRef; jobLabel: CFStringRef): CFDictionaryRef; cdecl;
  76.   external libServiceManagement name _PU + 'SMJobCopyDictionary';
  77.  
  78.  
  79. function SMCopyAllJobDictionaries(domain: CFStringRef): CFArrayRef; cdecl;
  80.   external libServiceManagement name _PU + 'SMCopyAllJobDictionaries';
  81.  
  82.  
  83. function SMJobSubmit(domain: CFStringRef; job: CFDictionaryRef; auth: AuthorizationRef; outError: PCFErrorRef): Boolean; cdecl;
  84.   external libServiceManagement name _PU + 'SMJobSubmit';
  85.  
  86.  
  87. function SMJobRemove(domain: CFStringRef; jobLabel: CFStringRef; auth: AuthorizationRef; wait: Boolean; outError: PCFErrorRef): Boolean; cdecl;
  88.   external libServiceManagement name _PU + 'SMJobRemove';
  89.  
  90.  
  91. function SMJobBless(domain: CFStringRef; executableLabel: CFStringRef; auth: AuthorizationRef; outError: PCFErrorRef): Boolean; cdecl;
  92.   external libServiceManagement name _PU + 'SMJobBless';
  93.  
  94.  
  95. implementation
  96.  
  97.  
  98. uses
  99.   System.SysUtils;
  100.  
  101.  
  102. var
  103.   ServiceManagementModule: THandle;
  104.  
  105.  
  106. initialization
  107.   ServiceManagementModule := LoadLibrary(libServiceManagement);
  108.  
  109.  
  110. finalization
  111.   if ServiceManagementModule <> 0 then
  112.     FreeLibrary(ServiceManagementModule);
  113.  
  114.  
  115. end.

cdbc

  • Hero Member
  • *****
  • Posts: 2095
    • http://www.cdbc.dk
Re: How to get and use the macOS 13 API headers?
« Reply #4 on: March 20, 2025, 12:02:29 pm »
Hi
Hmmm...
Ok, so first order of business, is to figure out if we(laz) have an equivalent /library/ to 'Delphi's 'Macapi'?!? If not we might have to create such a beast ourselves :(  But, humans made it for 'Delphi', so humans can create one for 'Lazarus'  8)
Is that library to be found anywhere?!? just to have a looksee of what it does...
The rest of the file, deals mostly with the interfaces used by Apple.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

cdbc

  • Hero Member
  • *****
  • Posts: 2095
    • http://www.cdbc.dk
Re: How to get and use the macOS 13 API headers?
« Reply #5 on: March 20, 2025, 12:11:25 pm »
Hi
Had a 'LookSee' at what google can find on 'Macapi'...
By the looks of it, you've got your work cut out for you  %)
Keep your spirit high mate =^
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Hansaplast

  • Hero Member
  • *****
  • Posts: 711
  • Tweaking4All.com
    • Tweaking4All
Re: How to get and use the macOS 13 API headers?
« Reply #6 on: March 20, 2025, 12:46:42 pm »
Thanks  ;)


Yeah it doesn't look "simple" and I gained an even deeper respect for those that did SDK 10.
Thank you for looking though, it is much appreciated.

Hansaplast

  • Hero Member
  • *****
  • Posts: 711
  • Tweaking4All.com
    • Tweaking4All
Re: How to get and use the macOS 13 API headers?
« Reply #7 on: March 24, 2025, 04:19:31 pm »

Got "Adding Login Items" with SMAppService to work thanks to some tips and suggestions by "The Eskimo" in the Apple Developer forum. This was the main reason (for now) to get access to the macOS SDK 13.


1) Created a unit to interact with SMAppService:

Code: Pascal  [Select][+][-]
  1. unit ServiceManagementAppService;
  2.  
  3.  
  4.  
  5.  
  6. {$mode objfpc}{$H+}
  7. {$modeswitch objectivec1}
  8. {$linkframework ServiceManagement}
  9.  
  10.  
  11. interface
  12.  
  13.  
  14. uses Classes, SysUtils, CocoaAll;
  15.  
  16.  
  17. const
  18.   SMAppServiceStatusNotRegistered       =0;
  19.   SMAppServiceStatusEnabled             =1;
  20.   SMAppServiceStatusRequiresApproval    =2;
  21.   SMAppServiceStatusNotFound            =3;
  22.  
  23.  
  24.   SmAppServiceStatusResult :
  25.     Array [0..3] of string =
  26.                             ('Not registered',
  27.                               'Enabled',
  28.                               'Requires Approval',
  29.                               'Not found' );  
  30. type
  31.   SMAppServiceStatus = NSInteger;
  32.  
  33. type
  34.   SMAppService = objcclass external (NSObject)
  35.   public
  36.     function  registerAndReturnError(error: NSErrorPtr): objcbool;  message 'registerAndReturnError:';
  37.     function  unregisterAndReturnError(error: NSErrorPtr): objcbool;  message 'unregisterAndReturnError:';
  38.     function  status:SMAppServiceStatus; message 'status';
  39.   end;
  40.  
  41.  
  42. implementation
  43.  
  44.  
  45. end.
  46.  


2) And in my main application (no helper tool needed - you can make these calls straight in your main app) for some random testing:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   appService: SMAppService;
  4.   StatusReturn : SMAppServiceStatus;
  5.   Registered:boolean;
  6. begin
  7.   try
  8.     // Create a service
  9.     appService := SMAppService.new;
  10.  
  11.  
  12.     // Get current status
  13.     StatusReturn := appService.status;
  14.     ShowMessage('Status: '+IntToStr(Integer(StatusReturn))+LineEnding+ SmAppServiceStatusResult[StatusReturn]);
  15.  
  16.  
  17.     // Resgister service
  18.     Registered := appService.registerAndReturnError(nil);
  19.     ShowMessage('Registering result: '+BoolToStr(Registered,'Success','Failed'));
  20.  
  21.  
  22.     // Get current status
  23.     StatusReturn := appService.status;
  24.     ShowMessage('Status: '+IntToStr(Integer(StatusReturn))+LineEnding+ SmAppServiceStatusResult[StatusReturn]);
  25.  
  26.  
  27.     // Resgister service
  28.     Registered := appService.unregisterAndReturnError(nil);
  29.     ShowMessage('Unregistering result: '+BoolToStr(Registered,'Success','Failed'));
  30.  
  31.  
  32.     // Get current status
  33.     StatusReturn := appService.status;
  34.     ShowMessage('Status: '+IntToStr(Integer(StatusReturn))+LineEnding+ SmAppServiceStatusResult[StatusReturn]);
  35.   except
  36.     Showmessage('fail');
  37.   end;
  38. end;
  39.  

Note:
- while testing it seemed I needed to sign the app bundle of my application first
- I haven't tested this yet in the App Store (I know that I need to make the user make this choice)
- Did set the compiler directive to "-WM13.0", not sure if that mattered.

I hope this is useful to someone and feel free to correct me if I goofed up somehow as this all remains new territory to me. 😊

Thanks again!

 

TinyPortal © 2005-2018