Your iPhone's messages, calls, notifications, and contacts β on your Linux desktop, over Bluetooth.
No Mac relay. No cloud service. No subscription. Just Bluetooth.
Microsoft's Phone Link gives Windows users their iPhone's texts and notifications on the desktop. There has never been a Linux equivalent β KDE Connect needs the Android/iOS app and only does Wi-Fi, ancs4linux does notifications only, Mac-relay bridges (BlueBubbles, AirMessage) need an actual Mac, and Beeper costs money.
iphonebridge is that missing piece. It's a small Python daemon that talks to a paired iPhone over standard Bluetooth profiles (MAP, PBAP, ANCS, HFP) and surfaces everything as native desktop notifications, a CLI, and a GTK4 desktop app.
| Feature | How | Status |
|---|---|---|
| π¨ Incoming SMS + iMessage as desktop notifications | MAP MNS push | β |
| π€ Send SMS + iMessage from the CLI or app | MAP PushMessage | β |
| π Verification codes auto-copied to the clipboard | OTP detection | β |
| π€ Contact-name resolution (1000s of contacts) | PBAP β SQLite cache | β |
| π Every app's notifications β Slack, WhatsApp, Mailβ¦ | ANCS over BLE | β |
| π Take & place phone calls β caller ID, answer/decline, dial | HFP via oFono | β |
| π Read-state sync β read on either device, syncs to both | MAP read-state writes | β |
| π Message history β incoming + your desktop replies | sms-list / the app | β |
| π₯οΈ Desktop app β conversations, notification feed, call UI | GTK4 / libadwaita | β |
| βοΈ Runs unattended as a systemd user service | β | β |
Every prior writeup of Bluetooth on iOS says iMessage is invisible to a paired computer β that you must use a Mac relay to bridge blue-bubble messages.
That is not true on iOS 26.5. iphonebridge receives and sends iMessage through the standard MAP Bluetooth profile, with no Mac, no Apple ID login, nothing. iOS labels iMessage and SMS identically (Type: sms-gsm) and exposes both. Outgoing messages route as iMessage automatically when the recipient is iMessage-capable.
As far as we know, iphonebridge is the first free, open-source, Mac-free iMessage bridge for Linux. The empirical proof is in spike/RESULTS.md Β§6.
| Minimum | Tested with | |
|---|---|---|
| OS | Linux + GNOME, BlueZ 5.72+ | Pop!_OS 24.04 |
| Bluetooth adapter | Intel chipset (for ANCS) | Intel AX-series |
| Python | 3.10+ | 3.12 |
| iPhone | iOS 16.5+ | iPhone 16 Pro Max, iOS 26.5 |
| System packages | bluez, bluez-obexd, python3-dbus, python3-gi (+ ofono for calls, wl-clipboard for code auto-copy) | β |
β οΈ Adapter chipset matters for ANCS. Per-app notifications need a real BLE bond with the iPhone. Intel adapters do this reliably. Realtek adapters and every USB Bluetooth dongle tested so far do not β their firmware negotiates legacy keys that block the cross-transport key derivation iOS needs. SMS/iMessage/contacts (MAP/PBAP) work on any adapter; only ANCS is picky. See bmh129/ancs4linux's hardware notes.
sudo apt install bluez bluez-obexd python3-dbus python3-gi python3-venv
# For the desktop app (iphonebridge-ui):
sudo apt install gir1.2-gtk-4.0 gir1.2-adw-1
# For auto-copying verification codes (Wayland):
sudo apt install wl-clipboard
git clone https://github.com/gabrielmeir53/iphonebridge.git
cd iphonebridge
# A venv that inherits the system PyGObject + dbus-python.
# (Never install those two from PyPI β the builds are notoriously fragile.)
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install -e .
# Put `iphonebridge` (CLI + daemon) and `iphonebridge-ui` (app) on your PATH
mkdir -p ~/.local/bin
ln -sf "$(pwd)/.venv/bin/iphonebridge" ~/.local/bin/iphonebridge
ln -sf "$(pwd)/.venv/bin/iphonebridge-ui" ~/.local/bin/iphonebridge-ui
Pair normally β GNOME Settings β Bluetooth, or bluetoothctl. Then run the wizard:
iphonebridge pair-setup
It finds your iPhone among paired devices, writes ~/.config/iphonebridge/local.env, and prints the iPhone-side steps.
mkdir -p ~/.config/systemd/user
cp systemd/iphonebridge.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now iphonebridge
On the iPhone: Settings β Bluetooth β tap the β next to your computer β enable
These toggles only appear once the daemon has run at least once (it sets the adapter's Bluetooth class + advertises correctly). If you don't see them, re-run
iphonebridge pair-setupand restart the daemon.
ANCS needs a true BLE bond, which only forms during a fresh pairing while the adapter is correctly configured. One-time setup:
# Install the privileged helper (writes one specific BlueZ setting)
sudo bash systemd/install-ancs-sudoers.sh
# Apply it and re-pair
iphonebridge ancs-enable
Then forget + re-pair the iPhone one more time (the wizard walks you through it). After the fresh pair, iOS performs cross-transport key derivation and the BLE bond sticks β ANCS notifications start flowing automatically. You only do this once.
To take and place calls on the laptop, iphonebridge uses oFono for HFP call control and PipeWire's oFono backend for the call audio.
# Install oFono
sudo apt install ofono
sudo systemctl enable --now ofono
# Write the WirePlumber config + print the remaining steps
iphonebridge hfp-enable
hfp-enable writes ~/.config/wireplumber/wireplumber.conf.d/51-bluez-hfp-hf.conf
(routing HFP through oFono) and restarts WirePlumber. Follow its printed
steps β restart oFono after WirePlumber so it can claim the HFP profile,
reconnect the iPhone, restart the daemon β and incoming calls will pop up
with Answer / Decline buttons. Place calls with iphonebridge call.
sudo bash systemd/install-cod-sudoers.sh
Lets the daemon set the adapter's Class-of-Device on every start without a password prompt. Without it you'd occasionally need to re-run setup after a reboot.
iphonebridge-ui is a GTK4 / libadwaita app β a separate process from the daemon, talking to it over D-Bus, so you can open and close it freely while the daemon keeps running in the background. Four tabs:
iphonebridge-ui
The iphonebridge command does everything the app does, plus setup and diagnostics:
| Command | What it does |
|---|---|
iphonebridge run | Run the daemon in the foreground (the systemd service uses this) |
iphonebridge doctor | Check prerequisites β config, adapter class, obexd, state dir |
iphonebridge pair-setup | First-run wizard β find the paired iPhone, write config |
iphonebridge sms-list | Recent messages β -n N, --from <contact>, --source iphone|local |
iphonebridge sms-send <to> <body> | Send an SMS / iMessage (<to> = number or contact name) |
iphonebridge call <to> | Place a phone call over HFP |
iphonebridge calls | List active calls |
iphonebridge hangup | Hang up the active call(s) |
iphonebridge contacts-sync | Force a contacts refresh (otherwise automatic every 24 h) |
iphonebridge ancs-enable | One-time setup for per-app notifications (ANCS) |
iphonebridge hfp-enable | One-time setup for phone calls (HFP) |
iphonebridge version | Print the version |
# Recent messages β live from the iPhone, or from the daemon's own log
iphonebridge sms-list -n 20
iphonebridge sms-list --from Maddie
iphonebridge sms-list --source local
# Send β recipient can be a phone number OR a contact name
iphonebridge sms-send "+15551234567" "on my way"
iphonebridge sms-send Maddie "running late"
# Calls β needs HFP set up (install step 7)
iphonebridge call Maddie
iphonebridge calls
iphonebridge hangup
# Watch the daemon live Β· control the service
journalctl --user -u iphonebridge -f
systemctl --user {start,stop,restart} iphonebridge
iPhone (paired: BR/EDR + BLE)
ββββββββββββ¬βββββββββββ¬ββββββββββββ¬βββββββββββ
β MAP β PBAP β ANCS β HFP β
β (OBEX) β (OBEX) β (BLE GATT)β (oFono) β
βΌ βΌ βΌ βΌ
messages contacts app notifs calls
ββββββββββββ΄βββββββββββ΄ββββββββββββ΄βββββββββββ
β
iphonebridge daemon
(Python Β· GLib Β· D-Bus)
β
ββββββββββββββΌβββββββββββββ
βΌ βΌ βΌ
notifications JSONL log D-Bus service
+ clipboard (history) (CLI Β· GTK app)
Design rationale and the empirical Bluetooth findings that shaped it are in spike/RESULTS.md.
The iPhone times out OBEX sessions. Restart the daemon:
systemctl --user restart iphonebridge
If the iOS toggles vanished from Bluetooth settings, forget + re-pair the iPhone.
Forbidden errors in the logAn iPhone toggle is off. Check Settings β Bluetooth β β β Show Message Notifications / Sync Contacts / Show System Notifications.
ANCS needs a BLE bond, which needs a fresh pair done with the adapter correctly set up. Run iphonebridge ancs-enable, then forget + re-pair the iPhone. Also confirm your adapter is Intel β Realtek and USB dongles can't do it.
HFP needs oFono, and oFono must start after WirePlumber so it can claim the HFP profile. Run iphonebridge hfp-enable, then sudo systemctl restart ofono, reconnect the iPhone, and restart the daemon. If journalctl -u ofono shows RegisterProfile β¦ UUID already registered, the start order is wrong β restart oFono again after WirePlumber is up.
Install a clipboard tool: sudo apt install wl-clipboard (Wayland) or xclip (X11). The daemon log shows no clipboard tool worked when none is present.
iphonebridge: command not foundThe CLI lives in the venv. Either source .venv/bin/activate, or create the ~/.local/bin symlink from install step 2.
These are Apple's Bluetooth-stack limits, not bugs:
packaging/flatpak/; it still needs a build pass.See BACKLOG.md.
iphonebridge stands on the shoulders of two prior projects, both GPL-2.0:
LastUsedBearer=le unlock, and adapter compatibility made iphonebridge's ANCS support possible. The ANCS wire-format code in src/iphonebridge/ancs/ is derived from their observer/ancs/ modules.GPL-2.0-or-later Β· Β© 2026 Gabe Shatunovsky
28 commits
Hacker News (2)
Python
96.4%
Shell
3.6%
Your iPhone's messages, calls, notifications, and contacts β on your Linux desktop, over Bluetooth.
No Mac relay. No cloud service. No subscription. Just Bluetooth.
Microsoft's Phone Link gives Windows users their iPhone's texts and notifications on the desktop. There has never been a Linux equivalent β KDE Connect needs the Android/iOS app and only does Wi-Fi, ancs4linux does notifications only, Mac-relay bridges (BlueBubbles, AirMessage) need an actual Mac, and Beeper costs money.
iphonebridge is that missing piece. It's a small Python daemon that talks to a paired iPhone over standard Bluetooth profiles (MAP, PBAP, ANCS, HFP) and surfaces everything as native desktop notifications, a CLI, and a GTK4 desktop app.
| Feature | How | Status |
|---|---|---|
| π¨ Incoming SMS + iMessage as desktop notifications | MAP MNS push | β |
| π€ Send SMS + iMessage from the CLI or app | MAP PushMessage | β |
| π Verification codes auto-copied to the clipboard | OTP detection | β |
| π€ Contact-name resolution (1000s of contacts) | PBAP β SQLite cache | β |
| π Every app's notifications β Slack, WhatsApp, Mailβ¦ | ANCS over BLE | β |
| π Take & place phone calls β caller ID, answer/decline, dial | HFP via oFono | β |
| π Read-state sync β read on either device, syncs to both | MAP read-state writes | β |
| π Message history β incoming + your desktop replies | sms-list / the app | β |
| π₯οΈ Desktop app β conversations, notification feed, call UI | GTK4 / libadwaita | β |
| βοΈ Runs unattended as a systemd user service | β | β |
Every prior writeup of Bluetooth on iOS says iMessage is invisible to a paired computer β that you must use a Mac relay to bridge blue-bubble messages.
That is not true on iOS 26.5. iphonebridge receives and sends iMessage through the standard MAP Bluetooth profile, with no Mac, no Apple ID login, nothing. iOS labels iMessage and SMS identically (Type: sms-gsm) and exposes both. Outgoing messages route as iMessage automatically when the recipient is iMessage-capable.
As far as we know, iphonebridge is the first free, open-source, Mac-free iMessage bridge for Linux. The empirical proof is in spike/RESULTS.md Β§6.
| Minimum | Tested with | |
|---|---|---|
| OS | Linux + GNOME, BlueZ 5.72+ | Pop!_OS 24.04 |
| Bluetooth adapter | Intel chipset (for ANCS) | Intel AX-series |
| Python | 3.10+ | 3.12 |
| iPhone | iOS 16.5+ | iPhone 16 Pro Max, iOS 26.5 |
| System packages | bluez, bluez-obexd, python3-dbus, python3-gi (+ ofono for calls, wl-clipboard for code auto-copy) | β |
β οΈ Adapter chipset matters for ANCS. Per-app notifications need a real BLE bond with the iPhone. Intel adapters do this reliably. Realtek adapters and every USB Bluetooth dongle tested so far do not β their firmware negotiates legacy keys that block the cross-transport key derivation iOS needs. SMS/iMessage/contacts (MAP/PBAP) work on any adapter; only ANCS is picky. See bmh129/ancs4linux's hardware notes.
sudo apt install bluez bluez-obexd python3-dbus python3-gi python3-venv
# For the desktop app (iphonebridge-ui):
sudo apt install gir1.2-gtk-4.0 gir1.2-adw-1
# For auto-copying verification codes (Wayland):
sudo apt install wl-clipboard
git clone https://github.com/gabrielmeir53/iphonebridge.git
cd iphonebridge
# A venv that inherits the system PyGObject + dbus-python.
# (Never install those two from PyPI β the builds are notoriously fragile.)
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install -e .
# Put `iphonebridge` (CLI + daemon) and `iphonebridge-ui` (app) on your PATH
mkdir -p ~/.local/bin
ln -sf "$(pwd)/.venv/bin/iphonebridge" ~/.local/bin/iphonebridge
ln -sf "$(pwd)/.venv/bin/iphonebridge-ui" ~/.local/bin/iphonebridge-ui
Pair normally β GNOME Settings β Bluetooth, or bluetoothctl. Then run the wizard:
iphonebridge pair-setup
It finds your iPhone among paired devices, writes ~/.config/iphonebridge/local.env, and prints the iPhone-side steps.
mkdir -p ~/.config/systemd/user
cp systemd/iphonebridge.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now iphonebridge
On the iPhone: Settings β Bluetooth β tap the β next to your computer β enable
These toggles only appear once the daemon has run at least once (it sets the adapter's Bluetooth class + advertises correctly). If you don't see them, re-run
iphonebridge pair-setupand restart the daemon.
ANCS needs a true BLE bond, which only forms during a fresh pairing while the adapter is correctly configured. One-time setup:
# Install the privileged helper (writes one specific BlueZ setting)
sudo bash systemd/install-ancs-sudoers.sh
# Apply it and re-pair
iphonebridge ancs-enable
Then forget + re-pair the iPhone one more time (the wizard walks you through it). After the fresh pair, iOS performs cross-transport key derivation and the BLE bond sticks β ANCS notifications start flowing automatically. You only do this once.
To take and place calls on the laptop, iphonebridge uses oFono for HFP call control and PipeWire's oFono backend for the call audio.
# Install oFono
sudo apt install ofono
sudo systemctl enable --now ofono
# Write the WirePlumber config + print the remaining steps
iphonebridge hfp-enable
hfp-enable writes ~/.config/wireplumber/wireplumber.conf.d/51-bluez-hfp-hf.conf
(routing HFP through oFono) and restarts WirePlumber. Follow its printed
steps β restart oFono after WirePlumber so it can claim the HFP profile,
reconnect the iPhone, restart the daemon β and incoming calls will pop up
with Answer / Decline buttons. Place calls with iphonebridge call.
sudo bash systemd/install-cod-sudoers.sh
Lets the daemon set the adapter's Class-of-Device on every start without a password prompt. Without it you'd occasionally need to re-run setup after a reboot.
iphonebridge-ui is a GTK4 / libadwaita app β a separate process from the daemon, talking to it over D-Bus, so you can open and close it freely while the daemon keeps running in the background. Four tabs:
iphonebridge-ui
The iphonebridge command does everything the app does, plus setup and diagnostics:
| Command | What it does |
|---|---|
iphonebridge run | Run the daemon in the foreground (the systemd service uses this) |
iphonebridge doctor | Check prerequisites β config, adapter class, obexd, state dir |
iphonebridge pair-setup | First-run wizard β find the paired iPhone, write config |
iphonebridge sms-list | Recent messages β -n N, --from <contact>, --source iphone|local |
iphonebridge sms-send <to> <body> | Send an SMS / iMessage (<to> = number or contact name) |
iphonebridge call <to> | Place a phone call over HFP |
iphonebridge calls | List active calls |
iphonebridge hangup | Hang up the active call(s) |
iphonebridge contacts-sync | Force a contacts refresh (otherwise automatic every 24 h) |
iphonebridge ancs-enable | One-time setup for per-app notifications (ANCS) |
iphonebridge hfp-enable | One-time setup for phone calls (HFP) |
iphonebridge version | Print the version |
# Recent messages β live from the iPhone, or from the daemon's own log
iphonebridge sms-list -n 20
iphonebridge sms-list --from Maddie
iphonebridge sms-list --source local
# Send β recipient can be a phone number OR a contact name
iphonebridge sms-send "+15551234567" "on my way"
iphonebridge sms-send Maddie "running late"
# Calls β needs HFP set up (install step 7)
iphonebridge call Maddie
iphonebridge calls
iphonebridge hangup
# Watch the daemon live Β· control the service
journalctl --user -u iphonebridge -f
systemctl --user {start,stop,restart} iphonebridge
iPhone (paired: BR/EDR + BLE)
ββββββββββββ¬βββββββββββ¬ββββββββββββ¬βββββββββββ
β MAP β PBAP β ANCS β HFP β
β (OBEX) β (OBEX) β (BLE GATT)β (oFono) β
βΌ βΌ βΌ βΌ
messages contacts app notifs calls
ββββββββββββ΄βββββββββββ΄ββββββββββββ΄βββββββββββ
β
iphonebridge daemon
(Python Β· GLib Β· D-Bus)
β
ββββββββββββββΌβββββββββββββ
βΌ βΌ βΌ
notifications JSONL log D-Bus service
+ clipboard (history) (CLI Β· GTK app)
Design rationale and the empirical Bluetooth findings that shaped it are in spike/RESULTS.md.
The iPhone times out OBEX sessions. Restart the daemon:
systemctl --user restart iphonebridge
If the iOS toggles vanished from Bluetooth settings, forget + re-pair the iPhone.
Forbidden errors in the logAn iPhone toggle is off. Check Settings β Bluetooth β β β Show Message Notifications / Sync Contacts / Show System Notifications.
ANCS needs a BLE bond, which needs a fresh pair done with the adapter correctly set up. Run iphonebridge ancs-enable, then forget + re-pair the iPhone. Also confirm your adapter is Intel β Realtek and USB dongles can't do it.
HFP needs oFono, and oFono must start after WirePlumber so it can claim the HFP profile. Run iphonebridge hfp-enable, then sudo systemctl restart ofono, reconnect the iPhone, and restart the daemon. If journalctl -u ofono shows RegisterProfile β¦ UUID already registered, the start order is wrong β restart oFono again after WirePlumber is up.
Install a clipboard tool: sudo apt install wl-clipboard (Wayland) or xclip (X11). The daemon log shows no clipboard tool worked when none is present.
iphonebridge: command not foundThe CLI lives in the venv. Either source .venv/bin/activate, or create the ~/.local/bin symlink from install step 2.
These are Apple's Bluetooth-stack limits, not bugs:
packaging/flatpak/; it still needs a build pass.See BACKLOG.md.
iphonebridge stands on the shoulders of two prior projects, both GPL-2.0:
LastUsedBearer=le unlock, and adapter compatibility made iphonebridge's ANCS support possible. The ANCS wire-format code in src/iphonebridge/ancs/ is derived from their observer/ancs/ modules.GPL-2.0-or-later Β· Β© 2026 Gabe Shatunovsky
Hacker News (2)
28 commits
Python
96.4%
Shell
3.6%