Unable to load SwiftUI view in MacPlugin(a shared protocol between Appkit + UIKit) for Mac Catalyst app
Long story short, my usecase is to include Status bar menu in Mac catalyst app, for that I need to access Appkit library. Thanks to shared protocol approach I can include both Appkit & UIkit together in catalyst app, I was able to load NSStatubar as long as it loads default NSMenuItem but when I assigned Custom SwiftUI view to NSMenuItem, the status bar doesn't show up at all.
Here is the code how I load the plugin in Appdelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let macPlugin = AppKitContainer.loadPlugin()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let macPlugin = macPlugin {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
macPlugin.loadStatusMenu()
}
}
return true
}
}
here is how I load the status bar with default nsmenuitem
class MacPlugin: NSObject, Plugin {
var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
var menu = NSMenu()
var contentMenuItemView = NSMenuItem.init()
//load default nsmenuitem which works
func loadStatusMenu() {
statusBarItem.button?.title = "search"
menu.addItem(NSMenuItem(title: "Quit Silicon Info", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
statusBarItem.menu = menu
}
}
Output https://i.stack.imgur.com/v4pYO.png
here is how I'm trying to load SwiftUI view in status bar(basically replaced default menu item with swiftui view)
import AppKit
class MacPlugin: NSObject, Plugin {
var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
var menu = NSMenu()
var contentMenuItemView = NSMenuItem.init()
//load swiftui in nsmenuitem doesn't work
func loadStatusMenuWithSwiftUIView() {
statusBarItem.button?.title = "search"
let view = NSHostingView.init(rootView: Text.init("Hello world")) //SwiftUI view
view.frame = NSRect(x: 0, y: 0, width: 292, height: 633)
contentMenuItemView.view = view
menu.addItem(contentMenuItemView)
statusBarItem.menu = menu
}
}
Output: No status bar shown
Based on debugging,method doesnt get called and it has something to do with NSHostingView. There are no errors in console.
Any help is appreciated.
Solution 1:
This isn’t possible. IIRC your AppKit bundle only has access to the frameworks your main (Catalyst) app has loaded, which includes UIKit, AppKit, and a UIKit-compatible version of SwiftUI. NSHostingView
is defined in the AppKit-compatible version of SwiftUI, which is a separate framework and (AFAIK) is not accessible from your Catalyst app.
You could instead create a separate Mac/AppKit app, which you then bundle with your Catalyst app. This bundled app can remain running even when the Catalyst parent app is not, which is how most status bar apps work so arguably this is a better solution. I wrote a blog post about how to do this, including a sample project.