Send and receive files between your Mac and nearby Android devices,
using Google's Quick Share — implemented from scratch.
Android phones can share files with each other in two taps. Macs can't join in — Quick Share has no Apple client, and AirDrop doesn't speak to Android. QShare fills that gap: your Mac shows up in your phone's Quick Share sheet, and your phone shows up in QShare's device list.
Quick Share is undocumented, so this is a clean implementation written against a reverse-engineered specification — mDNS discovery, UKEY2 key agreement, AES-256-CBC + HMAC-SHA256 secure messages, chunked transfer — depending on nothing outside the OS.
- Send — pick a device and drag files onto it, or drop them on a device row
- Receive — flip visibility on and your Mac appears on the phone
- Text and links — saved to your downloads folder as files, never opened
- PIN verification — a 4-digit code on both screens before anything moves
- Per-sender auto-accept — opt in per device to skip the prompt (what it does and doesn't promise)
- QR code — reach a phone that can't discover you
- Menu-bar app — keeps running with the window closed
- Command-line API — drive it from scripts or an agent (off by default)
Needs macOS 26 or later, and both devices on the same Wi-Fi network.
Grab the latest QShare-macOS.dmg,
open it, and drag QShare to Applications.
The build is ad-hoc signed but not notarized, so Gatekeeper blocks it the first time. On macOS 15 and later the old right-click → Open trick no longer works: open System Settings → Privacy & Security, find the notice about QShare being blocked, and press Open Anyway.
To receive, open the Receive tab and turn on visibility. The status line reflects whether your Mac is genuinely visible on the network, not just whether you flipped the switch. Then on your phone: share a file, pick your Mac, confirm the PIN.
To send, pick a device from the Send tab and drag files onto it. If the phone isn't listed, use the QR code — scanning it connects without discovery.
Received files land in ~/Downloads by default; change that in Settings.
⌘1 / ⌘2 |
Send / Receive |
⇧⌘V |
Toggle visibility |
⇧⌘O |
Open downloads folder |
⌃⌥← / ⌃⌥→ |
Snap window to screen edge |
⌘⌥I |
Build info |
Usually this isn't a bug. Android discovers nearby devices by listening for Bluetooth LE advertisements, and macOS provides no API to emit them. Nothing in this app can fix that — it's a platform limitation, not an oversight.
In practice that means Mac → phone is the reliable direction, and phone → Mac needs a hand:
- Make sure both devices are on the same Wi-Fi network — not one on 5 GHz and one on a guest SSID.
- Check the router isn't running AP isolation (often called "client isolation"), which blocks devices from seeing each other.
- Turn off any VPN on either device; most capture the traffic discovery needs.
- Still nothing? Use the QR code. It's the designed answer to this, not a workaround — scanning it skips discovery entirely.
Every transfer shows a 4-digit PIN on both screens before any bytes move. Matching it is what proves you're talking to the device you think you are.
Auto-accept is off by default, and it's worth knowing exactly what it gives up. Quick Share as implemented here exposes no verifiable device identity: UKEY2 keys are generated fresh for every handshake, and the certificate frames that would carry a persistent identity aren't in the specification this is built from. The only thing a sender proves is the name it chose to advertise.
So enabling auto-accept for "Pixel 8 Pro" means anything on your network calling itself Pixel 8 Pro is accepted without a prompt. That's why auto-accepted transfers still post a notification rather than landing silently, and why it's opt-in per device. For anything you care about, leave it off and confirm the PIN.
Received links are saved as files, never opened — otherwise auto-accept would let a device on your network open a URL on your Mac with no interaction at all.
QShare can host a small JSON API on 127.0.0.1:47821 for scripting and
automation. It is off by default — enable it in Settings → Services.
While it's on, anything running under your account can ask QShare to send any file it can read to a nearby device. That's the point of the feature, and the reason it's opt-in.
ln -s "$(pwd)/App/Packaging/qshare" /usr/local/bin/qshare
qshare list # devices currently visible
qshare send ~/photo.jpg --to "Pixel 8 Pro" # blocks; exit 0 on success
qshare status --json # machine-readableRequests are authenticated with a token in ~/.config/qshare/token. Full
endpoint reference: docs/API.md.
Views (SwiftUI) ──observe──▶ AppModel ──▶ QuickShareService
│
┌──────────┴──────────┐
MockService QuickShareEngine
(QS_MOCK=1) │
┌───────────┴───────────┐
Discovery Transport
mDNS · QR · TXT framing · sessions
│
Crypto ─── Wire
UKEY2 P-256 protobuf
Sources/QuickShareProtocol/ is the protocol; Sources/QuickShare/ is the app.
The seam between them is one protocol (QuickShareService), which is also what
makes the mock engine possible.
The whole thing is Swift 6 language mode: the transport runs on actors, the app on the main actor, and the compiler checks the boundary rather than convention.
The wire format is hand-written rather than generated — only a small fraction of the schema's messages are ever exchanged. Each is checked byte-identical against a reference encoder, and the parsers that face the network are tested against truncation, bit-flips, and random input.
See docs/ARCHITECTURE.md for the design and the protocol details worth knowing.
git clone https://github.com/kanin-design/QShare.git
cd QShare/App
./Packaging/build-app.sh
open build/QShare.appThe packaging step matters: real networking needs a proper .app bundle so
macOS will grant local-network access. A bare swift run binary can't get it.
swift test # unit + protocol tests
swift test --sanitize=thread # concurrency
QS_MOCK=1 swift run QuickShare # UI work without a phoneQS_MOCK=1 runs a simulated engine that drives every UI state — devices, PINs,
progress, completion — with no network at all. The screenshots above were taken
with it.
./Packaging/make-dmg.sh builds the app and wraps it in a disk image, which is
how releases are cut.
Quick Share is undocumented. The protocol was reverse-engineered and specified by @grishka, published at grishka/NearDrop and released into the public domain.
QShare implements the protocol from that specification — the code here is its own, but the knowledge isn't. See ATTRIBUTION.md for detail.
Not affiliated with or endorsed by Google. "Quick Share" and "Nearby Share" are their trademarks.
0BSD — use it, change it, ship it, sell it. No attribution required, no conditions attached. In the spirit of the work it's built on.

