Open source · direct device link

Your Mac and your Android,
acting as one machine.

Bridge puts a live link between the two devices on your desk. Notifications, clipboard, files and battery cross over directly — radio to radio. No network, no account, no cloud, no server anywhere in the path.

macOS 15+ · Android 12+ · BLE + Wi-Fi · MIT licensed · no cloud, no account, no telemetry

A MacBook and an Android phone joined by a live Bluetooth LE link A laptop on the left and a phone on the right, with packets of data travelling in both directions along a glowing link between them. BLE · always on no router · no account
  • 4transport tiers, chosen automatically
  • 10packet types in the v1 protocol
  • 0servers, accounts or telemetry endpoints
  • MITlicensed, source on GitHub

The problem

Nobody owns both ends, so nobody builds the bridge.

The Android↔Mac gap is commercial, not technical. Every shipping phone-to-desktop link exists because one vendor owns both sides of it — and the two you own happen to belong to different vendors.

Apple ↔ Apple

Continuity works beautifully, and the friction of leaving is exactly the point.

Android ↔ Windows

Microsoft sells no phone, so Phone Link defends Windows. Samsung ships the other half.

Android ↔ Mac

Nobody gains from building it for a rival. The radios are already there; the maintainer was missing.

Bluetooth LE for discovery and wake, Wi-Fi for payload, mDNS for service advertisement — both sides have had the hardware all along. Bridge is just the published protocol and the app on each end.

How it works

A ladder of four transports, climbed only when the payload needs it.

One resident link carries control. Anything bulky gets its own channel, opened for the transfer and torn down after — so a 2 GB video never parks itself in front of your notifications.

The Bridge transport ladder Four tiers between a Mac and a phone. Tier 1 is a Bluetooth LE GATT and L2CAP channel at 50 to 100 kilobytes per second carrying presence, notifications, clipboard and control, always on, needing only proximity. Tier 2 is Bluetooth Classic RFCOMM at about 140 kilobytes per second for small files and images, needing only proximity. Tier 3 is Wi-Fi LAN at full speed for large files and as a control fallback, needing a shared network. Tier 4 is a hotspot hosted by the phone and joined by the Mac, at full speed, for large files when there is no shared network, and only on the user's confirmation. Mac menu-bar app Phone foreground service 1 Bluetooth LE — GATT + L2CAP channel Presence · notifications · clipboard · control — always on 50–100 KB/s proximity only newline-delimited JSON, both directions 2 Bluetooth Classic — RFCOMM Small files and images, when there is no shared network to climb to ~140 KB/s proximity only 3 Wi-Fi LAN — mDNS + TCP over TLS Large files, and a control fallback when Bluetooth is out of range full speed shared network 4 Phone hotspot, joined by the Mac No shared network — the phone hosts a hotspot, the Mac joins it full speed you say yes Tiers 2–4 are opened for one payload and torn down after. Tier 1 stays free throughout — that is the whole point.
The ladder. The link never drops lower than it needs, and never climbs higher than the payload justifies.
The packet envelope Every message is one line of JSON with three fields: id holding a millisecond timestamp, type holding a name such as bridge.clipboard, and body holding the parameters. Lines are separated by a newline character. {"id": 1760000000000, "type": "bridge.clipboard", "body": {"content": "…"}}\n timestamp packet type payload No delivery guarantee, no response guarantee. Every handler is idempotent and tolerates packets it did not expect.
Ten packet types, one envelope. Identical on every tier — the higher tiers are just another stream.
Behaviour by range and network A two by two matrix. In Bluetooth range with a shared network, everything works and files go over Wi-Fi. In Bluetooth range with no shared network, control and small files work over Bluetooth, with the hotspot tier available for large ones. Out of Bluetooth range but on a shared network, control and files keep flowing over the LAN. Out of range and off the network, the link is down. same Wi-Fi no shared network in BLE range out of range Tier 1 + 3 Control on BLE, files at full Wi-Fi speed. Tier 1 + 2 Control on BLE, small files on RFCOMM; 4 on ask. Tier 3 only Phone in the next room — LAN carries control too. Link down The Mac says so plainly and keeps watching.
Out of Bluetooth range is not the same as gone. Tier 3 doubles as the control fallback.
  1. 1

    The phone advertises

    The foreground service broadcasts one Bridge service UUID — the only constant in the build. Nothing about either device is known in advance.

  2. 2

    The Mac scans and connects

    It reads an identity characteristic — a randomly generated device id, a name, a type and two capability arrays — then opens an L2CAP channel for the session.

  3. 3

    You confirm once

    The phone asks to pair; the Mac shows the request in its menu bar and waits. Nothing is trusted until you accept it yourself.

  4. 4

    It stays up

    Walk away and the Mac says out of range; walk back and it reconnects without you touching anything. Capability arrays, not a version number, decide what each peer may send.

What it does

Four things, done properly.

Bridge speaks the KDE Connect wire format — a public, stable protocol — rather than inventing a private one.

Notification mirror, with reply

Phone notifications land in macOS Notification Center. Where the notification supports a reply, you type it on the Mac and it goes back out through the phone.

bridge.notification · bridge.notification.reply

Clipboard, both ways

Copy on one device, paste on the other. Each side stamps its clip with a timestamp and ignores anything staler than what it already holds, so reconnecting never ping-pongs an old clipboard back at you.

bridge.clipboard · manual on Android 16 — see limitations

Wi-Fi, full speed

Files, both directions

Send without unlocking the phone or opening a browser. Bridge names a tier and a destination, the receiver opens that channel, the bytes move, the channel closes — the control link stays free the whole time.

bridge.share.request · tiers 2, 3 and 4

Battery on the menu bar

Charge level and charging state, pushed from the phone and visible from the Mac's menu bar — no app to open, no phone to pick up.

bridge.battery

Security & privacy

There is no server, so there is nothing to trust but the two devices.

Each device generates a self-signed certificate once, at first launch, and keeps it forever. The fingerprint of that certificate is the device's identity. There is no password, no account, and nothing in the middle to subpoena.

The pairing handshake A sequence between Mac and phone: the phone advertises, the Mac connects and both exchange identity and certificate. The phone sends a pair request and the Mac asks you to confirm it in the menu bar. Only after you accept does each side pin the other's fingerprint. Every later connection is mutual TLS against the pinned certificate, and packets from an unpaired device are dropped before parsing. Mac Phone advertises the Bridge service UUID connects · identity + certificate phone sends a pair request · the Mac asks you Pair with this phone? you accept in the Mac menu bar pair: true each side pins the other's fingerprint mutual TLS, pinned certs every connection after this one
Pair once. Nothing is trusted until you accept it on the Mac, and an unknown device gets dropped before it is parsed.
  • Nothing leaves the two devices

    No relay, no broker, no account, no telemetry. Bluetooth and your own Wi-Fi are the entire network path; the internet is never in it.

  • Unpaired packets are dropped

    Dropped before parsing — an unknown device cannot even get its JSON looked at.

  • A changed fingerprint closes the connection

    It is never silently re-paired. A reinstall and an impostor look identical from the outside, so both require a deliberate re-pair by you.

  • No device identity is baked in

    The device id is random, generated once at first launch, and derived from no hardware identifier. One service UUID is the only constant in the build.

  • Unpair is one tap

    Either side can drop the pin and go back to advertising. Pairing a different phone is an unpair and one more confirmation — no reinstall, no config file.

Install

Two installs, one confirmation, done.

Installing the app on both devices is the only setup step. There is nothing to sign up for.

Mac — Homebrew

brew install --cask deepakk33/tap/bridge-link

Bridge lives in the menu bar, not the Dock. On first run macOS asks for Bluetooth, Notifications and Local Network — all three are needed.

Ad-hoc signed, not notarized by Apple. There is no Apple Developer Program membership behind this build, so Gatekeeper has not blessed it. The cask clears the quarantine attribute on install; if you download the app by hand, macOS will refuse to open it until you allow it in System Settings → Privacy & Security. Read the cask and the source first if that trade-off matters to you — it should.

Android — sideload the APK

https://github.com/deepakk33/Bridge/releases/latest

Download the APK from the latest release and install it. Bridge is not on Google Play, so your phone will ask you to allow installs from your browser or file manager once.

Then grant Bluetooth and Notifications when prompted, enable Notification access in Settings (the app links you straight there), and let Bridge ignore battery optimisation so the service is not killed.

Open both apps and accept the pair request on the Mac. From then on it reconnects on its own. Requires macOS 15 (Sequoia) or later, Android 12 (API 31) or later, and Bluetooth LE on both.

Honest limitations

What Bridge does not do, and why.

Some of this is a choice. Some of it is the operating system saying no. Either way you should know it before you install, not after.

Clipboard sync is manual on Android, not automatic

Automatic background clipboard sync is not possible on Android 16 without rooting the phone. The OS made READ_CLIPBOARD_IN_BACKGROUND role-managed, so it cannot be granted to a sideloaded app — not by ADB, not by Shizuku, only by root. This is not something a future release of Bridge can fix.

So the clipboard works deliberately instead:

  • Phone → Mac: tap the Bridge Clipboard Quick Settings tile, or just open the app — opening it sends the current clip.
  • Mac → Phone: open the app. It applies whatever the Mac last copied; clips that arrived while it was backgrounded are cached and flushed on focus.

Mac-side reading is unrestricted, so the direction that annoys you least is the one that still works instantly.

No screen mirroring

Bridge does not mirror or control the phone's screen. scrcpy already does that well over USB or ADB-over-Wi-Fi; duplicating it badly would help nobody.

One phone at a time

A Mac is paired to exactly one phone, and a phone to one Mac. Either side can unpair and pair with a different device at any moment — but fan-out to several phones at once is out of scope.

Unsigned by Apple, sideloaded on Android

No Apple Developer Program, no Play Store listing. That means no review queue and no platform policy — and also no notarization and no store vetting. The source is public precisely so that trade-off is yours to check.

The hotspot tier costs you your Wi-Fi

A Mac has one Wi-Fi radio, and macOS cannot host a hotspot at all any more. So tier 4 means the phone hosts and the Mac leaves its current network to join — never automatic, always a button with a warning, and the Mac rejoins afterwards.

Aggressive battery managers can still kill it

Bridge runs a foreground service and survives being swiped from recents, but some Android skins are more aggressive than stock. Setting Bridge to unrestricted battery usage is part of setup for a reason.

FAQ

Questions worth asking.

Does it need Wi-Fi?

No. The resident link is Bluetooth LE, and it carries presence, notifications, clipboard and all control — with Wi-Fi switched off entirely. Wi-Fi is only climbed to when you move a file big enough to justify it, and if there is no shared network, small files still go over Bluetooth Classic.

Does anything touch the internet?

No. There is no server, no relay and no account in the design, so there is nothing for Bridge to call home to. The only network path is the radio between your two devices, plus your own LAN when a file is large enough to use it.

Which devices work?

Any Mac on macOS 15 (Sequoia) or later, and any Android phone on Android 12 (API 31) or later, both with Bluetooth LE. No device id, serial, name or address is baked into either build — everything about the pair is discovered at runtime.

Is it really free?

Yes. MIT licensed, source on GitHub, no paid tier, no upsell, nothing to subscribe to. It was built to solve one person's problem and costs nothing to give away.

Why not just use AirDrop or Quick Share?

AirDrop does not speak to Android at all, and Quick Share for desktop does not speak to macOS. Both are also file-transfer tools: they will not mirror a notification, let you reply from the Mac, sync a clipboard or show you the phone's battery. Bridge is the resident link, not a one-shot send.

What happens to my data?

It stays on your two devices. Notifications, clips and files cross the link directly and are not stored anywhere else; there is no analytics SDK, no crash reporter and no identifier collected. The device id each app generates is random and is only ever shown to the other device.

Why is the Mac app unsigned?

Notarization requires a paid Apple Developer Program membership, which this project does not have. The app is ad-hoc signed with a self-signed certificate instead, which is enough for macOS to run it but not enough for Gatekeeper to vouch for it. The Homebrew cask handles the quarantine attribute; the source is public so you can build it yourself if you would rather not trust a binary.

How do I pair a different phone?

Open the Mac menu-bar panel and tap Unpair — that drops the pinned fingerprint and puts the Mac back into scanning. Install Bridge on the new phone, open it, and accept the pair request on the Mac. No reinstall on the Mac, no configuration file, no build change.