Our app has a network extension (as I've mentioned lots 😄). We do an upgrade by downloading the new package, stopping & removing all of our components except for the network extension, and then installing the new package, which then loads a LaunchAgent causing the containing app to run. (The only difference between a new install and upgrade is the old extension is left running, but not having anything to tell it what to do, just logs and continues.)
On some (but not all) upgrades... nothing ends up able to communicate via XPC with the Network Extension. My simplest cli program to talk to it gets
Could not create proxy: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named blah was invalidated: failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named bla was invalidated: failed at lookup with error 3 - No such process.}
Could not communicate with blah
Restarting the extension by doing a kill -9 doesn't fix it; neither does restarting the control daemon. The only solution we've come across so far is rebooting.
I filed FB11086599 about this, but has anyone thoughts about this?
XPC
RSS for tagXPC is a a low-level (libSystem) interprocess communication mechanism that is based on serialized property lists.
Posts under XPC tag
74 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have an XPC server running on macOS and want to perform comprehensive performance and load testing to evaluate its efficiency, responsiveness, and scalability. Specifically, I need to measure factors such as request latency, throughput, and how well it handles concurrent connections under different load conditions.
What are the best tools, frameworks, or methodologies for testing an XPC service? Additionally, are there any best practices for simulating real-world usage scenarios and identifying potential bottlenecks?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
Endpoint Security
Instruments
Performance
I have a basic setup following WWDC 2020 on Safari Web Extensions and another one on XPC. The video even mentions that one can use UserDefaults or XPC to communicate with the host app. Here is my setup.
macOS 15.2, Xcode 16.2
A macOS app (all targets sandboxed, with an app group) with 3 targets:
SwiftUI Hello World
web extension
XPC Service
The web extension itself works and can update UserDefaults, which can then be read by SwiftUI app - everything works by the book.
The app can communicate to the XPC service via NSXPCConnection - again, everything works fine.
The problem is that the web extension does not communicate with XPC, and this is what I need so that I can avoid using UserDefaults for larger and more complex payloads.
Web Ext handler code:
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
// Unpack the message from Safari Web Extension.
let item = context.inputItems[0] as? NSExtensionItem
let message = item?.userInfo?[SFExtensionMessageKey]
// Update the value in UserDefaults.
let defaults = UserDefaults(suiteName: "com.***.AppName.group")
let messageDictionary = message as? [String: String]
if messageDictionary?["message"] == "Word highlighted" {
var currentValue = defaults?.integer(forKey: "WordHighlightedCount") ?? 0
currentValue += 1
defaults?.set(currentValue, forKey: "WordHighlightedCount")
}
let response = NSExtensionItem()
response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
os_log(.default, "setting up XPC connection")
let xpcConnection = NSXPCConnection(serviceName: "com.***.AppName.AppName-XPC-Service")
xpcConnection.remoteObjectInterface = NSXPCInterface(with: AppName_XPC_ServiceProtocol.self)
xpcConnection.resume()
let service = xpcConnection.remoteObjectProxyWithErrorHandler { error in
os_log(.default, "Received error: %{public}@", error as CVarArg)
} as? AppName_XPC_ServiceProtocol
service?.performCalculation(firstNumber: 23, secondNumber: 19) { result in
NSLog("Result of calculation XPC is: \(result)")
os_log(.default, "Result of calculation XPC is: \(result)")
context.completeRequest(returningItems: [response], completionHandler: nil)
}
}
}
The error I'm getting:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.***.AppName.AppName-XPC-Service was invalidated: failed at lookup with error 3 - No such process."
What am I missing?
Hello, community,
I'm using an HTML editor in a .NET MAUI application running on macOS, and I'm encountering some unexpected behavior during text editing:
Double-click text selection disappears after approximately one second.
Styles randomly revert or are applied to the wrong text unexpectedly.
It appears to be related to macOS spell checking. When using editable elements (, or with contenteditable), the system enables spell checking by default.
During this, MAUI attempts to communicate with a system process:
com.apple.TextInput.rdt, which is not running, leading to repeated errors like:
Error Domain=NSCocoaErrorDomain Code=4099
"The connection to service named com.apple.TextInput.rdt was invalidated: failed at lookup with error 3 - No such process."
Question:
What is com.apple.TextInput.rdt, and why might it not be running?
Thank you for any help!
I have Authorisation Plugin which talks using XPC to my Launch Daemon to perform privileged actions.
I want to protect my XPC service narrowing it to be called from known trusted clients.
Now since I want authorisation plugin code which is from apple to call my service, I cannot use my own team id or app group here.
I am currently banking on following properties of client connection.
Apple Team ID : EQHXZ8M8AV
Bundle ID starting with com.apple.
Client signature verified By Apple.
This is what I have come up with.
func isClientTrusted(connection: NSXPCConnection) -> Bool {
let clientPID = connection.processIdentifier
logInfo("🔍 Checking XPC Client - PID: \(clientPID)")
var secCode: SecCode?
var secStaticCode: SecStaticCode?
let attributes = [kSecGuestAttributePid: clientPID] as NSDictionary
let status = SecCodeCopyGuestWithAttributes(nil, attributes, [], &secCode)
guard status == errSecSuccess, let code = secCode else {
logInfo("Failed to get SecCode for PID \(clientPID)")
return false
}
let staticStatus = SecCodeCopyStaticCode(code, [], &secStaticCode)
guard staticStatus == errSecSuccess, let staticCode = secStaticCode else {
logInfo("Failed to get SecStaticCode")
return false
}
var signingInfo: CFDictionary?
let signingStatus = SecCodeCopySigningInformation(staticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &signingInfo)
guard signingStatus == errSecSuccess, let info = signingInfo as? [String: Any] else {
logInfo("Failed to retrieve signing info")
return false
}
// Extract and Verify Team ID
if let teamID = info["teamid"] as? String {
logInfo("XPC Client Team ID: \(teamID)")
if teamID != "EQHXZ8M8AV" { // Apple's official Team ID
logInfo("Client is NOT signed by Apple")
return false
}
} else {
logInfo("Failed to retrieve Team ID")
return false
}
// Verify Bundle ID Starts with "com.apple."
if let bundleID = info["identifier"] as? String {
logInfo("XPC Client Bundle ID: \(bundleID)")
if !bundleID.hasPrefix("com.apple.") {
logInfo("Client is NOT an Apple system process")
return false
}
} else {
logInfo("Failed to retrieve Bundle Identifier")
return false
}
// Verify Apple Code Signature Trust
var trustRequirement: SecRequirement?
let trustStatus = SecRequirementCreateWithString("anchor apple" as CFString, [], &trustRequirement)
guard trustStatus == errSecSuccess, let trust = trustRequirement else {
logInfo("Failed to create trust requirement")
return false
}
let verifyStatus = SecStaticCodeCheckValidity(staticCode, [], trust)
if verifyStatus != errSecSuccess {
logInfo("Client's signature is NOT trusted by Apple")
return false
}
logInfo("Client is fully verified as Apple-trusted")
return true
}
Q: Just wanted community feedback, is this correct approach?
I have used C APIs to create a XPC server(mach service) as a launch daemon. I use dispatch_source_create () followed by dispatch_resume() to start the listener. I dont have any code for cleaning up memory.
I want to make sure that the XPC server is shutdown gracefully, without any memory leaks.
I know that launchd handles the cycle and the XPC framework takes care of XPC objects.
But do I need to do additional cleanup when the XPC listener is shutdown ?
Im using the low-level C xpc api <xpc/xpc.h> and i get this error when I run it: Underlying connection interrupted. I know this error stems from the call to xpc_session_send_message_with_reply_sync(session, message, &reply_err);. I have no previous experience with xpc or dispatch and I find the xpc docs very limited and I also found next to no code examples online. Can somebody take a look at my code and tell me what I did wrong and how to fix it? Thank you in advance.
Main code:
#include <stdio.h>
#include <xpc/xpc.h>
#include <dispatch/dispatch.h>
// the context passed to mainf()
struct context {
char* text;
xpc_session_t sess;
};
// This is for later implementation and the name is also rudimentary
void mainf(void* c) {
//char * text = ((struct context*)c)->text;
xpc_session_t session = ((struct context*)c)->sess;
dispatch_queue_t messageq = dispatch_queue_create("y.ddd.main",
DISPATCH_QUEUE_SERIAL);
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "test", "eeeee");
if (session == NULL) {
printf("Session is NULL\n");
exit(1);
}
__block xpc_rich_error_t reply_err = NULL;
__block xpc_object_t reply;
dispatch_sync(messageq, ^{
reply = xpc_session_send_message_with_reply_sync(session,
message,
&reply_err);
if (reply_err != NULL) printf("Reply Error: %s\n",
xpc_rich_error_copy_description(reply_err));
});
if (reply != NULL)
printf("Reply: %s\n", xpc_dictionary_get_string(reply, "test"));
else printf("Reply is NULL\n");
}
int main(int argc, char* argv[]) {
// Create seperate queue for mainf()
dispatch_queue_t mainq = dispatch_queue_create("y.ddd.main",
DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t xpcq = dispatch_queue_create("y.ddd.xpc",
NULL);
// Create the context being sent to mainf
struct context* c = malloc(sizeof(struct context));
c->text = malloc(sizeof("Hello"));
strcpy(c->text, "Hello");
xpc_rich_error_t sess_err = NULL;
xpc_session_t session = xpc_session_create_xpc_service("y.getFilec",
xpcq,
XPC_SESSION_CREATE_INACTIVE,
&sess_err);
if (sess_err != NULL) {
printf("Session Create Error: %s\n",
xpc_rich_error_copy_description(sess_err));
xpc_release(sess_err);
exit(1);
}
xpc_release(sess_err);
xpc_session_set_incoming_message_handler(session, ^(xpc_object_t message) {
printf("message recieved\n");
});
c->sess = session;
xpc_rich_error_t sess_ac_err = NULL;
xpc_session_activate(session, &sess_ac_err);
if (sess_err != NULL) {
printf("Session Activate Error: %s\n",
xpc_rich_error_copy_description(sess_ac_err));
xpc_release(sess_ac_err);
exit(1);
}
xpc_release(sess_ac_err);
xpc_retain(session);
dispatch_async_f(mainq, (void*)c, mainf);
xpc_release(session);
dispatch_main();
}
XPC Service code:
#include <stdio.h>
#include <xpc/xpc.h>
#include <dispatch/dispatch.h>
int main(void) {
xpc_rich_error_t lis_err = NULL;
xpc_listener_t listener = xpc_listener_create("y.getFilec",
NULL,
XPC_LISTENER_CREATE_INACTIVE,
^(xpc_session_t sess){
printf("Incoming Session: %s\n", xpc_session_copy_description(sess));
xpc_session_set_incoming_message_handler(sess,
^(xpc_object_t mess) {
xpc_object_t repl = xpc_dictionary_create_empty();
xpc_dictionary_set_string(repl, "test", "test");
xpc_rich_error_t send_repl_err = xpc_session_send_message(sess, repl);
if (send_repl_err != NULL) printf("Send Reply Error: %s\n",
xpc_rich_error_copy_description(send_repl_err));
});
xpc_rich_error_t sess_ac_err = NULL;
xpc_session_activate(sess, &sess_ac_err);
if (sess_ac_err != NULL) printf("Session Activate: %s\n",
xpc_rich_error_copy_description(sess_ac_err));
},
&lis_err);
if (lis_err != NULL) {
printf("Listener Error: %s\n", xpc_rich_error_copy_description(lis_err));
xpc_release(lis_err);
}
xpc_rich_error_t lis_ac_err = NULL;
xpc_listener_activate(listener, &lis_ac_err);
if (lis_ac_err != NULL) {
printf("Listener Activate Error: %s\n", xpc_rich_error_copy_description(lis_ac_err));
xpc_release(lis_ac_err);
}
dispatch_main();
}
I'm working on an XPC server and need to determine the owner of the client process that connects to it. Specifically, I'd like to retrieve details such as the fully qualified user name or other identifying information from the XPC client connection.I'm considering using xpc_connection_get_pid() to get the client’s process ID, but I’m unsure of the best way to map this to the user who owns the process.
Is there a recommended API or approach to capture this information securely?
I have implemented a XPC server using C APIs. I want to write unit tests for it.
I came across the following links that use Swift APIs-
Testing and Debugging XPC Code With an Anonymous Listener
TN3113
I have tried to write anonymous listener code and the client code in the same file, using C APIs-
#include <unistd.h>
#include <syslog.h>
#include <pthread.h>
#include <stdio.h>
#include <xpc/xpc.h>
#include <xpc/connection.h>
#include <CoreFoundation/CoreFoundation.h>
static void Anon_Client_Connection_Handler(xpc_connection_t connection, xpc_object_t clientMessage)
{
const char *description = xpc_copy_description(clientMessage);
printf("Event received - %s\n", description);
free((void *)description);
xpc_type_t type = xpc_get_type(clientMessage);
if (type == XPC_TYPE_ERROR)
{
if (clientMessage == XPC_ERROR_CONNECTION_INVALID)
printf("Client_Connection_Handler received invalid connection n");
else if (clientMessage == XPC_ERROR_TERMINATION_IMMINENT)
printf("Client_Connection_Handler received termination notice n");
}
else
{
const char *clientMsg = xpc_dictionary_get_string(clientMessage, "message");
printf("Received from client: %s ", clientMsg);
}
}
static void Anon_Listener_Connection_Handler(xpc_connection_t connection)
{
printf("Anon_Listener_Connection_Handler called, setting up event handler \n");
xpc_connection_set_event_handler(connection, ^(xpc_object_t clientMessage) {
printf("Processing the connection! \n");
Anon_Client_Connection_Handler(connection, clientMessage);
});
xpc_connection_resume(connection);
}
int main(int argc, const char *argv[])
{
xpc_connection_t anon_listener = xpc_connection_create(NULL, NULL);
xpc_connection_set_event_handler(anon_listener, ^(xpc_object_t clientConnection) {
printf("Client tried to connect \n");
Anon_Listener_Connection_Handler(clientConnection);
});
xpc_connection_resume(anon_listener);
printf("\nINFO Anonymous connection resumed");
xpc_object_t anon_endpoint = xpc_endpoint_create(anon_listener);
xpc_connection_t clientConnection = xpc_connection_create_from_endpoint(anon_endpoint);
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "message", "client's message");
xpc_connection_send_message_with_reply(clientConnection, message, dispatch_get_main_queue(), ^(xpc_object_t event) {
printf("\nINFO inside reply");
const char *description = xpc_copy_description(event);
printf("\nINFO %s",description);
free((void *)description);
});
xpc_release(message);
xpc_release(anon_listener);
printf("\nINFO Releasing listener");
xpc_release(anon_endpoint);
printf("\nINFO Releasing endpoint");
// dispatch_main();
return 0;
}
and this is the output I get
INFO Anonymous connection resumed
INFO Releasing listener
INFO Releasing endpoint
I am not able to connect to the client and exchange messages. Where am I going wrong?
I've been experimenting with the new low-level Swift API for XPC (XPCSession and XPCListener). The ability to send and receive Codable messages is an appealing alternative to making an @objc protocol in order to use NSXPCConnection from Swift — I can easily create an enum type whose cases map onto the protocol's methods.
But our current XPC code validates the incoming connection using techniques similar to those described in Quinn's "Apple Recommended" response to the "Validating Signature Of XPC Process" thread. I haven't been able to determine how to do this with XPCListener; neither the documentation nor the Swift interface have yielded any insight.
The Creating XPC Services article suggests using Xcode's XPC Service template, which contains this code:
let listener = try XPCListener(service: serviceName) { request in
request.accept { message in
performCalculation(with: message)
}
}
The apparent intent is to inspect the incoming request and decide whether to accept it or reject it, but there aren't any properties on IncomingSessionRequest that would allow the service to make that decision. Ideally, there would be a way to evaluate a code signing requirement, or at least obtain the audit token of the requesting process.
(I did notice that a function xpc_listener_set_peer_code_signing_requirement was added in macOS 14.4, but it takes an xpc_listener_t argument and I can't tell whether XPCListener is bridged to that type.)
Am I missing something obvious, or is there a gap in the functionality of XPCListener and IncomingSessionRequest?
I have two privileged service(s) and a desktop app. The privileged services are packaged into /Library/*** and are run using launchd at runtime. The desktop app is just dropped into /Applications.
The desktop app connects to one of the services (let's say service "B") via XPC. That is, B is running an XPC listener (using libxpc). Both applications are written in golang with xpc interaction via CGO.
This is all working fine: The desktop app is receiving notifications over XPC from service B. However, during our build we dump the built and signed apps (before .pkg'ing) into a dist folder. When we run the app (using a makefile target), we copy the services from dist to another location as root, then execute the binaries directly. This is problematic for the desktop app, because my understanding is that XPC requires launchd to assert the namespace it's under. Thus, when service B is launched this way, it says "operation not permitted." We also want to reserve the ability to run a production version of our app on the same machine (drink our own champagne and all that), and I would like to avoid having development versions running on startup, so I don't want to use the same launch configurations.
MacOS is one of three platforms we support (linux, windows as well). Our IPC implementation under MacOS uses XPC via golang build tags.
Questions:
Is it possible to start the XPC server without using launchd, or by using launchd but without registering it as an actual service?
Is this a use case where using a unix domain socket would be better (albeit i feel like securing the socket between the privileged / unprivileged process would be ... fun).
Additional / somewhat unrelated questions:
is it possible for me to somehow restrict another process from chatting with service B over XPC (restrict to my other desktop app)?
This is an app bundle question, so very unrelated: The service "app" that contains services A and B is in /Library, with the plist pointing to A, but B resides in Contents/MacOS next to A. Should this be split out into its own app bundle under Frameworks, or is this fine?
I am using C APIs for XPC communication.
When my XPC server gets a xpc_dictionary as a message, I use xpc_dictionary_get_string to get the string which is of type const char*. Afterwards, when I try to free up the memory for the string, I get an error.
I could not find any details on why this happens.
Does XPC handle the lifecycle of these C strings ?
I did some tests to see the behaviour.
The following code snippet prints a string temp before and after releasing the dictionary memory.
char* string = "dummy-string";
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_string(dict, "str", string);
const char* temp = xpc_dictionary_get_string(reply, "str");
printf("temp before release: %s\n", temp);
xpc_release(reply);
printf("temp after release: %s\n", temp);
output:
# temp before release: dummy-string
# temp after release:
I tried to free the variable temp before and after releasing dict .
char* string = "dummy-string";
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_string(dict, "str", string);
const char* temp = xpc_dictionary_get_string(dict, "str");
printf("temp before release: %s\n", temp);
free((void *)temp); // case 1
xpc_release(dict);
// free((void *)temp); // case 2
printf("temp after release: %s\n", temp);
in both the cases i got the output:
# temp before release: dummy-string
# app(18502,0x1f02fc840) malloc: Double free of object 0x145004a20
# app(18502,0x1f02fc840) malloc: *** set a breakpoint in malloc_error_break to debug
# SIGABRT: abort
# PC=0x186953720 m=0 sigcode=0
# signal arrived during cgo execution
# ...
# ...
There is one xpc server and two xpc clients (clientA and clientB). When clientB sends a message to the xpc server, xpc server fills a value for dummyString in it's memory and I want clientA to know that dummyString got updated and also the new value for this dummyString. The updation of dummyString is not something that happens often.
Two options we tried:
Have a timer for 5 seconds in clientA and keep polling and request for the value of this dummyString.
Setup a darwin notification in server that gets posted whenever dummyString is being updated. clientA receives requests for dummyString value only when it observes a notification being posted.
Which of these two approaches causes the least delay for clientA to know the updated value of dummyString?
I have 2 XPC clients and an XPC server. One of the XPC clients is a binary-helper that serves as a native messaging host for the browserExtension. The other XPC client sends a specific event to the XPC server, which then triggers a Darwin notification. The binary-helper observes this Darwin notification and sends a response to the browserExtension.
Currently, we're considering two options to communicate the response from binary-helper to browserExtension:
Polling: Every 5 seconds, the browserExtension checks for a response.
Darwin Notifications: The binary-helper sends a message to the browserExtension as soon as it observes the Darwin notification.
I'm wondering if Darwin notifications are fast enough to reliably deliver this response to the browserExtension in real time, or if polling would be a more reliable approach. Any insights or experiences with using Darwin notifications in a similar scenario would be greatly appreciated.
I'm using libxpc in a C server and Swift client. I set up a code-signing requirement in the server using xpc_connection_set_peer_code_signing_requirement(). However, when the client doesn't meet the requirement, the server just closes the connection, and I get XPC_ERROR_CONNECTION_INTERRUPTED on the client side instead of XPC_ERROR_PEER_CODE_SIGNING_REQUIREMENT, making debugging harder.
What I want:
To receive XPC_ERROR_PEER_CODE_SIGNING_REQUIREMENT on the client when code-signing fails, for better debugging.
What I’ve tried:
Using xpc_connection_set_peer_code_signing_requirement(), but it causes the connection to be dropped immediately.
Questions:
Why does the server close the connection without sending the expected error?
How can I receive the correct error on the client side?
Are there any other methods for debugging code-signing failures with libxpc?
Thanks for any insights!
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
Signing Certificates
Code Signing
On my MAC, I have a XPC server running as a daemon. It also checks the clients for codesigning requirements.
I have multiple clients(2 or more).
Each of these clients periodically(say 5 seconds) poll the XPC server to ask for a particular data.
I want to understand how the performance of my MAC will be affected when multiple XPC clients keep polling a XPC server.
I have created a XPC server and client using C APIs. I want to ensure that I trust the client, so I want to have a codesigning requirement on the server side, something like -
xpc_connection_set_peer_code_signing_requirement(listener, "anchor apple generic and certificate leaf[subject.OU] = \"1234567\"")
This checks if the client code was signed by a code-signing-identity issued by Apple and that the teamID in the leaf certificate is 1234567.
My questions are-
Is using teamID as a signing requirement enough? What else can I add to this requirement to make it more secure?
How does xpc_connection_set_peer_code_signing_requirement work internally? Does it do any cryptographic operations to verify the clients signature or does it simply do string matching on the teamID?
Is there a way actually verify the clients signature(cryptographically) before establishing a connection with the server? (so we know the client is who he claims to be)
Topic:
Code Signing
SubTopic:
Certificates, Identifiers & Profiles
Tags:
XPC
Signing Certificates
Code Signing
Hi! I've been developing iOS and macOS apps for many years, but now I am looking to dive into smth i have never touched before, namely privileged helpers, and i am struggling hard trying to find my footing.
Here’s my use case: I have a CLI tool that requires elevated privileges. I want to create a menu bar app that can interact with this tool, but I’m struggling to find solid documentation or examples of how to accomplish this using SMAppService. I might just be missing something obvious.
If anyone could point me toward relevant documentation, examples, articles, tutorials, or even a WWDC session that covers running privileged helpers with SMAppService, I would greatly appreciate it.
Thanks in advance!
This is the functionality I am trying to achieve with libxpc:
There's one xpc server and two xpc clients. When the xpc server receives a particular dictionary item from clientB, the server needs to send a response to both clientA and clientB.
This is the approach I am currently using:
First, clientA creates a dictionary item that indicates that this item is from clientA. Now, clientA sends this dictionary to server. When server receives this item, it stores the connection instance with clientA in a global variable. Next, when clientB sends a particular dictionary item, server uses this global variable where it perviously stored clientA's connection instance to send a response back to clientA, alongside clientB.
Only one edge case I can see is that when clientA closes this connection instance, server will be trying to send a response to an invalidated connection.
Question:
Is this approach recommended? Any edge cases I should be aware of? Is there any better way to achieve this functionality?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Inter-process communication
XPC
I have followed this post for creating a Launch Agent that provides an XPC service on macOS using Swift-
post link - https://rderik.com/blog/creating-a-launch-agent-that-provides-an-xpc-service-on-macos/
In the swift code the interface of the XPC service is defined by protocols which makes the code nice and neat. I want to implement the XPC service using C APIs for XPC, and C APIs send and receive messages using dictionaries, which need manual handling with conditional statements.
I want to know if its possible to go with the protocol based approach with C APIs.