1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

iOS: Fix building with JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK option

This also fixes an issue where endBackgroundTask wasn't guaranteed to be
called after suspended() completed. According to the docs,
endBackgroundTask must be called after the task completes.
This commit is contained in:
reuk 2025-09-25 19:52:03 +01:00 committed by Tom Poole
parent f863f16f5b
commit ce737946f0

View file

@ -63,6 +63,46 @@ namespace juce
} }
}; };
/* Each successful call to beginBackgroundTask must be balanced
by a call to endBackgroundTask.
*/
class TaskHandle
{
public:
TaskHandle() = default;
explicit TaskHandle (UIBackgroundTaskIdentifier t)
: task (t) {}
~TaskHandle()
{
if (task != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:task];
}
TaskHandle (TaskHandle&& other) noexcept
{
swap (other);
}
TaskHandle& operator= (TaskHandle&& other) noexcept
{
TaskHandle { std::move (other) }.swap (*this);
return *this;
}
TaskHandle (const TaskHandle&) = delete;
TaskHandle& operator= (const TaskHandle&) = delete;
private:
void swap (TaskHandle& other) noexcept
{
std::swap (other.task, task);
}
UIBackgroundTaskIdentifier task = UIBackgroundTaskInvalid;
};
struct SceneUtils struct SceneUtils
{ {
// This will need to become more sophisticated to enable support for multiple scenes // This will need to become more sophisticated to enable support for multiple scenes
@ -80,20 +120,20 @@ namespace juce
appBecomingInactiveCallbacks.getReference (i)->appBecomingInactive(); appBecomingInactiveCallbacks.getReference (i)->appBecomingInactive();
} }
static void sceneDidEnterBackground() template <typename Self>
static void sceneDidEnterBackground ([[maybe_unused]] Self* s)
{ {
if (auto* app = JUCEApplicationBase::getInstance()) if (auto* app = JUCEApplicationBase::getInstance())
{ {
#if JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK #if JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK
appSuspendTask = [application beginBackgroundTaskWithName:@"JUCE Suspend Task" expirationHandler:^{ s->appSuspendTask = TaskHandle { [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"JUCE Suspend Task"
if (appSuspendTask != UIBackgroundTaskInvalid) expirationHandler:^{ s->appSuspendTask = {}; }] };
{
[application endBackgroundTask:appSuspendTask];
appSuspendTask = UIBackgroundTaskInvalid;
}
}];
MessageManager::callAsync ([app] { app->suspended(); }); MessageManager::callAsync ([app, s]
{
app->suspended();
s->appSuspendTask = {};
});
#else #else
app->suspended(); app->suspended();
#endif #endif
@ -112,10 +152,17 @@ namespace juce
API_AVAILABLE (ios (13.0)) API_AVAILABLE (ios (13.0))
@interface JuceAppSceneDelegate : NSObject<UIWindowSceneDelegate> @interface JuceAppSceneDelegate : NSObject<UIWindowSceneDelegate>
{
@public
TaskHandle appSuspendTask;
}
@end @end
@implementation JuceAppSceneDelegate @implementation JuceAppSceneDelegate
SharedResourcePointer<WindowSceneTracker> windowSceneTracker; {
SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
}
- (void) scene: (UIScene*) scene - (void) scene: (UIScene*) scene
willConnectToSession: (UISceneSession*) session willConnectToSession: (UISceneSession*) session
options: (UISceneConnectionOptions*) connectionOptions options: (UISceneConnectionOptions*) connectionOptions
@ -144,7 +191,7 @@ SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
- (void) sceneDidEnterBackground: (UIScene*) scene - (void) sceneDidEnterBackground: (UIScene*) scene
{ {
SceneUtils::sceneDidEnterBackground(); SceneUtils::sceneDidEnterBackground (self);
} }
- (void) sceneWillEnterForeground: (UIScene*) scene - (void) sceneWillEnterForeground: (UIScene*) scene
@ -167,7 +214,8 @@ SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate> @interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
#endif #endif
{ {
UIBackgroundTaskIdentifier appSuspendTask; @public
TaskHandle appSuspendTask;
std::optional<ScopedJuceInitialiser_GUI> initialiser; std::optional<ScopedJuceInitialiser_GUI> initialiser;
} }
@ -216,13 +264,13 @@ SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
@end @end
@implementation JuceAppStartupDelegate @implementation JuceAppStartupDelegate
{
NSObject* _pushNotificationsDelegate; NSObject* _pushNotificationsDelegate;
}
- (id) init - (id) init
{ {
self = [super init]; self = [super init];
appSuspendTask = UIBackgroundTaskInvalid;
#if JUCE_PUSH_NOTIFICATIONS #if JUCE_PUSH_NOTIFICATIONS
[UNUserNotificationCenter currentNotificationCenter].delegate = self; [UNUserNotificationCenter currentNotificationCenter].delegate = self;
@ -260,7 +308,7 @@ SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
- (void) applicationDidEnterBackground: (UIApplication*) application - (void) applicationDidEnterBackground: (UIApplication*) application
{ {
SceneUtils::sceneDidEnterBackground(); SceneUtils::sceneDidEnterBackground (self);
} }
- (void) applicationWillEnterForeground: (UIApplication*) application - (void) applicationWillEnterForeground: (UIApplication*) application