Processes & Concurrency

RSS for tag

Discover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.

Concurrency Documentation

Posts under Processes & Concurrency subtopic

Post

Replies

Boosts

Views

Activity

Processes & Concurrency Resources
General: DevForums subtopic: App & System Services > Processes & Concurrency Processes & concurrency covers a number of different technologies: Background Tasks Resources Concurrency Resources — This includes Swift concurrency. Service Management Resources XPC Resources Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
166
Jul ’25
Getting Started with SMAppService
I was stuck on a long train journey this weekend, so I thought I’d use that time to write up the process for installing a launchd daemon using SMAppService. This involves a number of deliberate steps and, while the overall process isn’t too hard — it’s certainly a lot better than with the older SMJobBless — it’s easy to accidentally stray from the path and get very confused. If you have questions or comments, start a new thread in the App & System Services > Processes & Concurrency subtopic and tag it with Service Management. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Getting Started with SMAppService This post explains how to use SMAppService to install a launchd daemon. I tested these instructions using Xcode 26.0 on macOS 15.6.1. Things are likely to be slightly different with different Xcode and macOS versions. Create the container app target To start, I created a new project: I choose File > New > Project. In the template picker, I chose macOS > App. In options page, I set the Product Name field to SMAppServiceTest [1]. And I selected my team in the Team popup. And I verified that the Organization Identifier was set to com.example.apple-samplecode, the standard for Apple sample code [1]. I selected SwiftUI in the Interface popup. There’s no requirement to use SwiftUI here; I chose it because that’s what I generally use these days. And None in the Testing System popup. And None in the Storage popup. I then completed the new project workflow. I configured basic settings on the project: In the Project navigator, I selected the SMAppServiceTest project. In the Project editor, I selected the SMAppServiceTest target. At the top I selected Signing & Capabilities. In the Signing section, I made sure that “Automatically manage signing” was checked. And that my team was selected in the Team popup. And that the bundle ID of the app ended up as com.example.apple-samplecode.SMAppServiceTest. Still in the Signing & Capabilities tab, I removed the App Sandbox section. Note It’s possible to use SMAppService to install a daemon from a sandboxed app, but in that case the daemon also has to be sandboxed. That complicates things, so I’m disabling the sandbox for the moment. See Enable App Sandbox, below, for more on this. Next I tweaked some settings to make it easier to keep track of which target is which: At the top, I selected the Build Settings tab. I changed the Product Name build setting from $(TARGET_NAME) to SMAppServiceTest. On the left, I renamed the target to App. I chose Product > Scheme > Manage Schemes. In the resulting sheet, I renamed the scheme from SMAppServiceTest to App, just to keep things in sync. [1] You are free to choose your own value, of course. However, those values affect other values later in the process, so I’m giving the specific values I used so that you can see how everything lines up. Create the daemon target I then created a daemon target: I chose File > New > Target. In the template picker, I chose macOS > Command Line Tool. In the options page, I set the Product Name field to Daemon. And I selected my team in the Team popup. And I verified that the Organization Identifier was set to com.example.apple-samplecode, the standard for Apple sample code. I selected Swift in the Language popup. And verified that SMAppServiceTest was set in the Project popup. I clicked Finish. I configured basic settings on the target: In the Project navigator, I selected the SMAppServiceTest project. In the Project editor, I selected the Daemon target. At the top I selected Signing & Capabilities. In the Signing section, I made sure that “Automatically manage signing” was checked. And that my team was selected in the Team popup. Note The Bundle Identifier field is blank, and that’s fine. There are cases where you want to give a daemon a bundle identifier, but it’s not necessary in this case. Next I tweaked some settings to make it easier to keep track of which target is which: At the top, I selected the Build Settings tab. I changed the Product Name build setting from $(TARGET_NAME) to SMAppServiceTest-Daemon. I forced the Enable Debug Dylib Support to No. IMPORTANT To set it to No, you first have to set it to Yes and then set it back to No. I edited Daemon/swift.swift to look like this: import Foundation import os.log let log = Logger(subsystem: "com.example.apple-samplecode.SMAppServiceTest", category: "daemon") func main() { log.log("Hello Cruel World!") dispatchMain() } main() This just logs a ‘first light’ log message and parks [1] the main thread in dispatchMain(). Note For more about first light log points, see Debugging a Network Extension Provider. [1] Technically the main thread terminates in this case, but I say “parks” because that’s easier to understand (-: Test the daemon executable I selected the Daemon scheme and chose Product > Run. The program ran, logging its first light log entry, and then started waiting indefinitely. Note Weirdly, in some cases the first time I ran the program I couldn’t see its log output. I had to stop and re-run it. I’m not sure what that’s about. I chose Product > Stop to stop it. I then switched back the App scheme. Embed the daemon in the app I added a build phase to embed the daemon executable into app: In the Project navigator, I selected the SMAppServiceTest project. In the Project editor, I selected the App target. At the top I selected Build Phases. I added a new copy files build phase. I renamed it to Embed Helper Tools. I set its Destination popup to Executables. I clicked the add (+) button under the list and selected SMAppServiceTest-Daemon. I made sure that Code Sign on Copy was checked for that. I then created a launchd property list file for the daemon: In the Project navigator, I selected SMAppServiceTestApp.swift. I chose Product > New > File from Template. I selected the Property List template. In the save sheet, I named the file com.example.apple-samplecode.SMAppServiceTest-Daemon.plist. And made sure that the Group popup was set to SMAppServiceTest. And that only the App target was checked in the Targets list. I clicked Create to create the file. In the property list editor, I added two properties: Label, with a string value of com.example.apple-samplecode.SMAppServiceTest-Daemon BundleProgram, with a string value of Contents/MacOS/SMAppServiceTest-Daemon I added a build phase to copy that property list into app: In the Project navigator, I selected the SMAppServiceTest project. In the Project editor, I selected the App target. At the top I selected Build Phases. I added a new copy files build phase. I renamed it to Copy LaunchDaemons Property Lists. I set its Destination popup to Wrapper. And set the Subpath field to Contents/Library/LaunchDaemons. I disclosed the contents of the Copy Bundle Resources build phase. I dragged com.example.apple-samplecode.SMAppServiceTest-Daemon.plist from the Copy Bundle Resources build phase to the new Copy LaunchDaemons Property Lists build phase. I made sure that Code Sign on Copy was unchecked. Register and unregister the daemon In the Project navigator, I selected ContentView.swift and added the following to the imports section: import os.log import ServiceManagement I then added this global variable: let log = Logger(subsystem: "com.example.apple-samplecode.SMAppServiceTest", category: "app") Finally, I added this code to the VStack: Button("Register") { do { log.log("will register") let service = SMAppService.daemon(plistName: "com.example.apple-samplecode.SMAppServiceTest-Daemon.plist") try service.register() log.log("did register") } catch let error as NSError { log.log("did not register, \(error.domain, privacy: .public) / \(error.code)") } } Button("Unregister") { do { log.log("will unregister") let service = SMAppService.daemon(plistName: "com.example.apple-samplecode.SMAppServiceTest-Daemon.plist") try service.unregister() log.log("did unregister") } catch let error as NSError { log.log("did not unregister, \(error.domain, privacy: .public) / \(error.code)") } } IMPORTANT None of this is code is structured as I would structure a real app. Rather, this is the absolutely minimal code needed to demonstrate this API. Check the app structure I chose Product > Build and verified that everything built OK. I then verified that the app’s was structured correctly: I then choose Product > Show Build Folder in Finder. I opened a Terminal window for that folder. In Terminal, I changed into the Products/Debug directory and dumped the structure of the app: % cd "Products/Debug" % find "SMAppServiceTest.app" SMAppServiceTest.app SMAppServiceTest.app/Contents SMAppServiceTest.app/Contents/_CodeSignature SMAppServiceTest.app/Contents/_CodeSignature/CodeResources SMAppServiceTest.app/Contents/MacOS SMAppServiceTest.app/Contents/MacOS/SMAppServiceTest.debug.dylib SMAppServiceTest.app/Contents/MacOS/SMAppServiceTest SMAppServiceTest.app/Contents/MacOS/__preview.dylib SMAppServiceTest.app/Contents/MacOS/SMAppServiceTest-Daemon SMAppServiceTest.app/Contents/Resources SMAppServiceTest.app/Contents/Library SMAppServiceTest.app/Contents/Library/LaunchDaemons SMAppServiceTest.app/Contents/Library/LaunchDaemons/com.example.apple-samplecode.SMAppServiceTest-Daemon.plist SMAppServiceTest.app/Contents/Info.plist SMAppServiceTest.app/Contents/PkgInfo There are a few things to note here: The com.example.apple-samplecode.SMAppServiceTest-Daemon.plist property list is in Contents/Library/LaunchDaemons. The daemon executable is at Contents/MacOS/SMAppServiceTest-Daemon. The app is still built as debug dynamic library (SMAppServiceTest.debug.dylib) but the daemon is not. Test registration I chose Product > Run. In the app I clicked the Register button. The program logged: will register did not register, SMAppServiceErrorDomain / 1 Error 1 indicates that installing a daemon hasn’t been approved by the user. The system also presented a notification: Background Items Added “SMAppServiceTest” added items that can run in the background for all users. Do you want to allow this? Options > Allow > Don’t Allow I chose Allow and authenticated the configuration change. In Terminal, I verified that the launchd daemon was loaded: % sudo launchctl list com.example.apple-samplecode.SMAppServiceTest-Daemon { "LimitLoadToSessionType" = "System"; "Label" = "com.example.apple-samplecode.SMAppServiceTest-Daemon"; "OnDemand" = true; "LastExitStatus" = 0; "Program" = "Contents/MacOS/SMAppServiceTest-Daemon"; }; IMPORTANT Use sudo to target the global launchd context. If you omit this you end up targeting the launchd context in which Terminal is running, a GUI login context, and you won't find any launchd daemons there. I started monitoring the system log: I launched the Console app. I pasted subsystem:com.example.apple-samplecode.SMAppServiceTest into the search box. I clicked “Start streaming”. Back in Terminal, I started the daemon: % sudo launchctl start com.example.apple-samplecode.SMAppServiceTest-Daemon In Console, I saw it log its first light log point: type: default time: 17:42:20.626447+0100 process: SMAppServiceTest-Daemon subsystem: com.example.apple-samplecode.SMAppServiceTest category: daemon message: Hello Cruel World! Note I’m starting the daemon manually because my goal here is to show how to use SMAppService, not how to use XPC to talk to a daemon. For general advice about XPC, see XPC Resources. Clean up Back in the app, I clicked Unregister. The program logged: will unregister did unregister In Terminal, I confirmed that the launchd daemon was unloaded: % sudo launchctl list com.example.apple-samplecode.SMAppServiceTest-Daemon Could not find service "com.example.apple-samplecode.SMAppServiceTest-Daemon" in domain for system Note This doesn’t clean up completely. The system remembers your response to the Background Items Added notification, so the next time you run the app and register your daemon it will be immediately available. To reset that state, run the sfltool with the resetbtm subcommand. Install an Agent Rather Than a Daemon The above process shows how to install a launchd daemon. Tweaking this to install a launchd agent is easy. There are only two required changes: In the Copy Launch Daemon Plists copy files build phase, set the Subpath field to Contents/Library/LaunchAgents. In ContentView.swift, change the two SMAppService.daemon(plistName:) calls to SMAppService.agent(plistName:). There are a bunch of other changes you should make, like renaming everything from daemon to agent, but those aren’t required to get your agent working. Enable App Sandbox In some cases you might want to sandbox the launchd job (the term job to refer to either a daemon or an agent.) This most commonly crops up with App Store apps, where the app itself must be sandboxed. If the app wants to install a launchd agent, that agent must also be sandboxed. However, there are actually four combinations, of which three are supported: App Sandboxed | Job Sandboxed | Supported ------------- | ------------- | --------- no | no | yes no | yes | yes yes | no | no [1] yes | yes | yes There are also two ways to sandbox the job: Continue to use a macOS > Command Line Tool target for the launchd job. Use an macOS > App target for the launchd job. In the first approach you have to use some low-level build settings to enable the App Sandbox. Specifically, you must assign the program a bundle ID and then embed an Info.plist into the executable via the Create Info.plist Section in Binary build setting. In the second approach you can use the standard Signing & Capabilities editor to give the job a bundle ID and enable the App Sandbox, but you have to adjust the BundleProgram property to account for the app-like wrapper. IMPORTANT The second approach is required if your launchd job uses restricted entitlements, that is, entitlements that must be authorised by a provisioning profile. In that case you need an app-like wrapper to give you a place to store the provisioning profile. For more on this idea, see Signing a daemon with a restricted entitlement. For more background on how provisioning profiles authorise the use of entitlements, see TN3125 Inside Code Signing: Provisioning Profiles. On balance, the second approach is the probably the best option for most developers. [1] When SMAppService was introduced it was possible to install a non-sandboxed daemon from a sandboxed app. That option is blocked by macOS 14.2 and later.
0
0
170
Sep ’25
Proper initialization - views, dependencies, laoder and viewcontroller
So i am pretty new to Xcode, but i have been using Python and other language for some while. But I am quite new to the game of view and view control. So it may be that i have over complicated this a bit - and it may be that I have some wrong understanding of the dependencies and appcontroller (that i thought would be a good idea). So here we have a main file we call it app.swift, we have a startupmanager.swift, a appcoordinator and a dependeciescontainer. But it may be that this is either a overkill - or that I am doing it wrong. So my thought was that i had a dependeciecontainer, a appcoordinator for the views and a startupmanager that controll the initialized fetching. I have controlled the memory when i run it - checking if it is higher, lower eg - but it was first when i did my 2 days profile i saw a lot of new errors, like this: Fikser(7291,0x204e516c0) malloc: xzm: failed to initialize deferred reclamation buffer (46). and i also get macro errors, probably from the @Query in my feedview. So my thought was that a depencecie manager and a startupmanager was a good idea together with a app coordinator. But maybe I am wrong - maybe this is not a good idea? Or maybe I am doing some things twice? I have added a lot of prints and debugs for checking. But it seems that it starts off to heavy? import SwiftUI import Combine @MainActor class AppCoordinator: ObservableObject { @Published var isLoggedIn: Bool = false private var authManager: AuthenticationManager = .shared private var cancellables = Set<AnyCancellable>() private let startupManager: StartupManager private let container: DependencyContainer @Published var path = NavigationPath() enum Screen: Hashable, Identifiable { case profile case activeJobs case offers case message var id: Self { self } } init(container: DependencyContainer) { self.container = container self.startupManager = container.makeStartupManager() setupObserving() startupManager.start() print("AppCoordinator initialized!") } private func setupObserving() { authManager.$isAuthenticated .receive(on: RunLoop.main) .sink { [weak self] isAuthenticated in self?.isLoggedIn = isAuthenticated } .store(in: &cancellables) } func userDidLogout() { authManager.logout() path.removeLast(path.count) } func showProfile() { path.append(Screen.profile) } func showActiveJobs() { path.append(Screen.activeJobs) } func showOffers() { path.append(Screen.offers) } func showMessage() { path.append(Screen.message) } @ViewBuilder func viewForDestination(_ destination: Screen) -> some View { switch destination { case .profile: ProfileView() case .activeJobs: ActiveJobsView() case .offers: OffersView() case .message: ChatView() } } @ViewBuilder func viewForJob(_ job: Job) -> some View { PostDetailView( job: job, jobUserDetailsRepository: container.makeJobUserDetailsRepository() ) } @ViewBuilder func viewForProfileSubview(_ destination: ProfileView.ProfileSubviews) -> some View { switch destination{ case .personalSettings: PersonalSettingView() case .historicData: HistoricDataView() case .transactions: TransactionView() case .helpCenter: HelpcenterView() case .helpContract: HelpContractView() } } enum HomeBarDestinations: Hashable, Identifiable { case postJob case jobPosting var id: Self { self } } @ViewBuilder func viewForHomeBar(_ destination: HomeBarView.HomeBarDestinations) -> some View { switch destination { case .postJob: PostJobView() } } } import Apollo import FikserAPI import SwiftData class DependencyContainer { static var shared: DependencyContainer! private let modelContainer: ModelContainer static func initialize(with modelContainer: ModelContainer) { shared = DependencyContainer(modelContainer: modelContainer) } private init(modelContainer: ModelContainer) { self.modelContainer = modelContainer print("DependencyContainer being initialized at ") } @MainActor private lazy var userData: UserData = { return UserData(apollo: Network.shared.apollo) }() @MainActor private lazy var userDetailsRepository: UserDetailsRepository = { return UserDetailsRepository(userData: makeUserData()) }() @MainActor private lazy var jobData: JobData = { return JobData(apollo: Network.shared.apollo) }() @MainActor private lazy var jobRepository: JobRepository = { return JobRepository(jobData: makeJobData(), modelContainer: modelContainer) }() @MainActor func makeUserData() -> UserData { return userData } @MainActor func makeUserDetailsRepository() -> UserDetailsRepository { return userDetailsRepository } @MainActor func makeStartupManager() -> StartupManager { return StartupManager( userDetailsRepository: makeUserDetailsRepository(), jobRepository: makeJobRepository(), authManager: AuthenticationManager.shared, lastUpdateRepository: makeLastUpdateRepository() ) } @MainActor func makeJobData() -> JobData { return jobData } @MainActor func makeJobRepository() -> any JobRepositoryProtocol { return jobRepository } @MainActor private lazy var jobUserData: JobUserData = { return JobUserData(apollo: Network.shared.apollo) }() @MainActor private lazy var jobUserDetailsRepository: JobUserDetailsRepository = { return JobUserDetailsRepository(jobUserData: makeJobUserData()) }() @MainActor func makeJobUserData() -> JobUserData { return jobUserData } @MainActor func makeJobUserDetailsRepository() -> JobUserDetailsRepository { return jobUserDetailsRepository } @MainActor private lazy var lastUpdateData: LastUpdateData = { return LastUpdateData(apollo: Network.shared.apollo) }() @MainActor private lazy var lastUpdateRepository: LastUpdateRepository = { return LastUpdateRepository(lastUpdateData: makeLastUpdateData()) }() @MainActor func makeLastUpdateData() -> LastUpdateData { return lastUpdateData } @MainActor func makeLastUpdateRepository() -> LastUpdateRepository { return lastUpdateRepository } }```
1
0
338
Feb ’25
Why is xpc_connection_set_peer_code_signing_requirement() closing the connection instead of returning XPC_ERROR_PEER_CODE_SIGNING_REQUIREMENT?
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!
1
0
471
Feb ’25
Electron app with Express + Python child processes not running in macOS production build
Hi all, I’ve built an Electron application that uses two child processes: An Express.js server A Python executable (packaged .exe/binary) During the development phase, everything works fine — the Electron app launches, both child processes start, and the app functions as expected. But when I create a production build for macOS, the child processes don’t run. Here’s a simplified snippet from my electron.mjs: import { app, BrowserWindow } from "electron"; import { spawn } from "child_process"; import path from "path"; let mainWindow; const createWindow = () =&gt; { mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: true, }, }); mainWindow.loadFile("index.html"); // Start Express server const serverPath = path.join(process.resourcesPath, "app.asar.unpacked", "server", "index.js"); const serverProcess = spawn(process.execPath, [serverPath], { stdio: "inherit", }); // Start Python process const pythonPath = path.join(process.resourcesPath, "app.asar.unpacked", "python", "myapp"); const pythonProcess = spawn(pythonPath, [], { stdio: "inherit", }); serverProcess.on("error", (err) =&gt; console.error("Server process error:", err)); pythonProcess.on("error", (err) =&gt; console.error("Python process error:", err)); }; app.whenReady().then(createWindow); I’ve already done the following: Configured package.json with the right build settings Set up extraResources / asarUnpack to include the server and Python files Verified both child processes work standalone Questions: What’s the correct way to package and spawn these child processes for macOS production builds? Do I need to move them into a specific location (like Contents/Resources/app.asar.unpacked) and reference them differently? Is there a more reliable pattern for handling Express + Python child processes inside an Electron app bundle? Any insights or working examples would be really appreciated!
2
0
75
Sep ’25
About GCD (Grand Central Dispatch) in an extension.
We are currently developing a VoIP application that supports Local Push extention. I would like to ask for your advice on how the extension works when the iPhone goes into sleep mode. Our App are using GCD (Grand Central Dispatch) to perform periodic processing within the extension, creating a cycle by it. [sample of an our source] class LocalPushProvider: NEAppPushProvider { let activeQueue: DispatchQueue = DispatchQueue(label: "com.myapp.LocalPushProvider.ActiveQueue", autoreleaseFrequency: .workItem) var activeSchecule: Cancellable? override func start(completionHandler: @escaping (Error?) -&gt; Void) { : self.activeSchecule = self.activeQueue.schedule( after: .init(.now() + .seconds(10)), // start schedule after 10sec interval: .seconds(10) // interval 10sec ) { self.activeTimerProc() } completionHandler(nil) } } However In this App that we are confirming that when the iPhone goes into sleep mode, self.activeTimerProc() is not called at 10-second intervals, but is significantly delayed (approximately 30 to 180 seconds). What factors could be causing the timer processing using GCD not to be executed at the specified interval when the iPhone is in sleep mode? Also, please let us know if there are any implementation errors or points to note. I apologize for bothering you during your busy schedule, but I would appreciate your response.
3
0
114
Jun ’25
BGContinuedProcessingTask what's the point?
Hi, This post is coming from frustration of working on using BGContinuedProcessingTask for almost 2 weeks, trying to get it to actually complete in the background after the app is backgrounded. My process will randomlly finish and not finish and have no idea why. I'm properly using and setting task?.progress.totalUnitCount = [some number] task?.progress.completedUnitCount = [increment as processed] I know this, because it all looks propler as long as the app insn't backgrounded. So it's not a progress issue. The task will ALWAYS complete. The device has full power, as it is plugged in as I run from within Xcode. So, it's not a power issue. Yes, the process will take a few minutes, but I thought that is BGContinuedProcessingTask purpose in iOS 26. For long running process that a user could place in the background and leave the app, assuming the process would actually finish. Why bother introducing a feature that only works with short tasks that don't actually need long running time in the first place.
7
0
177
Oct ’25
SMAppService
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.
5
0
174
Nov ’25
LaunchAgent (Mac) as peripheral doesn't show a pairing request.
The same code built in a regular Mac app (with UI) does get paired. The characteristic properties are [.read, .write, .notify, .notifyEncryptionRequired] The characteristic permissions are [.readEncryptionRequired, .writeEncryptionRequired] My service is primary. In the iOS app (central) I try to read the characteristic, but an error is reported: Error code: 5, Description: Authentication is insufficient.
3
0
73
1w
Can we create a bundled non-interactive macOS application which uses CFRunLoop only(instead of using NSApplicationMain to run NSRunLoop)?
I am developing a macOS non-interactive macOS application which does not show any ui. i want to block main thread and do all the work on worker thread . Once done with work in worker thread, want to unblock main thread by exiting event loop to terminate application. Because i dont want to show any UI or use any Foundation/Cocoa functionality, i am thinking of using CFRunLoop to block main thread from exiting until i finish my work in worker thread. When i tried this in a project, I am able to finish work in worker thread after block main thread using CFRunLoop. I also want this application to be a bundled application, which can be launched by double clicking on application bundle . But when i tried it in my xcode project by launching it using double clicking on application bundle, application keeps on toggling/bouncing in the dock menu with a status "Not responding". Although i am able to complete my work in worker thread. import Foundation let runLoop = CFRunLoopGetCurrent() func workerTask() { DispatchQueue.global().async { print("do its work") sleep(5) // do some work print("calling exit event loop") CFRunLoopStop(runLoop) print ("unblocking main thread") } } workerTask () // blocking main thread print ("blocked main thread") CFRunLoopRun() print ("exit") Why i am getting this application bouncing in doc menu behavior ? I tried by using NSApplicationMain instead of CFRunLoop in my project, in that case i didnt get this behavior . Does NSApplicationMain does some extra work before starting NSRunLoop which i am not doing while using CFRunLoop, which is showing this toggling/Bouncing application icon in Dock menu ? or Is this bouncing app icon issue is related to run loop i am using which is CFRunLoop ? Note : If i dont use a bundled application and use a commandline application then i am able to do all steps in worker thread and exit main thread as i wanted after finishing my work . But i need to do all this in application which can be launched using double clicking (bundled applcation). If not by using CFRunLoop, then how can i achive this ? - Create a application which shows no UI and do all work in worker thread while main thread is blocked. Once work is done unblock main thread and exit. And user should be able to launch application using double click the application icon.
3
0
420
Mar ’25
How to get the full process name like Activity Monitor
I'm try to monitor all processes by ES client. But I found the process name is different from the Activity Monitor displayed. As shown in the picture below, there are ShareSheetUI(Pages) and ShareSheetUI(Finder) processes in Activity Monitor, but I can only get the same name ShareSheetUI, I thought of many ways to display the name in parentheses, but nothing worked, so there is a way to display the process name like Activity Monitor?
1
0
459
Jan ’25
Effect of App Nap on Timer
I'm developing a macOS application that tracks the duration of a user's session using a timer, which is displayed both in the main window and in an menu bar extra view. I have a couple of questions regarding the timer's behavior: What happens to the timer if the user closes the application's window (causing the app to become inactive) but does not fully quit it? Does the timer continue to run, pause, or behave in some other way? Will the app nap feature stop the timer when app is in-active state?
1
0
114
Mar ’25
Are XPCSession and XPCListener incomplete(ly documented)?
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?
3
0
954
Feb ’25
Guideline 3.2.1(viii) - Business - Other Business Model Issues - Acceptable
The support URL provided in App Store Connect must direct to a support page with links to a loan services privacy policy. The support page must also reference the lender or lending license. The privacy policy provided in App Store Connect must include references to the lender. The verified email domains associated with your Apple Developer Program account must match domains for the submitting company or partnered financial institution.
0
0
494
Dec ’24
Spawning electron app from deamon process
Hi all, Our company has an application that runs on several machines, this app is launched via a deamon that keeps it alive. One of the feature of this app, is to start a headless electron application to run some tests. When spawning this electron application with the new arm64 OS, we are getting this issue: Silent Test Agent Worker exited with code: 133 [ERROR] [75873:0205/135842.347044:ERROR:mach_port_rendezvous.cc(384)] bootstrap_look_up com.hivestreaming.silenttestagent.MachPortRendezvousServer.1: Permission denied (1100) [ERROR] [75873:0205/135842.347417:ERROR:shared_memory_switch.cc(237)] No rendezvous client, terminating process (parent died?) [ERROR] [75872:0205/135842.347634:ERROR:mach_port_rendezvous.cc(384)] bootstrap_look_up com.hivestreaming.silenttestagent.MachPortRendezvousServer.1: Permission denied (1100) [ERROR] [75872:0205/135842.347976:ERROR:shared_memory_switch.cc(237)] No rendezvous client, terminating process (parent died?) Both application (main app and electron one) are signed and notarized, but it seems that there is some other permission issue. If we run the electron application manually, all runs as expected. I added the crash report as attachment CrashReport.log
2
0
510
Feb ’25
MacOS 26 TestFlight SIGKILLs app when updating
We're developing an Electron app for MacOS App Store. When updating our app through TestFlight, TestFlight prompts "Close This App to Update", and when I click "Continue" our app would be "Terminated" for update. Now this is where things go wrong. On MacOS 15 our app seems to be gracefully terminating (We attached it with lldb and it shows that our app returns with 0 when we click "Continue") which is fine. However for MacOS 26 though, it seems that TestFlight just directly SIGKILLs our app (indicated by lldb), which means that all of our app's child processes are left orphaned. Even worse, our app is singleton, which means that when the app relaunches it fails, because the leftover child processes from the previously SIGKILLed session is still alive, and even if we want to kill those orphaned child processes we can't because our app is sandboxed thus cannot kill processes outside of the current sandbox. We captured output from log stream (app name redacted): 12-02 22:08:16.477036-0800 0x5452     Default     0x5a4a7              677    7    installcoordinationd: [com.apple.installcoordination:daemon] -[IXSCoordinatorProgress setTotalUnitsCompleted:]: Progress for coordinator: [com.our.app/Invalid/[user-defined//Applications/OurApp.app]], Phase: IXCoordinatorProgressPhaseLoading, Percentage: 99.454 123: Attempt to set units completed on finished progress: 214095161 2025-12-02 22:08:16.483056-0800 0x53ba     Default     0x5a5c9              167    0    runningboardd: (RunningBoard) [com.apple.runningboard:connection] Received termination request from [osservice<com.apple.installcoordinationd(274)>:677] on <RBSProcessPredicate <RBSProcessBundleIdentifierPredicate "com.our.app">> with context <RBSTerminateContext| explanation:installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N re portType:None maxTerminationResistance:Absolute attrs:[ 2025-12-02 22:08:16.488651-0800 0x53ba     Default     0x5a5c9              167    7    runningboardd: (RunningBoard) [com.apple.runningboard:ttl] Acquiring assertion targeting system from originator [osservice<com.apple.installcoordinationd(274)>:677] with description <RBSAssertionDescriptor| "installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N" ID:167-677-1463 target:system attributes:[ 2025-12-02 22:08:16.489353-0800 0x53ba     Default     0x5a5c9              167    0    runningboardd: (RunningBoard) [com.apple.runningboard:process] [app<application.com.our.app.485547.485561(501)>:2470] Terminating with context: <RBSTerminateContext| explanation:installcoordinationd app:[com.our.app/Invalid/[user-defined//Applications/OurApp.app]] uuid:A3BC0629-124E-4165-ABB7-1324380FC354 isPlaceholder:N reportType:None maxTerminationResistance:Absolute attrs:[ 2025-12-02 22:10:23.920869-0800 0x5a5a     Default     0x5a4c6              674    14   appstoreagent: [com.apple.appstored:Library] [A95D57D7] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0} 2025-12-02 22:10:32.027304-0800 0x5ae5     Default     0x5a4c7              674    14   appstoreagent: [com.apple.appstored:Library] [BEB5F2FD] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0} 2025-12-02 22:10:36.542321-0800 0x5b81     Default     0x5a4c8              674    14   appstoreagent: [com.apple.appstored:Library] [185B9DD6] Completed with 1 result: <ASDApp: 0xc932a8780>: {bundleID = com.our.app; completedUnitCount = 600; path = /Applications/OurApp.app; installed = 0} The line "Terminating with context" seems suspicious. This line is not seen on MacOS 15, only MacOS 26. Is this documented behavior? If so, how can we handle this?
7
0
190
3d
How to view documentation and example codes for Grand Central Dispatch for C
Hi, I am programming in C and would like to use Grand Central Dispatch for parallel computing (I mostly do physics based simulations). I remember there used to be example codes provided by Apple, but can't find those now. Instead I get the plain documentation. May anyone point me to the correct resources? It will be greatly appreciated. Thanks ☺.
2
0
125
Oct ’25
Issue with Developer App Crashing on iPad Upon Launch
Recently, after updating the Developer app to the latest version, my iPad has been unable to open this app as it crashes immediately upon launch. Prior to the update, the app functioned normally. My device is an 11-inch iPad Pro from 2021, running iPadOS 17.3. I have tried troubleshooting steps such as reinstalling the app and restarting the device, but these actions have not resolved the issue. However, I need to use this specific version of the system, iPadOS 17.3, for software testing purposes and cannot upgrade the system. Other apps on my device work normally without any issues. Is there a solution to this problem? I have attempted to contact the developer support team in China, but they were also unable to provide a resolution. This issue is reproducible 100% of the time on my iPad.
1
0
360
Jan ’25
How to Handle Asynchronous Operations in BGContinuedProcessingTask
I would like to know whether BGContinuedProcessingTaskRequest supports executing asynchronous tasks internally, or if it can only execute synchronous tasks within BGContinuedProcessingTaskRequest? Our project is very complex, and we now need to use BGContinuedProcessingTaskRequest to perform some long-running operations when the app enters the background (such as video encoding/decoding & export). However, our export interface is an asynchronous function, for example video.export(callback: FinishCallback). This export call returns immediately, and when the export completes internally, it calls back through the passed-in callback. So when I call BGTaskScheduler.shared.register to register a BGContinuedProcessingTask, what should be the correct approach? Should I directly call video.export(nil) without any waiting, or should I wait for the export function to complete in the callback? For example: BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.xxx.xxx.xxx.xxx", using: nil) { task in guard let continuedTask = task as? BGContinuedProcessingTask else { task.setTaskCompleted(success: false) return } let scanner = SmartAssetsManager.shared let semaphore = DispatchSemaphore(value: 0) continuedTask.expirationHandler = { logError(items: "xwxdebug finished.") semaphore.signal() } logInfo(items: "xwxdebug start!") video.export { _ in semaphore.signal() } semaphore.wait() logError(items: "xwxdebug finished!") }
3
0
96
Nov ’25
BGContinuedProcessingTask expiring unpredictably
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.
7
0
271
1w
BGContinuedProcessingTask register block not called, submit does not throw an error
I implemented BGContinuedProcessingTask in my app and it seems to be working well for everyone except one user (so far) who has reached out to report nothing happens when they tap the Start Processing button. They have an iPhone 12 Pro Max running iOS 26.1. Restarting iPhone does not fix it. When they turn off the background processing feature in the app, it works. In that case my code directly calls the function to start processing instead of waiting for it to be invoked in the register block (or submit catch block). Is this a bug that's possible to occur, maybe device specific? Or have I done something wrong in the implementation? func startProcessingTapped(_ sender: UIButton) { if isBackgroundProcessingEnabled { startBackgroundContinuedProcessing() } else { startProcessing(backgroundTask: nil) } } func startBackgroundContinuedProcessing() { BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: .main) { @Sendable [weak self] task in guard self != nil else { return } startProcessing(backgroundTask: task as? BGContinuedProcessingTask) } let request = BGContinuedProcessingTaskRequest(identifier: taskIdentifier, title: title, subtitle: subtitle) request.strategy = .fail if BGTaskScheduler.supportedResources.contains(.gpu) { request.requiredResources = .gpu } do { try BGTaskScheduler.shared.submit(request) } catch { startProcessing(backgroundTask: nil) } } func startProcessing(backgroundTask: BGContinuedProcessingTask?) { // FIXME: Never called for this user when isBackgroundProcessingEnabled is true }
8
0
196
19h