5 Things Nobody Tells You About macOS File Provider Extensions
I spent the last few months building a File Provider extension that mounts an Android phone as a native Finder location — files-on-demand, no FUSE, no drivers. The framework is genuinely great. The docs are genuinely sparse. Here are the five things I wish someone had told me on day one.
1. It's not a filesystem — it's a Q&A session with the OS
I came in thinking "File Provider = mount a drive." Wrong mental model. You never implement a filesystem. The OS asks you questions and you answer them:
- "What's in this folder?" → enumeration
-
"Tell me about this item" →
item(for:) -
"Give me the bytes" →
fetchContents(...) - "Here's a change, save it" → writeback
That's it. Once it clicked that I'm just a question-answering service and the framework owns all the syncing, caching, and Finder integration, everything got simpler. The corollary: the system decides when to ask. You don't push; you respond.
2. Folder listings must be free; bytes must be lazy
The single most important performance rule: enumeration moves zero file data.
My device has years of photos. If listing a folder eagerly fetched anything, browsing would be unusable. So enumeration returns lightweight metadata only — name, size, identifier, dates — and the actual transfer is deferred to fetchContents, which fires only when the user opens a file.
Get this backwards and a folder with 5,000 items tries to download 60GB on open. Get it right and the same folder appears instantly and transfers nothing until you double-click something. The laziness isn't an optimization; it's the entire reason files-on-demand works.
3. A blocking extension takes Finder down with it
This is the scary one. Your extension is a process Finder leans on hard. If a call hangs — a dead network socket, an unplugged cable, a sleeping device — you can beachball Finder itself.
The fix isn't "be fast," because you can't be; you're talking to a phone over a cable. The fix is to treat every operation as cancellable and time-bounded, and to translate failures into proper NSFileProviderError cases (.serverUnreachable, .noSuchItem, .notAuthenticated) instead of letting them stall. Finder knows how to render those gracefully. It does not know how to recover from your deadlock.
Budget most of your time here. The happy path is a weekend; "fails politely under every kind of disconnect" is the project.
4. Identifiers are a contract, not a convenience
Every item has an NSFileProviderItemIdentifier, and the system uses it to reconcile what changed between enumerations. The rule that bit me: the same file must always produce the same identifier.
If you derive identifiers from something unstable — array index, a hash that includes mtime, a path that shifts when a vendor exposes storage differently — the system thinks files are being deleted and recreated constantly. You get phantom churn, broken "open in place," and weird duplicate states. Pick a stable, deterministic mapping early (I map identifiers to canonical device paths) and never let it drift.
5. You can register a domain backed by literally anything
The realization that made the whole project possible: File Provider does not care where your data lives. iCloud, Dropbox, an S3 bucket, a Postgres row, or — in my case — an Android phone on the other end of adb. You register a domain, and it shows up in the Finder sidebar. The OS asks its questions; your answers happen to come from adb shell ls and adb pull.
let domain = NSFileProviderDomain(
identifier: .init("device-<serial>"),
displayName: "Pixel 8"
)
try await NSFileProviderManager.add(domain) // <- the phone "mounts" here
If you've ever wanted to surface a remote API, a database, or a weird device as a first-class, on-demand Finder location, this is the door. It's far more approachable than the FUSE-shaped solution you were dreading.
TL;DR
- You're a Q&A service, not a filesystem.
- Enumeration = metadata only; bytes load on open.
- Never block — translate failures into
NSFileProviderErroror you'll beachball Finder. - Stable identifiers or bust.
- The backing store can be anything — that's the superpower.
This is the framework behind MacPortal, which mounts your Android phone as a native Finder location over USB or Wi-Fi (macOS 13+). macportal.app
Top comments (0)