個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Your Android phone on your Mac, over your own Wi-Fi: files, notifications, calls, clipboard, photos and screen mirroring. No account, no cloud.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Unison is a pair of native apps: a Mac menu-bar app and an Android app. You pair them once by scanning a QR code. After that they find each other on your local network and stay connected in the background. Send files either way, see and answer your phone's notifications and calls on the Mac, share the clipboard, browse your photos, and mirror and control your phone's screen.
Get it: the Mac app is a free download from venu005.github.io/unison. The Android app is coming soon to Google Play.
It's built by one person (developed on a Nothing Phone (3) running Android 17 and a MacBook Air running macOS 26). The Mac app is sandboxed, and the Android app is being prepared for Google Play.
| Status | |
|---|---|
| Pairing by QR code (or manual entry with fingerprint check), forget & re-pair on either side | ✅ |
| Always-on connection over local Wi-Fi with auto-reconnect (Wi-Fi drops, sleep/wake, reboots) | ✅ |
| Phone battery level and charging state in the Mac menu bar | ✅ |
| File transfer, both ways: resumable, SHA-256 checked, up to 3 at once | ✅ |
| Notifications mirrored to the Mac: reply, action buttons, dismiss both ways, per-app mutes | ✅ |
| Clipboard: Mac → phone automatic, phone → Mac in one tap, Mac history | ✅ |
Calls on the Mac: answer, decline, hang up, number pad and tel: links (audio stays on the phone) | ✅ |
| Photos: browse the phone's photos and videos on the Mac, preview, save, drag out | ✅ |
| Screen mirroring with phone audio, and remote control from the Mac's mouse and keyboard | ✅ |
| Small wins: ring my phone, media controls, open links on the other device | ✅ |
| "Share → Send to phone" from Finder | Parked |
From the Mac:
From the phone:
Receiving:
~/Downloads/Unison on the Mac and Download/Unison on the phone.Reliability:
*.macdroid-part until then. (1), (2), … Android phone (always the client) Mac (the server, advertised as _macdroid._tcp)
───────────────────────────────── ──────────────────────────────────────────────
finds the Mac via NSD / Bonjour ─────────────────────────▶ BonjourAdvertiser
OkHttp, mutual TLS 1.3, pinned:
WSS /v1/ws (control messages, JSON) ─────▶ ConnectionHub
POST /v1/pair (only while pairing is open) ──▶ PairingManager
HEAD/PUT/GET /v1/files/{id} (file bytes, resumable) ──▶ TransferManager
transfer.offer/accept/finish/result/…) travel as JSON over a WebSocket. File bytes go over HTTPS. Uploads resume with HEAD + Content-Range; downloads resume with Range.protocol/PROTOCOL.md, with JSON fixtures that both the Swift and the Kotlin test suites decode and re-encode.| Mac | macOS 14 or later |
| Android | Android 10 (API 29) or later; on Android 17 the app asks for the local network permission first |
| Network | Both devices on the same local network |
Toolchain (what the project is developed with):
brew install xcodegen)The Gradle wrapper is committed.
cd mac
xcodegen generate # creates MacDroid.xcodeproj (not committed)
xcodebuild -project MacDroid.xcodeproj -scheme MacDroid -configuration Debug -derivedDataPath build build
open build/Build/Products/Debug/Unison.app
Unison lives in the menu bar. Open it again (or press ⌘O in the popover) to show its window.
Builds are signed with a self-signed identity, "MacDroid Self-Signed". Create it once per Mac with scripts/make-signing-cert.sh. With it, keychain access ("Always Allow") survives rebuilds and updates.
Create android/local.properties with sdk.dir=/path/to/android/sdk, then:
cd android
./gradlew :app:assembleDebug
ANDROID_SERIAL=<device> ./gradlew :app:installDebug
# Mac core: protocol, pairing, server, transfer engine (Swift Testing)
cd mac/MacDroidCore && swift test
# Android: core library and app unit tests, plus a debug build
cd android && ./gradlew :core:test :app:testDebugUnitTest :app:assembleDebug
# End to end: the real Swift server against the real Kotlin client.
# It pairs, then sends 24 MiB each way, cuts the connection mid-file,
# and checks both files resume and match byte for byte.
./scripts/cross-platform-test.sh
On-device tests (Keystore TLS, MediaStore part files) live in android/app/src/androidTest. Run them with am instrument as described in the developer guide. Gradle's connectedDebugAndroidTest uninstalls the app afterwards, which loses your pairing.
All builds are expected to pass with no warnings.
mac/
MacDroidCore/ Swift package with all testable Mac logic: protocol, TLS identity, pairing,
Bonjour, Hummingbird HTTPS/WebSocket server, connection hub, transfer engine
MacDroid/ SwiftUI app (menu-bar popover + window); views stay thin
project.yml XcodeGen spec
android/
core/ Pure Kotlin/JVM: protocol, pinned mTLS client, pairing, connection manager,
transfer client and engine
app/ Android glue and Jetpack Compose UI (Material You)
protocol/ PROTOCOL.md and the shared JSON fixtures both test suites use
scripts/ Cross-platform test and icon rendering
design/icon/ App icon source art (SVG)
docs/handoff/ Living project docs: status, architecture, decisions, dev guide, changelog
docs/superpowers/ Design specs, implementation plans and follow-up lists
The site lives in website/ and is published at https://venu005.github.io/unison/; download the Mac app from Releases. Mac releases (Unison.dmg) are built with scripts/make-release.sh. See the developer guide.
Unison is free, with no ads and no account. If it saves you time, you can leave a one-time tip:
MIT © 2026 Venu005