Yes, that works.
Discovered if not sandbox app, then the main app's UserDefaults can be read by CFPreferencesCopyAppValue in NSDockTilePlugin.
In both cases, this is reading ~/Library/Preferences/<BundleID>.plist. If similar plist exists in the ~/Library/Containers/... it is not used. Is there a way the main app can check and read if there is a sandboxed version of the plist?
Is there no way to communicate to the NSDockTilePlugin from the main app with notifications? This way I don't need the sandbox exception.
Unrelated, but a deal breaker, in the same NSDockTilePlugIn class implementing func dockMenu() -> NSMenu? {} does display a dynamically generated NSMenu. However NsMenuItems' action: #selector(selectItem(:)) and @objc func selectItem( sender: NSMenuItem) { /* never called */ } doesn't fire. Instead the NSDockTilePlugIn plugin is reloaded. How do I capture the NSMenuItem.action?