Hello,
On macOS, I can include a second executable in the app bundle, which the main executable can launch and communicate with via pipes (standard input/output). I've done this before (with app sandbox inheritance).
I've read on other forums that this is not possible on iOS. Is that correct?
I tried popen() and it always fails with the error "Operation not permitted." 😔
I just wanted to confirm before I move on to using frameworks. Thanks for your time.
Post not yet marked as solved
In my project I have a host application and a husk application.
What I want to do is, every time the user launches a new view in the host application, I want to create one more dock icon by launching another instance of husk application. Then the husk application behaves like it is the view itself by monitoring the event of click/quit and send them to the host application through XPC.
The XPC tutorial tells me an XPC service embedded in an application is invisible to the processes outside the bundle. To communicate between two foreground applications it seems that I need to create a third helperTool/agent/daemon which venders a Mach/XPC service.
But I wonder if I can put husk application inside the bundle of the hose application. So they can directly connect to the XPC service which is also embedded in the same bundle.
If the answer is no, maybe NSDistributedNotificationCenter is much better and simpler in my scenario?
Hi, I am currently building my own VPN application using NetworkExtension's PacketTunnelProvider.
I want to send information from the PacketTunnelProvider to the ViewController when a VPN connection fails and to tell the user why.
The code now is as shown below.
When the startTunnel() being overwritten is executed, somehow NotificationCenter.default.post(name: NSNotification.Name.NEVPNStatusDidChange, object: nil) is executed and VPNStatusDidChange(_ notification: Notification?) in the ViewController is called and displays some message.
I tried to do the same thing by writing NotificationCenter.default.post(name: NSNotification.Name(rawValue: "testnotify"), object: nil) in the PacketTunnelProvider.swift , but it does not work. What is wrong?
Here is a part of current PacketTunnelProvider.swift
override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) {
conf = (self.protocolConfiguration as! NETunnelProviderProtocol).providerConfiguration! as [String : AnyObject]
self.setupWSSession()
DispatchQueue.global().async {
while (self.connectionPhase < 5) {
Thread.sleep(forTimeInterval: 0.5)
}
self.tunToWS()
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "testnotify"), object: nil)
}
And here is a part of ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
initVPNTunnelProviderManager()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.VPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.receieve(_:)), name: NSNotification.Name(rawValue: "testnotify"), object: nil)
}
@objc func VPNStatusDidChange(_ notification: Notification?) {
print("VPN Status changed:")
let status = self.vpnManager.connection.status
switch status {
case .connecting:
print("Connecting...")
connectButton.setTitle("Disconnect", for: .normal)
break
case .connected:
print("Connected...")
connectButton.setTitle("Disconnect", for: .normal)
break
case .disconnecting:
print("Disconnecting...")
break
case .disconnected:
print("Disconnected...")
connectButton.setTitle("Connect", for: .normal)
break
case .invalid:
print("Invliad")
break
case .reasserting:
print("Reasserting...")
break
}
}
@objc func receive(_ notification: Notification?) {
print("receive Notification!")
}
Post not yet marked as solved
We'd prefer our security application not be worked around by the complex task of typing sudo launchctl unload /Library/LaunchDaemons/foo.plist 😄. Is there a way to prevent that? (We're not using ServiceManagement because we need ot control some of the plist entries, sadly.)
Post not yet marked as solved
Hi,
I’d like to perform client-side certificate authentication from https based connection in macOS.
I’m using the method didReceiveChallenge from URLSession. However, I cannot read the keychain directly since my process is running as Daemon, and my client certificate reside in login keychain.
So I've followed the guidance from this question https://developer.apple.com/forums/thread/106851, and sent this authentication request to a user-based process which is running in the current user so it has access to the keychain.
After I acquire the NSURLCredential object, I’d like to return it back to the Daemon, so it may run the completionHandler with that credential.
However, After I successfully create the NSURLCredential in the user process, and send it back using some reply callback. It looks like the object didn’t serialized properly and I get the following error :
Exception: decodeObjectForKey: Object of class "NSURLCredential" returned nil from -initWithCoder: while being decoded for key <no key>
Here’s my client side code ( I made sure that the server side create a valid NSURLCredential object).
and the problem occur after I send the XPC request, right when i’m about to get the callback response (reply)
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) {
[myXpcService getCertIdentityWithAcceptedIssuers:challenge.protectionSpace.distinguishedNames
withReply:^(NSURLCredential *cred, NSError *error) {
if (error != nil) {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
} else {
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
}
}];
}
Perhaps anybody can tell me what did I do wrong here ? Does XPC is capable to pass complex objects like NSURLCredentials ?
thanks !
Post not yet marked as solved
I am trying to pass an array of C-structs to an XPC Service, but the service receives only the first element. Following is the C struct
struct MyStruct
{
char *name;
unsigned char v1;
unsigned char v2;
Status status; // a c-style enum
};
and I am using it like this
struct MyStruct structs[3] = {{"name1", 0, 0, success}, {"name2", 1,1, success}, {0}};
[[_connectionToService remoteObjectProxy] doSomething:structs];
and doSomething is declared as
- (void)doSomething: (struct MyStruct[]) structs;
The document Creating XPC Services mentions that C structures and arrays containing only the types listed above are supported, but I am unable to get it to work even for an array of c-strings or ints.
Also, there's an API for making synchronous RPC calls but there is no documentation available for it.
- (id)synchronousRemoteObjectProxyWithErrorHandler:(void (^)(NSError *error))handler
It does seem to block but only if the remote method has a reply block. Is this the expected behaviour? And is it safe to cache the proxy object returned by this method?
Post not yet marked as solved
I refer to this article:
https://developer.apple.com/forums/thread/129752
extension Cmd {
static func launch(tool: URL, arguments: [String], completionHandler: @escaping (Int32, Data) -> Void) throws {
let group = DispatchGroup()
let pipe = Pipe()
var standardOutData = Data()
group.enter()
let proc = Process()
proc.executableURL = tool
proc.arguments = arguments
proc.standardOutput = pipe.fileHandleForWriting
proc.terminationHandler = { _ in
proc.terminationHandler = nil
group.leave()
}
group.enter()
DispatchQueue.global().async {
// Doing long-running synchronous I/O on a global concurrent queue block
// is less than ideal, but I’ve convinced myself that it’s acceptable
// given the target ‘market’ for this code.
let data = pipe.fileHandleForReading.readDataToEndOfFile()
pipe.fileHandleForReading.closeFile()
DispatchQueue.main.async {
standardOutData = data
group.leave()
}
}
group.notify(queue: .main) {
completionHandler(proc.terminationStatus, standardOutData)
}
try proc.run()
// We have to close our reference to the write side of the pipe so that the
// termination of the child process triggers EOF on the read side.
pipe.fileHandleForWriting.closeFile()
}
}
run shell :
try Cmd.launch(tool: URL(fileURLWithPath: "/usr/bin/which"), arguments: ["docker"]) { (status, outputData) in
let output = String(data: outputData, encoding: .utf8) ?? ""
print("done, status: \(status), output: \(output)")
}
the result print:
done, status: 1, output:
i had remove sandbox and use this code in my mac app. and return value is empty string.
I tried running this script using https://github.com/kareman/SwiftShell and got the same result
Post not yet marked as solved
We are noticing a strange behavior with our app and launchctl, not sure yet if it is only in M1 Monterey Macos.
We have a launchctl plist that has not changed for a while that allows the app to restart after a crash via the Keepalive key
&lt;key&gt;KeepAlive&lt;/key&gt;
&lt;dict&gt;
&lt;key&gt;SuccessfulExit&lt;/key&gt;
&lt;false/&gt;
What we are noticing is that the app crashes and instead of the app reopening via launchctl , an Apple crash report window opens. The app is used in several headless environments and we are trying to understand asap how to deal with this change of behavior.
Any input will be helpful.
Is there an option in xcode to modify this kind of behavior ? For example set the app to show a crash report instead of launchctl executing.
Is there a way to trace why launchctl did not reopen the app ?
Does it make a difference if the app is a debug version ? We have noticed no difference between Release and Debug versions, same behavior.
I have a few questions regarding daemons. Indeed, even the macos developer center has limited information resources.
I want to develop an application daemon that runs after system boot without login.
a) a Daemon; Is it a simple console application combined with a plist? Because there are almost no tutorials on daemon development related to xcode. If there is a code sample reference, can you share it here?
b) Can daemons be downloaded from the app store? Because there must be a software that I can offer to everyone through the app store. Is the installation automatic like other app store apps? If anyone has experience and can share it, I would be very grateful.
c) I am working on an api related to mirroring the screen to android phone. Do you think a daemon has full access to wifi/ble and screen capture APIs?
I would be very happy to hear your suggestions.
Post not yet marked as solved
I'm trying to use task_for_pid in a project but I keep getting error code 5 signaling some kind of signing error. Even with this script I cant seem to get it to work.
#include <mach/mach_types.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/mach_traps.h>
#include <stdio.h>
int main(int argc, const char * argv[]) {
task_t task;
pid_t pid = argc >= 2 ? atoi(argv[1]) : 1;
kern_return_t error = task_for_pid(mach_task_self(), pid, &task);
printf("%d -> %x [%d - %s]\n", pid, task, error, mach_error_string(error));
return error;
}
I've tried signing my executables using codesign and also tried building with Xcode with the "Debugging Tool" box checked under hardened runtime. My Info.plist file includes the SecTaskAccess key with the values "allowed" and "debug." Hoping someone can point me towards what I'm missing here. Thanks!
Hi!
I wrote a backup console application. It does use ssh/sshfs to access a web server via public key. Also it does send an SMTP-mail when finished.
If the process is started via
launchctl load DAEMON
it works always properly (RunAtLoad is true).
But when the daemon is called automatically at night it does not always work. In my log I get these errors:
ssh: connect to host SERVERURL port 22: Undefined error: 0
and
Failed sending: NIOConnectionError(host: "mail.mydomain", port: 25, dnsAError: Optional(NIOCore.SocketAddressError.unknown(host: "mail.mydomain", port: 25)), dnsAAAAError: Optional(NIOCore.SocketAddressError.unknown(host: "mail.mydomain", port: 25)), connectionErrors: [])
it does run on a MacMini M1 with macOS 12.2.
Any clue what's wrong or how to find the reason of this issue?
PS. On another MacMini (Intel) with macOS 11.6 the backup works since a year but there is always an admin user logged in.
Post not yet marked as solved
and how to access the metadata ?
Post not yet marked as solved
As per my research I found that there is no way to open general settings app but it is possible with openSettingsURLString.
Can I use openURL API with options to open general settings?
And also how can we request iOS API team to provide such support in future as this is so many time generated request.
Post not yet marked as solved
This question came from https://developer.apple.com/forums/thread/695826, where I saw crashes in AppKit if called without a GUI session. What troubles me from there is that our code is registered as a LaunchAgent (under /Library/LaunchAgents), and I was under the impression that a LaunchAgent only runs if a user logs into a GUI session. I tried at least ssh-only sessions and didn't see it launch automatically (I had to manually launch it through ssh to reproduce the crash). But the fact that we see thousands of crash reports coming from a few devices means somehow our LaunchAgent is trying to launch itself automatically & repeatedly on these devices, while there is no GUI session so it keeps crashing.
So, maybe there is a legit way to reproduce the scenario, to launch a LaunchAgent without a GUI session that I'm not aware of?
I have a use case in which I have a launch daemon (as the XPC service) than needs to communicate with two XPC clients. Each of these clients has different functional cases for communication that do not overlap. Therefore, the NSXPCInterface for client A would be configured with a different protocol than the NSXPCInterface that would be configured for client B. Client A and Client B do not need to talk to each other; they each just need to communicate with the daemon.
I am confused how to appropriately set up the NSXPCListener and NSXPCListenerDelegate on the daemon to support NSXPCConnections with proxy objects that adhere to varying interfaces to support these two clients.
Is there a way for a single NSXPCListener (and associated delegate) to listen for connections requiring the exportedInterface to be different?
Is there a way to send data through the NSXPCConnection that will allow the NSXPCListenerDelegate to conditionally determine which exported interface and object to configure?
One idea I had was to have the daemon contain two NSXPCListeners. Each listener would be responsible for connections coming from the respective clients.
Will this option work? If so, it is the advisable approach?
I'd like to get an indication about the context in which my process is running from. I'd like to distinguish between the following cases :
It runs as a persistent scheduled task (launchDaemon/launchAgent)
It was called on-demand and created by launchd
using open command-line or double-click.
It was called directly from command-line terminal (i.e. > /bin/myProg from terminal )
Perhaps is there any indication about the process context using Objective-c/swift framework or any other way ?
I wish to avoid inventing the wheel here :-)
thanks
Post not yet marked as solved
Hi,
We are creating a macOS application that is built as a 'Bundle' and NOT as a Unix-style application. In a specific flow, we need to attach this process to a terminal session by creating one. Now, on this attached terminal, stdin/stdout etc would happen.
We are using Objective C.
Any pointers on how to go about this would be helpful.
Post not yet marked as solved
Hi,
In our system we have a launch daemon that manages a child process that performs networking. We also have launch agents that perform GUI work in each user session. We'd like those agents to connect to the child process of the launch daemon via XPC. In the launchd.plist we can expose a MachServices port for the launch daemon itself but how do we expose a port for the child process? Is it possible for the Launch daemon to smuggle a declared port to its child process?
Thanks!
Johan
Post not yet marked as solved
I had my daemon service registered ( with keepalive true) to Mac OS and running in Catalina, after I upgraded to Bigsur the daemon did not start. when I tried to start manually I found that the daemon has been disabled.
I had to load the daemon service with '-w' to enable it. in a customer machine, we cant ask them to do it manually.
is there any way to stop disabling a daemon service during an upgrade to bigsur?
I have small integration test that is confirming behavior in XPC communications (leveraging NSXPCConnection) between a dummy XPC service and an XPC client. My test is flaky, which is indicating to me that I don't fully understand the nature of connections between services and clients, and I was hoping to get clarity as to what's happening in my test.
My test involves the following steps.
XCode Pre-Action: Load the plist for a dummy XPC service into launchctl.
Create 2 XPC client objects (in the same client process), each with their own NSXPCConnection to the dummy service, and connect.
Tell client 1 to disconnect, which calls NSXPCConnection.invalidate()
Using client 2, send a message to the same dummy XPC service over it's own NSXPCConnection object.
Wait for the echo response from the dummy XPC service
XCode Post-Action: Unload the plist for the dummy XPC service from launchctl
func testMultipleConnections() {
let delegate1 = MockClientDelegate()
let delegate2 = MockClientDelegate()
let client1 = XPCMessagingClientFacade(withServiceName: serviceName, andXPCErrorHandler: {error in })
let client2 = XPCMessagingClientFacade(withServiceName: serviceName, andXPCErrorHandler: {error in })
client1.processMessageDelegate = delegate1
client2.processMessageDelegate = delegate2
_ = client1.connect()
_ = client2.connect()
_ = client1.disconnect()
delegate2.expectation = XCTestExpectation(description: "Message received from echo service")
_ = client2.sendMessage(ofMessageType: eMTAction_Uninstall, withData: ["dummy": "data"])
wait(for: [delegate2.expectation!], timeout: timeout)
}
This test sometimes succeeds and sometimes fails. Sometimes, the test expectation at the bottom is fulfilled, and sometimes the timeout is hit. I have tested with excessively long timeouts to rule-out processing-time as as factor.
I am suspecting that calling invalidate() on one NSXPCConnection object is somehow causing a separate connection between the same client and service process to also be invalidated.
Is it even a valid use-case to have multiple NSXPCConnection objects between a single XPC Service and XPC Client?
When NSXPCConnection.invalidate() is called, does it inherently mean nothing can connect and communicate anymore, or is it just for that specific connection?
When invalidate() is called, what does launchctl do to manage that service? Does it shut it down and allow subsequent connection attempts to spool the service up again? Does it prevent from any connections from ever being made again?