I have a Mac Catalyst app that's essentially a one-window app, but I added multi-window support (using scenes) to allow opening a second window for one function, which a small portion of users will use. Now Apple has rejected the app because with multi-window support, the app doesn't quit when a user clicks the red button at the top of the main window. One solution is to provide a menu item to reopen it, but I think it would be more intuitive for users if the app simply quit as it did before.
I found a similar problem on the Apple forums and am trying to implement the provided solution. Using this tutorial that provides more setup instructions, I have added a macOS bundle as a new target, embedded that into the iOS target, and added this class to the bundle:
#import "AppKitBridge.h"
@implementation AppKitBridge
@synthesize application;
@synthesize window;
- (id)init {
NSLog(@"AppKitBridge init");
self = [super init];
self.application = [NSApplication sharedApplication];
self.window = [[self.application windows] firstObject];
if (self.window) {
self.application.delegate = self;
self.window.delegate = self;
} else {
NSLog(@"AppKitBridge error: window is nil");
}
return self;
}
- (void)test {
NSArray *windows = NSApplication.sharedApplication.windows;
for (NSWindow *window in windows) {
NSLog(@"AppKitBridge window: %@", window);
}
}
- (void)applicationDidUpdate:(NSNotification *)notification {
NSLog(@"AppKitBridge applicationDidUpdate");
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
NSLog(@"AppKitBridge applicationShouldTerminateAfterLastWindowClosed");
return TRUE;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
NSLog(@"AppKitBridge applicationShouldTerminate");
return TRUE;
}
@end
Then in viewDidLoad of the initial view controller of the iOS app, I call this method to load the bundle:
- (void)enableAppKit {
NSString *pluginPath = [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:@"AppKit.bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:pluginPath];
[bundle load];
NSObject *appKit = [[[bundle classNamed:@"AppKitBridge"] alloc] init];
[appKit performSelector:@selector(test) withObject:nil afterDelay:0];
}
When I run the app, the console shows the AppKitBridge init
, AppKitBridge window
and AppKitBridge applicationDidUpdate
lines. So it seems like the overall setup is working. But when I click the red window button, it does not show the AppKitBridge applicationShouldTerminateAfterLastWindowClosed
or AppKitBridge applicationShouldTerminate
lines, and the app does not quit.
Should this do what I'm expecting, and if so, what am I missing in the setup?
The problem is this line:
NSObject *appKit = [[[bundle classNamed:@"AppKitBridge"] alloc] init];
Your appKit
object is a local variable so your AppKitBridge instance goes out of existence one line later. You need this object to persist if it is to function as the app/window delegate. Assign it to an instance property of some persistent object.