I have an app which contains a bundled launch agent that I register using SMAppService.agent(plistName:). I’ve packaged the launch agent executable in the typical Mac app bundle structure so I can embed a framework in it. So, the launch agent lives in Contents/SharedSupport/MyLaunchAgent.app/Contents/MacOS/MyLaunchAgent.
However, I suspect this approach might be falling afoul of the scheduler, since the taskinfo tool reports my launch agent has a requested & effective role of TASK_DEFAULT_APPLICATION (PRIO_DARWIN_ROLE_UI), rather than the TASK_UNSPECIFIED (PRIO_DARWIN_ROLE_DEFAULT) value I see with system daemons.
I tried setting the LSUIElement Info.plist key of my launch agent to YES, but this seems to have had no effect.
What’s the recommended approach here?
Processes & Concurrency
RSS for tagDiscover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi! I'm trying to submit a task request into BGTaskScheduler when I background my app. The backgrounding triggers an update of data to a shared app groups container. I'm currently getting the following error and unsure where it's coming from:
*** Assertion failure in -[BGTaskScheduler _unsafe_submitTaskRequest:error:], BGTaskScheduler.m:274
Here is my code:
BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:kRBBackgroundTaskIdentifier];
NSError *error = nil;
bool success = [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
MacOS Version: 14.7.2
macOS SDKs:
macOS 14.5 -sdk macosx14.5
I am working on a sample program for validation Against:
Team Identifier
Developer ID
I started with validating Team Identifier, but my validation is not working and it is allowing to launch programs which are not matching the team identifier in the signature.
Below is my code:
func verifyExecutableWithLCR(executablePath: String, arguments: [String]) -> Bool {
let task = Process()
task.launchPath = executablePath
task.arguments = arguments
if #available(macOS 14.4, *) {
print("launchRequirementData is available on this system.")
do {
let req = try OnDiskCodeRequirement.allOf {
TeamIdentifier("ABCDEFGHI")
//SigningIdentifier("com.***.client.***-Client.****")
}
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
let requirementData = try encoder.encode(req)
task.launchRequirementData = requirementData
print("launchRequirementData is set.")
try task.run()
print("[SUCCESS] Executable passed the code signature verification.")
return true
} catch {
print("[ERROR] Code signature verification failed: \(error.localizedDescription)")
return false
}
} else {
print("[WARNING] launchRequirement is not available on this macOS version.")
return false
}
}
Could you please help me in identifying whay am I doing wrong here?
Since macOS 26, including the latest 26.1, the menu bar icon does not show up for our app called Plover which is built with PySide6 (based on Qt 6) and runs via a relocatable python that is packaged into the app. The code is open source and can be found on GitHub. The latest release, including the notarized DMG, can be found here.
When running the .app via the command below, the menu bar icon does show up but the process that is running is python3.13 and not Plover:
/Applications/Plover.app/Contents/MacOS/Plover -l debug
When running the app by just clicking on the application icon, the process is Plover but the menu bar icon is not showing - also not in the settings (Menu Bar > Allow in the Menu Bar). Before macOS 26, the menu bar icon was always shown.
Some pointers to potentially relevant parts of our code:
shell script that builds the .app
Info.plist
plover_launcher.c
trayicon.py
This problem might be related to this thread, including the discussion around Qt not calling NSApplicationMain.
What I'm trying to figure out is whether this is a problem with macOS 26, Qt 6, PySide6, or our code.
Any pointers are highly appreciated!
Topic:
App & System Services
SubTopic:
Processes & Concurrency
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 ?
Hello,
My app (daemon) time to time need to know list of GUI login sessions.
According to the recommendation, I am using getutxent().
https://developer.apple.com/library/archive/qa/qa1133/_index.html
However, I have faced with unclear behaviour in case of running "Migration Assistant". It can be re-created without my app.
Steps to recreate:
login as 'user #1'
start "Migration Assistant"
quit "Migration Assistant"
new login prompt will be opened
login as 'user #2'
In spite the session of 'user #1' is closed, the command line tool "who", which gathers information from /var/run/utmpx, reports opened sessions of 'user #1'.
Is it bug or feature?
Thank you in advance!
I've adopted the new BGContinuedProcessingTask in iOS 26, and it has mostly been working well in internal testing. However, in production I'm getting reports of the tasks failing when the app is put into the background.
A bit of info on what I'm doing: I need to download a large amount of data (around 250 files) and process these files as they come down. The size of the files can vary: for some tasks each file might be around 10MB. For other tasks, the files might be 40MB. The processing is relatively lightweight, but the volume of data means the task can potentially take over an hour on slower internet connections (up to 10GB of data).
I set the totalUnitCount based on the number of files to be downloaded, and I increment completedUnitCount each time a file is completed.
After some experimentation, I've found that smaller tasks (e.g. 3GB, 10MB per file) seem to be okay, but larger tasks (e.g. 10GB, 40MB per file) seem to fail, usually just a few seconds after the task is backgrounded (and without even opening any other apps). I think I've even observed a case where the task expired while the app was foregrounded!
I'm trying to understand what the rules are with BGContinuedProcessingTask and I can see at least four possibilities that might be relevant:
Is it necessary to provide progress updates at some minimum rate? For my larger tasks, where each file is ~40MB, there might be 20 or 30 seconds between progress updates. Does this make it more likely that the task will be expired?
For larger tasks, the total time to complete can be 60–90 mins on slower internet connections. Is there some maximum amount of time the task can run for? Does the system attempt some kind of estimate of the overall time to complete and expire the task on that basis?
The processing on each file is relatively lightweight, so most of the time the async stream is awaiting the next file to come down. Does the OS monitor the intensity of workload and suspend the task if it appears to be idle?
I've noticed that the task UI sometimes displays a message, something along the lines of "Do you want to continue this task?" with a "Continue" and "Stop" option. What happens if the user simply ignores or doesn't see this message? Even if I tap "Continue" the task still seems to fail sometimes.
I've read the docs and watched the WWDC video, but there's not a whole lot of information on the specific issues I mention above. It would be great to get some clarity on this, and I'd also appreciate any advice on alternative ways I could approach my specific use case.
Testing Environment:
iOS: 26.0 Beta 7
Xcode: Beta 6
Description:
We are implementing the new BGContinuedProcessingTask API introduced in iOS 26. We have followed the official documentation and WWDC session guidance to configure our project.
The Background Modes (processing) and Background GPU Access capabilities have been added in Xcode.
The com.apple.developer.background-tasks.continued-processing.gpu entitlement is present and set to in the .entitlements file.
The provisioning profile details viewed within Xcode explicitly show that the "Background GPU Access" capability and the corresponding entitlement are included.
Despite this correct configuration, when running the app on supported hardware (iPhone 16 Pro), a call to BGTaskScheduler.supportedResources.contains(.gpu) consistently returns false.
This prevents us from setting request.requiredResources = .gpu. As a result, when the BGContinuedProcessingTask starts without the GPU resource flag, our internal Metal-based exporter attempts to access the GPU and is terminated by the system, throwing an IOGPUMetalError: Insufficient Permission (to submit GPU work from background).
We have performed extensive debugging, including a full reset of the provisioning profile (removing/re-adding capabilities, toggling automatic signing, cleaning build folders, and reinstalling the app), but the issue persists. This strongly suggests a bug in the iOS 26 beta where the runtime is failing to correctly validate a valid entitlement.
Additionally, we've observed inconsistent behavior across devices. On an A16-based iPad, the task submits successfully (BGTaskScheduler.submit does not throw an error), but the launch handler is never invoked by the system. On the iPhone 16 Pro, the handler is invoked, but we encounter the supportedResources issue described above. This leads us to ask for clarification on the exact hardware requirements for this feature. We hypothesize that it may be limited to devices that support Apple Intelligence (A17 Pro and newer). Could you please confirm this and provide official documentation on the device support criteria?
Steps to Reproduce:
Create a new Xcode project.
In Signing & Capabilities, add "Background Modes" (with "Background processing" checked) and "Background GPU Access".
Add a permitted identifier (e.g., "com.company.test.*") to BGTaskSchedulerPermittedIdentifiers in Info.plist.
In application(_:didFinishLaunchingWithOptions:) or a ViewController's viewDidLoad, log the result of BGTaskScheduler.shared.supportedResources.contains(.gpu).
Build and run on a physical, supported device (e.g., iPhone 16 Pro).
Expected Results:
The log should indicate that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns true.
Actual Results:
The log shows that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns false.
Problem summary
I have a macOS helper app that is launched from a sandboxed main app. The helper:
has com.apple.security.app-sandbox = true and com.apple.security.inherit = true in its entitlements,
is signed and embedded inside the main app bundle (placed next to the main executable in Contents/MacOS),
reports entitlement_check = 1 (code signature contains sandbox entitlement, implemented via SecStaticCode… check),
sandbox_check(getpid(), NULL, 0) returns 1 (runtime sandbox enforcement present),
APP_SANDBOX_CONTAINER_ID environment variable is not present (0).
Despite that, Cocoa APIs return non-container home paths:
NSHomeDirectory() returns /Users/<me>/ (the real home).
[[NSFileManager defaultManager] URLsForDirectory:inDomains:] and
URLForDirectory:inDomain:appropriateForURL:create:error: return paths rooted at /Users/<me>/ (not under ~/Library/Containers/<app_id>/Data/...) — i.e. they look like non-sandboxed locations.
However, one important exception: URLForDirectory:... for NSItemReplacementDirectory (temporary/replacement items) does return a path under the helper's container (example: ~/Library/Containers/<app_id>/Data/tmp/TemporaryItems/NSIRD_<helper_name>_hfc1bZ).
This proves the sandbox is active for some FileManager APIs, yet standard directory lookups (Application Support, Documents, Caches, and NSHomeDirectory()) are not being redirected to the container.
What I expect
The helper (which inherits the sandbox and is clearly sandboxed) should get container-scoped paths from Cocoa’s FileManager APIs (Application Support, Documents, Caches), i.e. paths under the helper’s container: /Users/<me>/Library/Containers/<app_id>/Data/....
What I tried / diagnostics already gathered
Entitlements & code signature
codesign -d --entitlements :- /path/to/Helper.app/Contents/MacOS/Helper
# shows com.apple.security.app-sandbox = true and com.apple.security.inherit = true
Runtime checks (Objective-C++ inside helper):
extern "C" int sandbox_check(pid_t pid, const char *op, int flags);
NSLog(@"entitlement_check = %d", entitlement_check()); // SecStaticCode check
NSLog(@"env_variable_check = %d", (getenv("APP_SANDBOX_CONTAINER_ID") != NULL));
NSLog(@"runtime_sandbox_check = %d", sandbox_check(getpid(), nullptr, 0));
NSLog(@"NSHomeDirectory = %s", NSHomeDirectory());
NSArray *urls = [[NSFileManager defaultManager]
URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
NSLog(@"URLsForDirectory: %@", urls);
Observed output:
entitlement_check = 1
env_variable_check = 0
runtime_sandbox_check = 1
NSHomeDirectory = /Users/<me>
URLsForDirectory: ( "file:///Users/<me>/Library/Application%20Support/..." )
Temporary/replacement directory (evidence sandbox active for some APIs):
NSURL *tmpReplacement = [[NSFileManager defaultManager]
URLForDirectory:NSItemReplacementDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:&err];
NSLog(@"NSItemReplacementDirectory: %@", tmpReplacement.path);
Observed output (example):
/Users/<me>/Library/Containers/<app_id>/Data/tmp/TemporaryItems/NSIRD_<helper_name>_hfc1bZ
Other facts
Calls to NSHomeDirectory() and URLsForDirectory: are made after main() to avoid "too early" initialization problems.
Helper is placed in Contents/MacOS (not Contents/Library/LoginItems).
Helper is a non-GUI helper binary launched by the main app (not an XPC service).
macOS version: Sequoia 15.6
Questions
Why do NSHomeDirectory() and URLsForDirectory: return the real /Users/<me>/... paths in a helper process that is clearly sandboxed (entitlement + runtime enforcement), while NSItemReplacementDirectory returns a container-scoped temporary path?
Is this behavior related to how the helper is packaged or launched (e.g., placement in Contents/MacOS vs Contents/Library/LoginItems, or whether it is launched with posix_spawn/fork+exec vs other APIs)?
Are there additional entitlements or packaging rules required for a helper that inherits sandbox to have Cocoa directory APIs redirected to the container (for Application Support, Documents, Caches)?
*Thanks in advance — I can add any requested logs
Hello everybody!
I'm currently working on a Bluetooth Low Energy Sync that is using BGTaskScheduler & successfully running periodically in the Background on iOS 26. I did watch this years WWDC Session 227 (Finish tasks in the background) & follow the recommendations as suggested.
Currently, the App is only using 37 Mb (iPhone 12 mini) & no Location or other services are running in Background.
However, when opening Safari & scrolling through some webpages, the App is killed because of "Terminated due to memory issue". I profiled the App & followed advice when it comes to reducing the memory footprint of the App. Are there any additional steps I can take to prevent the App being killed? Are there any recommendations for periodically scheduled Tasks when it comes to the Interval? Do more frequent Tasks (30min compared to one or two hours) have any impact? I tried many different schedules but none seem to make a difference.
From my observation, the App is first suspended & eventually killed because of the Memory Pressure. Any hints, suggestions or recommendations are highly appreciated!
Thanks a lot for the support!
I'm trying to launch a command line app from my objective C application (sandboxed) using NSTask and I keep getting "launch path not accessible"
Here is the path:
[task setLaunchPath:@"/usr/local/bin/codeview"];
I have set the appropriate attributes for codeview and it is working perfectly when I use it from the command line and /usr/local/bin IS in the $PATH
I know I have NSTask configured correctly because this WILL work:
[task setLaunchPath:@"/usr/bin/hexdump"];
With the exception being that I'm using a command already in /usr/bin. But I can't copy codeview into /usr/bin due to SIPS.
I've tried moving codeview to various other non-SIPS protected locations all to no avail. Must all NSTask commands come from /usr/bin? Where might I put codeview so that it can be launched.
Today I'm going to use an older computer and disable SIPS to put my command in /usr/bin and see if that works. If it does. I will do it on my main machine.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Entitlements
Objective-C
Command Line Tools
App Sandbox
On MacOS 26 Tahoe, we are getting a background warning message stating, “App is running in the background…”
Is this expected behavior on the new OS?
Thanks
Asutos
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Dear Apple Support Team,
My app, io.cylonix.sase, has a BGAppRefreshTask (io.cylonix.sase.ios.refresh) that is canceled by dasd ~9ms after submission from a Network Extension. Please help identify the cause and suggest a solution.
App Details:
App ID: io.cylonix.sase
iOS Version: 17.1.1 (iPhone Xs Max)
Network Extension: saseWgNetworkExtension with packet-tunnel-provider entitlement
Use Case: VPN app; Network Extension records file receipts in shared group UserDefaults and schedules BGAppRefreshTask to wake the main app.
App Usage: High (frequently used)
System State: Sufficient resources (not low on battery or memory)
Issue:
The task is submitted but canceled immediately with priority 10. It has never run, so rate-limiting is not an issue.
`
debug 22:09:37.952749-0700 dasd Best binding found for evaluator 0x16d541720: <private>
debug 22:09:37.954483-0700 dasd Invoking selector backgroundTaskSchedulerPermittedIdentifiersWithContext:tableID:unitID:unitBytes: on <LSApplicationRecord 0x724844650>
default 22:09:37.955563-0700 dasd CANCELED: bgRefresh-io.cylonix.sase.ios.refresh:ABDAFA at priority 10 <private>!
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Background Tasks
Network Extension
I am building an app that uses the SMAppService to register a LaunchDaemon that is bundled with my .app. I've got a priming flow created which walks the user through approving the service so that it will start on login.
However, I need to also be able to upgrade this background service if the user updates the app. To do this, I think I need to call unregisterAndReturnError and then registerAndReturnError.
From my testing, this seems to work correctly, but I have a concern. Will the user ever be prompted to re-authorize the LaunchDaemon that I am registering? If so, under what circumstances will that happen, and what does it look like (so that I can guide the user through it)?
What’s the recommended way to recursively walk through a directory tree using File Coordination? From what I understand, coordinating a read of a directory only performs a “shallow” lock; this would mean that I’d need to implement the recursive walk myself rather than use FileManager.enumerator(at:includingPropertiesForKeys:options:errorHandler:) plus a single NSFileCoordinator.coordinate(with:queue:byAccessor:) call.
I’m trying to extract information from all files of a particular type, so I think using NSFileCoordinator.ReadingOptions.immediatelyAvailableMetadataOnly on each file before acquiring a full read lock on it (if it’s the right file type) would make sense. Am I on the right track?
Hello,
I have a few questions regarding the documentation here:
Can this method described in the article be built with Xcode 26 and run on iOS 26? Or is it restricted to run only on iOS 26, since AppExtensionPoint appears to be available starting from iOS 26?
Does this approach allow two apps under the same Team ID to communicate with each other?
Does this approach also allow two apps under different Team IDs to communicate with each other?
Is it mandatory to implement EXAppExtensionBrowserViewController and obtain user consent before using this method to exchange information?
In our implementation, we followed the documentation. Inside EXAppExtensionBrowserViewController, we were able to see the Generic Extension from another app and enabled the permission.
However, we still get the following error:
Failed to connect: Error Domain=NABUExtensionConnector Code=1
"No matching extension found"
UserInfo={NSLocalizedDescription=No matching extension found}
Could someone clarify whether this is expected behavior, or if we are missing an additional configuration step?
Thanks in advance!
I have BGProcessingTask & BGAppRefreshTask working fine. The main purpose of my use of BGProcessingTask is to upload a file to AWS S3 using multipart/form-data. I have found that any file above about 2.5MB times out after running almost four minutes. If I run the same RESTful api using curl or Postman, I can upload a 25MB file in 3 seconds or less.
I have tried to deliberately set .earliestBeginDate to 01:00 or 02:00 local time on the iPhone, but that does not seem to help.
I use the delegate (yes, I am writing in Objective C) - URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: and find that the iOS system uploads about 140kB every 15 seconds or so.
I am looking for recommendations or insight into how I might enable uploads of 25MB files. I would be happy it I could do just one a day for my use case.
I provide code on how I set up the NSURLSession and NSURLSessionDownloadTask, as it is my guess that if there is something that needs to be modified it is there.
I have to believe there is a solution for this since I read in many posts here and in StackOverflow how developers are using this functionality for uploading many, many files.
NSURLSessionConfiguration *sConf = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:bkto.taskIdentifier];
sConf.URLCache = [NSURLCache sharedURLCache];
sConf.waitsForConnectivity = YES;
sConf.allowsCellularAccess = NO;
sConf.networkServiceType = NSURLNetworkServiceTypeVideot;
sConf.multipathServiceType = NSURLSessionMultipathServiceTypeNone;
sConf.discretionary = YES;
sConf.timeoutIntervalForResource = kONEHOURINTERVAL;
sConf.timeoutIntervalForRequest = kONEMINUTEINTERVAL;
sConf.allowsExpensiveNetworkAccess = NO ;
sConf.allowsConstrainedNetworkAccess = NO;
sConf.sessionSendsLaunchEvents = YES;
myURLSession = [NSURLSession sessionWithConfiguration:sConf delegate:self delegateQueue:nil];
And then later in the code...
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:pth]];
request.HTTPMethod = kHTTPPOST;
request.HTTPBody = [NSData my body data];
request.timeoutInterval = 60;
[request setValue:@"*/*" forHTTPHeaderField:@"Accept"];
[request setValue:@"en-us,en" forHTTPHeaderField:@"Accept-Language"];
[request setValue:@"gzip, deflate, br" forHTTPHeaderField:@"Accept-Encoding"];
[request setValue:@"ISO-8859-1,utf-8" forHTTPHeaderField:@"Accept-Charset"];
[request setValue:@"600" forHTTPHeaderField:@"Keep-Alive"];
[request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"];
NSString *contType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",bnd];
[request setValue:contType forHTTPHeaderField:@"Content-Type"];
[request addValue:[NSString stringWithFormat:@"%lu",(unsigned long)myData.length] forHTTPHeaderField:@"Content-Length"];
and here are a few lines from my logs to show the infrequent multi-part uploads of only small chunks of data by the iOS system:
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 393,216
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 393,216
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:27 2025
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 524,288
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:42 2025
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 655,360
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: task = BackgroundDownloadTask <76A81A80-4703-4686-8742-A0048EB65108>.<2>, time Fri Mar 7 16:25:56 2025
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: bytesSent = 131,072
-[BKSessionManager URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:]: totalBytesSent = 786,432
Hello,
I have a question regarding the behavior of BGProcessingTaskRequest when the app is force-quit by the user via the App Switcher.
Based on common understanding and various discussions — including the following Apple Developer Forum threads:
Waking up an iOS app after app is … | Apple Developer Forums
Will BGAppRefreshTaskRequest will … | Apple Developer Forums
Background fetch after app is forc… | Apple Developer Forums
…it is widely understood that iOS prevents background execution (such as background fetch, push notifications, or BGTaskScheduler) after a user force-quits an app via the App Switcher.
However, in my app, I have observed that a scheduled BGProcessingTaskRequest still executes even after the app has been explicitly terminated via App Switcher. The task is scheduled using submit(_:error:), and it is clearly running some time after the app has been closed by the user.
That said, the task does run, but it appears to operate under tighter constraints — for example, it may be allowed to run for a shorter duration, and network requests appear to be more restricted compared to when the app is not force-quit.
My questions are:
Are there any documented or undocumented exceptions that allow this kind of behavior after force-quit?
Could this be a bug or a behavior change in recent iOS versions? (I am observing this on iOS 18.3, 18.4, and 18.5)
Any insights, experiences, or clarifications from Apple engineers or fellow developers would be greatly appreciated.
Thank you!
Hello,
https://developer.apple.com/forums/thread/802443
https://developer.apple.com/documentation/servicemanagement/updating-helper-executables-from-earlier-versions-of-macos
https://developer.apple.com/documentation/ServiceManagement/updating-your-app-package-installer-to-use-the-new-service-management-api#Run-the-sample-launch-agent
Read these.
Earlier we had a setup with SMJobBless, now we have migrated to SMAppService.
Everything is working fine, the new API seems easier to manage, but we are having issues with updating the daemon.
I was wondering, what is the right process for updating a daemon from app side?
What we are doing so far:
App asks daemon for version
If version is lower than expected:
daemon.unregister(), wait a second and daemon.register() again.
The why?
We have noticed that unregistering/registering multiple times, of same daemon, can cause the daemon to stop working as expected. The daemon toggle in Mac Settings -> Login Items & Extensions can be on or off, but the app can still pickup daemon running, but no daemon running in Activity monitor. Registration/unregistration can start failing and nothing helps to resolve this, only reseting with sfltool resetbtm and a restart seems to does the job. This is usually noticeable for test users, testing same daemon version with different app builds.
In production app, we also increase the bundle version of daemon in plist, in test apps we - don't.
I haven't found any sources of how the update of pre-bundled app daemon should work.
Initial idea is register/unregister, but from what I have observed, this seems to mess up after multiple registrations.
I have a theory, that sending the daemon a command to kill itself after app update, would load the latest daemon.
Also, I haven't observed for daemon, with different build versions to update automatically.
What is the right way to update a daemon with SMAppService setup?
Thank you in advance.
Hi,
I built an Electron app that uses puppeteer-cluster to open a bundled version of Chrome. Everything works before packaging/signing with electron builder. Transporter does not report any issues and the app opens in TestFlight.
the Chrome.app is signed separately before running builder
hardenedRuntime = false
However, a permission error occurs when cluster attempts to launch Chrome:
Error: Unable to launch browser, error message: Failed to launch the browser process!
[0601/152740.225314:ERROR:bootstrap.cc(65)] bootstrap_check_in org.chromium.crashpad.child_port_handshake.9915.63117.BUEXLMXFWPLCEONM: Permission denied (1100)
[0601/152740.226091:ERROR:file_io.cc(94)] ReadExactly: expected 4, observed 0
[0601/152740.229808:ERROR:bootstrap.cc(65)] bootstrap_check_in org.chromium.crashpad.child_port_handshake.9913.63115.VVKELOQUCWUYPFMQ: Permission denied (1100)
[0601/152740.230244:ERROR:file_io.cc(94)] ReadExactly: expected 4, observed 0
[9911:45571:0601/152740.506968:ERROR:named_platform_channel_mac.cc(44)] bootstrap_check_in com.google.chrome.for.testing.apps.52995c87946bbcc94fc9a27df1478a13: Permission denied (1100)
[9911:62467:0601/152740.507564:FATAL:mach_port_rendezvous.cc(281)] Check failed: kr == KERN_SUCCESS. bootstrap_check_in com.google.chrome.for.testing.MachPortRendezvousServer.9911: Permission denied (1100)
at Cluster.<anonymous> (/Applications/MyApp.app/Contents/Resources/app.asar/node_modules/puppeteer-cluster/dist/Cluster.js:119:23)
at Generator.throw (<anonymous>)
at rejected (/Applications/MyApp.app/Contents/Resources/app.asar/node_modules/puppeteer-cluster/dist/Cluster.js:6:65)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
I'm wondering if it's an issue with entitlements, or something more.
The entitlements.mas.plist (aside from identifiers):
com.apple.security.app-sandbox
com.apple.security.cs.allow-jit
com.apple.security.cs.allow-unsigned-executable-memory
com.apple.security.cs.allow-dyld-environment-variables
com.apple.security.network.client
com.apple.security.network.server
com.apple.security.files.user-selected.read-write
com.apple.security.cs.disable-executable-page-protection
com.apple.security.files.user-selected.executable
I've spent many hours searching for a solution. Any help or insight would be greatly appreciated.
Topic:
App & System Services
SubTopic:
Processes & Concurrency