简体   繁体   中英

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM