How can you force cancel a task that doesn't need cleanup and doesn't check for cancellation?
If this cannot be done, would this be a useful addition to Swift?
Here is the situation:
The async method doesn't check for cancellation since it is not doing anything repetively (for example in a loop). For example, the method may be doing "try JSONDecoder().decode(Dictionary<String, ...>.self, from: data)" where data is a large amount.
The method doesn't need cleanup.
I would like the force cancellation to throw an error. I am already handling errors for the async method.
My intended situation if that the user request the async method to get some JSON encoded data, but since it is taking longer that they are willing to wait, they would tap a cancellation button that the app provides.
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
If I create a BGContinuedProcessingTaskRequest, register it, and then "do work" within it appropriately reporting progress, and before my task has finished doing all the work it had to do, its expirationHandler triggers...
does the task later try again?
Or does it lose the execution opportunity until the app is next re-launched to the foreground?
In my testing, I never saw my task execute again once expired (which suggests the latter?).
I was able to easily force this expiry by starting my task, backgrounding my app, then launching the iOS Camera App. My example is just using test code inspired from https://developer.apple.com/documentation/backgroundtasks/performing-long-running-tasks-on-ios-and-ipados
let request = BGContinuedProcessingTaskRequest(identifier: taskIdentifier, title: "Video Upload", subtitle: "Starting Upload")
request.strategy = .queue
BGTaskScheduler.shared.register(forTaskWithIdentifier: taskIdentifier, using: nil) { task in
guard let task = task as? BGContinuedProcessingTask else { return }
print("i am a good task")
var wasExpired = false
task.expirationHandler = {
wasExpired = true
}
let progress = task.progress
progress.totalUnitCount = 100
while !progress.isFinished && !wasExpired {
progress.completedUnitCount += 1
let formattedProgress = String(format: "%.2f", progress.fractionCompleted * 100)
task.updateTitle(task.title, subtitle: "Completed \(formattedProgress)%")
sleep(1)
}
if progress.isFinished {
print ("i was a good task")
task.setTaskCompleted(success: true)
} else {
print("i was not a good task")
task.setTaskCompleted(success: false)
}
}
try? BGTaskScheduler.shared.submit(request)
Apologies if this is clearly stated somewhere and I'm missing it.
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?
When the application is inactive and the system is either in sleep mode or locked, does the timer’s tolerance get affected? In other words, will the timer fire with any additional delay compared to its scheduled time under these conditions?
For example, let’s propose an XPC service that can connect to websites. Suppose that I want to connect to Apple.com, microsoft.com, and ibm.com. Can 3 service objects be made between the service and client? Or does the service have to return an ID for each web connection, with the client needing to specify which connection ID along with a command?
Hello im creating an expo module using this new API, but the problem i found currently testing this functionality is that when the task fails, the notification error doesn't go away and is always showing the failed task notification even if i start a new task and complete that one.
I want to implement this module into the production app but i feel like having always the notification error might confuse our users or find it a bit bothersome.
Is there a way for the users to remove this notification?
Best regards!
I have an XPC server running on macOS and want to perform comprehensive performance and load testing to evaluate its efficiency, responsiveness, and scalability. Specifically, I need to measure factors such as request latency, throughput, and how well it handles concurrent connections under different load conditions.
What are the best tools, frameworks, or methodologies for testing an XPC service? Additionally, are there any best practices for simulating real-world usage scenarios and identifying potential bottlenecks?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
Endpoint Security
Instruments
Performance
I am currently developing a macOS app that can show system HUDs in the Notch
Till Sequoia I used to kill the OSDUIHelper process (which displays the default macOS Volume and Brightness control HUDs) - and replaced it with my app's HUDs
But, it is not working on macOS Tahoe anymore as the OSDUIHelper process is no longer there due to the UI changes
Has the process been renamed - or is there any other way to kill the process?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Swift
macOS
SwiftUI
Background Tasks
An XPC service’s process has a system-managed lifecycle: the process is launched on-demand when another process tries to connect to it, and the system can decide to kill it when system resources are low. XPC services can tell the system when they shouldn’t be killed using xpc_transaction_begin/end.
Do extensions created with ExtensionFoundation and/or ExtensionKit have the same behavior?
Regarding the Background Assets capability on iOS:
In the install scenario, resources defined as the "install" type are incorporated into the App Store download progress. Do resources of the "update" type in the update scenario also get incorporated into the App Store download progress in the same way?
If an exception occurs during the download of install-type resources and the download cannot proceed further, will the system no longer actively block users from launching the app and instead enable the launch button?
Currently, if a user has enabled automatic updates on their device, after the app is updated and released on the App Store, will the Background Assets download start immediately once the automatic update completes? Or does Background Assets have its own built-in scheduling logic that prevents it from running concurrently with the automatic update?
Are there any plans to add RBI support (the sending keyword) to the OSAllocatedLock interface? So it could be used with non-sendable objects without surrendering to the unchecked API
After logging in to the main App, turn on screen recording, then switch to the interface of another App to perform operations. After about ten-odd minutes, when returning to the main App, it was found that the app was forcefully quit by the system, and subsequent operations could not be carried out.
I'm using flutter's inappwebview. All functions work on my simulator and phone, but when I submit for review, I get an answer saying infinite loading. How did it happen? I don't know what the problem is.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Hi,
I have requirement in iOS where application needs to run in the background
It can be a simple hello world program running in the background.
could you shed some light on what is the expected behaviour and is it allowed in iOS.
Hi,
I'm trying to create a launch daemon that uses XPC to receive requests from an unprivileged app. Ultimately both components will be written in Go. For now I'm trying to write a PoC in Objective-C to make sure I get everything right, so I'm compiling / signing from the CLI, and writing plist files by hand -- I'm not using XCode.
My current daemon code is pretty much the same as the boilerplate code that XCode generates when creating a new 'XPC Service':
#import <stdio.h>
#include <xpc/xpc.h>
int main(int argc, char *argv[]) {
xpc_rich_error_t error;
dispatch_queue_t queue = dispatch_queue_create("com.foobar.daemon", DISPATCH_QUEUE_SERIAL);
xpc_listener_t listener = xpc_listener_create(
"com.foobar.daemon",
queue,
XPC_LISTENER_CREATE_NONE,
^(xpc_session_t _Nonnull peer) {
xpc_session_set_incoming_message_handler(peer, ^(xpc_object_t _Nonnull message) {
int64_t firstNumber = xpc_dictionary_get_int64(message, "firstNumber");
int64_t secondNumber = xpc_dictionary_get_int64(message, "secondNumber");
// Create a reply and send it back to the client.
xpc_object_t reply = xpc_dictionary_create_reply(message);
xpc_dictionary_set_int64(reply, "result", firstNumber + secondNumber);
xpc_rich_error_t replyError = xpc_session_send_message(peer, reply);
if (replyError) {
printf("Reply failed, error: %s", xpc_rich_error_copy_description(replyError));
}
});
},
&error);
if (error != NULL) {
printf("ERROR: %s\n", xpc_rich_error_copy_description(error));
exit(1);
}
printf("Created listener: %s", xpc_listener_copy_description(listener));
// Resuming the serviceListener starts this service. This method does not return.
dispatch_main();
return 0;
}
I'm compiling, signing and installing my daemon with the following commands:
build_foobar() {
clang -Wall -x objective-c -o com.foobar.daemon poc/main.m
codesign --force --verify --verbose --options=runtime \
--identifier="com.foobar.daemon" \
--sign="Mac Developer: Albin Kerouanton (XYZ)" \
--entitlements=poc/entitlements.plist \
com.foobar.daemon
}
install_foobar() {
sudo cp com.foobar.daemon /Library/PrivilegedHelperTools/com.foobar.daemon
sudo cp poc/com.foobar.daemon.plist /Library/LaunchDaemons/com.foobar.daemon.plist
sudo launchctl bootout system/com.foobar.daemon || true
sudo launchctl bootstrap system /Library/LaunchDaemons/com.foobar.daemon.plist
}
Here's the content of my entitlements.plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>ABCD.com.foobar.daemon</string>
</dict>
</plist>
And finally, here's my launchd plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.foobar.daemon</string>
<key>Program</key>
<string>/Library/PrivilegedHelperTools/com.foobar.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Library/PrivilegedHelperTools/com.foobar.daemon</string>
</array>
<key>RunAtLoad</key>
<false/>
<key>StandardOutPath</key>
<string>/tmp/com.foobar.daemon.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/com.foobar.daemon.err.log</string>
<key>Debug</key>
<true/>
</dict>
</plist>
Whenever I start my service using sudo launchctl start com.foobar.daemon, it exits with the following error message:
ERROR: Unable to activate listener: failed at listener activation with error 1 - Operation not permitted
System logs don't show anything interesting -- they're just repeating the same error message. I tried to add / remove some properties from both the entitlement and the launchd plist file but to no avail.
Any idea what's going wrong?
Issue:
Background downloads using the flutter_downloader package work perfectly in debug mode and release mode when run directly from Xcode (plugged in).
However, when I create an archive build and install the app separately (via TestFlight or direct IPA install), the background download stops working as soon as the app is minimized.
✅ What I’ve already done
Info.plist
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
<string>fetch</string>
<string>processing</string>
<string>audio</string>
<string>push-to-talk</string>
</array>
AppDelegate.swift
import UIKit
import Flutter
import Firebase
import flutter_downloader
import BackgroundTasks
@main
@objc class AppDelegate: FlutterAppDelegate {
static let backgroundChannel = "com.example.app/background_service"
private var backgroundCompletionHandler: (() -> Void)?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
}
if #available(iOS 13.0, *) {
registerBackgroundTask()
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
@available(iOS 13.0, *)
private func registerBackgroundTask() {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.example.app.process_download_queue",
using: nil
) { [weak self] task in
guard let self = self else { return }
self.handleDownloadQueueTask(task: task as! BGProcessingTask)
}
}
@available(iOS 13.0, *)
private func handleDownloadQueueTask(task: BGProcessingTask) {
scheduleNextDownloadTask()
let headlessEngine = FlutterEngine(name: "BackgroundTaskEngine", project: nil, allowHeadlessExecution: true)
headlessEngine.run()
let channel = FlutterMethodChannel(
name: AppDelegate.backgroundChannel,
binaryMessenger: headlessEngine.binaryMessenger
)
task.expirationHandler = {
channel.invokeMethod("backgroundTaskExpired", arguments: nil)
}
channel.invokeMethod("processNextInBackground", arguments: nil) { result in
task.setTaskCompleted(success: (result as? Bool) ?? false)
}
}
override func application(
_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void
) {
self.backgroundCompletionHandler = completionHandler
super.application(application, handleEventsForBackgroundURLSession: identifier, completionHandler: completionHandler)
}
override func applicationDidEnterBackground(_ application: UIApplication) {
if #available(iOS 13.0, *) {
scheduleNextDownloadTask()
}
}
@available(iOS 10.0, *)
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
if #available(iOS 14.0, *) {
completionHandler([.list, .banner, .badge, .sound])
} else {
completionHandler([.alert, .badge, .sound])
}
}
@available(iOS 10.0, *)
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
completionHandler()
}
}
// MARK: - Helper
@available(iOS 13.0, *)
func scheduleNextDownloadTask() {
let request = BGProcessingTaskRequest(identifier: "com.example.app.process_download_queue")
request.requiresNetworkConnectivity = true
request.requiresExternalPower = false
request.earliestBeginDate = Date(timeIntervalSinceNow: 60)
do {
try BGTaskScheduler.shared.submit(request)
print("BGTask: Download queue processing task scheduled successfully.")
} catch {
print("BGTask: Could not schedule download queue task: \(error)")
}
}
private func registerPlugins(registry: FlutterPluginRegistry) {
if !registry.hasPlugin("FlutterDownloaderPlugin") {
FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
}
}
🧩 Observations
Background download works correctly when:
The app is plugged in and run via Xcode (release/debug)
It stops working when:
The app is installed from an archived build (IPA/TestFlight) and minimized
All entitlements and background modes are properly added.
Provisioning profile includes required background modes.
❓Question
Is there any known limitation or signing difference between Xcode run and archived release builds that could cause URLSession background tasks not to trigger?
Has anyone faced a similar issue when using flutter_downloader on iOS 13+ with BGTaskScheduler or URLSession background configuration?
Any help or working setup example for production/TestFlight would be appreciated.
My app uses SMAppService to register a privileged helper, the helper registers without errors, and can be seen in System Settings. I can get a connection to the service and a remote object proxy, but the helper process cannot be found in Activity Monitor and the calls to the proxy functions seem to always fail without showing any specific errors. What could be causing this situation?
I'm working on a Mac app that receives a process ID via NSXPCConnection, and I'm trying to figure out the best way to determine whether that process is a native macOS app like Safari—with bundles and all—or just a script launched by something like Node or Python. The executable is signed with a Team ID using codesign.
I was thinking about getting the executable's path as one way to handle it, but I’m wondering if there’s a more reliable method than relying on the folder structure.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
Inter-process communication
When I search, it's always people trying to do stuff in the background. I want my app to only do stuff when it is active. And this post https://developer.apple.com/forums/thread/685525 seems to have prevented replies from the start. Which means it's just a documentation page and does not belong in the discussion forums at all, because it prevents all discussion.
I've discovered that a system network extension can communicate with a LaunchDaemon (loaded using SMAppService) over XPC, provided that the XPC service name begins with the team ID.
If I move the launchd daemon plist to Contents/Library/LaunchAgents and swap the SMAppService.daemon calls to SMAppService.agent calls, and remove the .privileged option to NSXPCConnection, the system extension receives "Couldn't communicate with a helper application" as an error when trying to reach the LaunchAgent advertised service. Is this limitation by design?
I imagine it is, but wanted to check before I spent any more time on it.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Service Management
XPC
System Extensions
Network Extension
I am writing an app which mainly is used to update data used by other apps on the device. After the user initializes some values in the app, they almost never have to return to it (occasionally to add a "friend"). The app needs to run a background task at least daily, however, without the user's intervention (or even awareness, once they've given permission). My understanding of background refresh tasks is that if the user doesn't activate the app in the foreground periodically, the scheduled background tasks may never run. If this is true, do I want to use a background processing task instead, or is there a better solution (or have I misunderstood entirely)?
Topic:
App & System Services
SubTopic:
Processes & Concurrency