Forwards iPhone notifications to Linux desktops over Bluetooth.
The ANCS Bluetooth handling in this project is based on impiaaa/ios-notif-forward. This repo diverged significantly (daemon/client architecture, mDNS discovery, JSON event stream, no UI) so it lives as its own project rather than a fork, but the original did the hard work of figuring out ANCS on Linux.
A daemon running on a server in Bluetooth range of your phone receives notifications via ANCS and pushes them over the LAN to any number of subscribed desktop clients, which display them with notify-send.
This is rather a niche setup for my own uses: I have multiple computers, I don't carry my phone around me at home, and my laptops are often out of bluetooth range of the phone. This keeps me notified of calls/texts/etc no matter where I am working.
iPhone
│ Bluetooth LE / ANCS
▼
iosd advertises via mDNS (_ios-notif._tcp)
│ TCP / JSON
├──▶ ios-client → notify-send
└──▶ ios-client → notify-send
iosd — runs on a server that stays in Bluetooth range of the phone. Connects to the paired iPhone, subscribes to its Apple Notification Center Service, and pushes notification events as newline-delimited JSON to all connected clients. Advertises itself on the LAN via mDNS so clients find it automatically.
ios-client — runs on each desktop. Discovers iosd via mDNS, connects over TCP, and calls notify-send for each incoming notification. Reconnects automatically if the daemon restarts or the network drops. The originating app name (e.g. "Messages", "Instagram") is shown as the notification source.
- Linux
- Bluetooth LE adapter on the server
notify-sendon each client machine (libnotify)- Your user in the
bluetoothgroup on the server
Arch:
sudo pacman -S rust dbusDebian/Ubuntu:
sudo apt install cargo libdbus-1-dev pkg-configThe server must be paired with the iPhone before iosd will work. Initiate from the phone side — it's more reliable for ANCS.
On the server:
bluetoothctl
power on
agent on
discoverable onOn the iPhone, go to Settings → Bluetooth and tap your server in the device list. Confirm the pairing PIN on both sides, then back in bluetoothctl:
trust AA:BB:CC:DD:EE:FFThe phone will reconnect automatically when in range from then on.
The first time iosd connects, iOS will ask whether to allow the computer to receive notifications — tap Allow.
cargo build --releasemake install # build release, install binaries and systemd units
make enable # start and enable both servicesInstall only one half if needed:
make install-daemon # server only
make install-client # this desktop onlymake uninstall # remove everythingmake dist
scp -r dist/ user@server:ios-notif-forward/
ssh user@server 'sudo ./ios-notif-forward/install.sh'make dist produces a dist/ directory with stripped binaries, systemd unit files, and an install.sh script. By default install.sh installs only the daemon. To install the client on a desktop instead:
./install.sh client # installs ios-client as a user service
./install.sh all # installs bothinstall.sh substitutes your username into the service file at install time.
Server:
cargo run --bin iosdClient (any machine on the LAN):
cargo run --bin ios-clientIf the server has more than one adapter, specify which to use:
iosd --adapter hci0The name matches as a prefix against the adapter info string. To make it permanent, edit ExecStart in /etc/systemd/system/iosd.service after installing.
To suppress notifications from specific apps, create ~/.config/ios-client/blacklist on each client machine:
# one app display name per line, case-insensitive
Mail
News
Duolingo
The list is read when the client connects. To reload it, restart the service:
systemctl --user restart ios-clientClients receive newline-delimited JSON:
{"event":"added","uid":12345,"app":"Messages","title":"Alice","body":"Hey","category":"social"}
{"event":"modified","uid":12345,"app":"Messages","title":"Alice","body":"Hey, you there?"}
{"event":"removed","uid":12345}app is the display name of the iOS app that sent the notification. silent and important boolean fields are included when true. category maps to ANCS category names (incoming-call, email, social, etc.) and is omitted when the category is unset.