I\'m working on an action extension for an app which prepares some data for the user and then uses MailCore2 to send this information to a SMTP server. Preparing data is done ve
It seems like you can't schedule long running running tasks in background from an extension.Refer here(Some APIs Are Unavailable to App Extensions)
Among the solutions you suggested,my suggestion would be to try using silent push notifications ,you can call an api at the preparing data stage,then sent a silent push from server and perform the background task when the silent push arrives.
Judging from your response, your difficulties is that you need to allow background activities. You can do that by following a tutorial such as this one.
The most useful solution is using push notifications. The solution I used in my own application:
func applicationWillEnterForeground(_ application: UIApplication) {
inside AppDelegate
.For example,
@UIApplicationMain
class AppDelegate: UIResponder {
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if UIApplication.shared.applicationState != .active {
doFetch(completionHandler: completionHandler)
} else {
// foreground here
completionHandler(UIBackgroundFetchResult.noData)
}
}
func application(_ application: UIApplication,
performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
doFetch(completionHandler: completionHandler)
}
private func doFetch(completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
sendTheRequestToWakeApp()
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.endBackgroundTask()
}
/// do work here
completionHandler(UIBackgroundFetchResult.noData)
}
private func endBackgroundTask() {
print("Background task ended.")
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
private func sendTheRequestToWakeApp() {
/// Implement request using native library or Alamofire. etc.
}
}
on server side use simple time or loop.
Disadvantages,
Don't forget to setup the project:
After many tests and failures, I found the following solution to execute a long performing task in the background of an extension. This works as expected, even if the extension is already finished:
func performTask()
{
// Perform the task in background.
let processinfo = ProcessInfo()
processinfo.performExpiringActivity(withReason: "Long task") { (expired) in
if (!expired) {
// Run task synchronously.
self.performLongTask()
}
else {
// Cancel task.
self.cancelLongTask()
}
}
}
This code uses ProcessInfo.performExpiringActivity() to execute the task in another thread. It’s important that the task in performLongTask()
is executed synchronously. When the end of the block is reached, the thread will terminate and end the execution of your task.
A similar approach is also working in the main app. It's described in detail in a small summary for background tasks in iOS.