File Provider UI extension on macOS

I'm asking this because the documentation is totally contradicting to itself on multiple occasions:

  • Extensions overview page (https://developer.apple.com/app-extensions/) claims it's not supported.
  • At the same time, on FileProviderUI docs page (https://developer.apple.com/documentation/fileproviderui) macOS is listed among another platforms and docs kinda generally suggest it is supported.
  • At the same time, "add new target" dialog in xcode is missing "File Provider UI Extension" template under macOS.
  • At the same time, it's can be easily be done by creating an iOS extension, then swapping SDK to macOS and UIKit APIs to their AppKit counterparts. This way, FileProviderUI actions DO appear in Finder.

Problem is, after clicking the action, UI never appears and here's what i see in Console:

default	pkd	Waiting on thread <private> until Launch Services database seeding is complete.
default	Finder	[d <private>] <PKHost:0x600000c38cc0> Beginning discovery for flags: 1024, point: (null)
default	Finder	[d <private>] <PKHost:0x600000c38cc0> Completed discovery. Final # of matches: 0
error	Finder	nil extension for provider ID (<private>), error: (null)
error	Finder	Action with identifier (<private>) did finish with error (Error Domain=FPUIActionViewControllerErrorDomain Code=1000).
error	Finder	FP Custom action sheet finished with error Error Domain=FPUIActionViewControllerErrorDomain Code=1000 "(null)"
default	pkd	[d <private>] Final plugin count: 0

This is totally confusing, please elaborate.

Replies

Update: Ok, the original problem was missing entitlements. Now it fails with:

default	Finder	+[NSExtensionContext _allowedItemPayloadClasses] not implemented. Setting the allowed payload classes to <private>
default	macmount-actions	+[NSExtensionContext _allowedItemPayloadClasses] not implemented. Setting the allowed payload classes to <private>
error	cfprefsd	Couldn't open parent path due to [2: No such file or directory]
default	macmount-actions	NSApp cache appearance:
-NSRequiresAquaSystemAppearance: 0
-appearance: (null)
-effectiveAppearance: <NSCompositeAppearance: 0x14760ce80
 (
    "<NSAquaAppearance: 0x150811e30>",
    "<NSSystemAppearance: 0x15080cc90>"
)>
default	distnoted	register name: com.apple.nsquiet_safe_quit_give_reason object: com.mycompany.macmount-actions token: 3b0000003b pid: 52332
default	macmount-actions	*** Assertion failure in -[FPUIActionExtensionContainerViewController _configureWithDomainIdentifier:], FPUIActionExtensionContainerViewController.m:129
error	Finder	Action with identifier (<private>) did finish with error (Error Domain=com.apple.ViewBridge Code=14 UserInfo={com.apple.ViewBridge.error.hint=<private>, com.apple.ViewBridge.error.description=NSViewBridgeErrorServiceBootstrap}).
error	Finder	FP Custom action sheet finished with error Error Domain=com.apple.ViewBridge Code=14 "(null)" UserInfo={com.apple.ViewBridge.error.hint=-[NSViewServiceMarshal bootstrap:withReply:] caught NSInternalInconsistencyException 'attempting to send message to non-existent action extension view controller' with backtrace (
    "0   CoreFoundation                      __exceptionPreprocess + 176",
    "1   libobjc.A.dylib                     objc_exception_throw + 60",
    "2   Foundation                          -[NSCalendarDate initWithCoder:] + 0",
    "3   FileProviderUI                      -[FPUIActionExtensionContainerViewController _configureWithDomainIdentifier:] + 164",
    "4   FileProviderUI                      -[FPUIActionExtensionContainerViewController awakeFromRemoteView] + 692",
    "5   ViewBridge                          -[NSViewServiceMarshal _bootstrap:replyData:completion:] + 1828",
    "6   ViewBridge                          -[NSViewServiceMarshal bootstrap:withReply:] + 272",
    "7   CoreFoundation                      __invoking___ + 148",
    "8   CoreFoundation                      -[NSInvocation invoke] + 428",
    "9   CoreFoundation                      -[NSInvocation invokeWithTarget:] + 64",
    "10  ViewBridge                          -[NSVB_ViewServiceImplicitAnimationDecodingProxy forwardInvocation:] + 192",
    "11  CoreFoundation                      ___forwarding___ + 976",
    "12  CoreFoundation                      _CF_forwarding_prep_0 + 96",
    "13  CoreFoundation                      __invoking___ + 148",
    "14  CoreFoundation                      -[NSInvocation invoke] + 428",
    "15  CoreFoundation                      -[NSInvocation invokeWithTarget:] + 64",
    "16  ViewBridge                          -[NSVB_QueueingProxy forwardInvocation:] + 300",
    "17  CoreFoundation                      ___forwarding___ + 976",
    "18  CoreFoundation                      _CF_forwarding_prep_0 + 96",
    "19  CoreFoundation                      __invoking___ + 148",
    "20  CoreFoundation                      -[NSInvocation invoke] + 428",
    "21  CoreFoundation                      -[NSInvocation invokeWithTarget:] + 64",
    "22  CoreFoundation                      ___forwarding___ + 976",
    "23  CoreFoundation                      _CF_forwarding_prep_0 + 96",
    "24  CoreFoundation                      __invoking___ + 148",
    "25  CoreFoundation                      -[NSInvocation invoke] + 428",
    "26  ViewBridge                          __deferNSXPCInvocationOntoMainThread_block_invoke + 120",
    "27  ViewBridge                          __wrapBlockWithVoucher_block_invoke + 56",
    "28  ViewBridge                          kNotRunningOnAppKitCompatibleThread_block_invoke + 360",
    "29  CoreFoundation                      __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28",
    "30  CoreFoundation                      __CFRunLoopDoBlocks + 364",
    "31  CoreFoundation                      __CFRunLoopRun + 2432",
    "32  CoreFoundation                      CFRunLoopRunSpecific + 612",
    "33  HIToolbox                           RunCurrentEventLoopInMode + 292",
    "34  HIToolbox                           ReceiveNextEventCommon + 648",
    "35  HIToolbox                           _BlockUntilNextEventMatchingListInModeWithFilter + 76",
    "36  AppKit                              _DPSNextEvent + 636",
    "37  AppKit                              -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 716",
    "38  ViewBridge                          __77-[NSViewServiceApplication vbNextEventMatchingMask:untilDate:inMode:dequeue:]_block_invoke + 136",
    "39  ViewBridge                          -[NSViewServiceApplication _withToxicEventMonitorPerform:] + 152",
    "40  ViewBridge                          -[NSViewServiceApplication vbNextEventMatchingMask:untilDate:inMode:dequeue:] + 168",
    "41  ViewBridge                          -[NSViewServiceApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 100",
    "42  AppKit                              -[NSApplication run] + 464",
    "43  AppKit                              NSApplicationMain + 880",
    "44  libxpc.dylib                        _xpc_objc_main + 976",
    "45  libxpc.dylib                        xpc_main + 108",
    "46  Foundation                          +[NSXPCListener serviceListener] + 0",
    "47  PlugInKit                           pkSafeDataFromRelativeURL + 33800",
    "48  PlugInKit                           pkSafeDataFromRelativeURL + 32752",
    "49  PlugInKit                           pkSafeDataFromRelativeURL + 34680",
    "50  ExtensionFoundation                 EXExtensionMain + 268",
    "51  Foundation                          NSExtensionMain + 204",
    "52  dyld                                start + 2236"
), com.apple.ViewBridge.error.description=NSViewBridgeErrorServiceBootstrap}
error	23:24:30.455372+0900	Finder	FP Custom action sheet failed to load with error Error Domain=com.apple.ViewBridge Code=14 "(null)" UserInfo={com.apple.ViewBridge.error.hint=-[NSViewServiceMarshal bootstrap:withReply:] caught NSInternalInconsistencyException 'attempting to send message to non-existent action extension view controller' with backtrace (
<same backtrace as above>), com.apple.ViewBridge.error.description=NSViewBridgeErrorServiceBootstrap}
  • All right, I have figured it out. Apparently, unlike iOS, macOS FileProviderUI extension does not support NSExtensionMainStoryboard Info.plist key. Using NSExtensionPrincipalClass worked like a charm. Beware of a few things though:

    Don't forget to load view for principal class (e.g. by having corresponding .xib)On macOS prepareForActionWithIdentifier:itemIdentifiers: and prepareForError: are called before viewDidLoad (on iOS it's vice versa)
Add a Comment