【附原始程式碼】我用 Jetpack Compose 寫了一個局域網微信
一、起點
從 WeUI 到 WeChat Lan:一段跨越兩年的技術沉澱。 兩年前因為技術儲備不足而擱置的「微信」,在這次離職後的一次爬山中被重新喚醒。市面上有不少局域網通訊 App,但大多不是功能太簡單,就是介面太醜。而我想做一個把近場通訊玩透、介面與功能對齊微信的小而美 App~
核心技術思考:
- 去中心化: 擺脫伺服器限制,探索裝置間的高效互聯。
- 多模態連線: 同時相容
Wi‑Fi LAN、Wi‑Fi Direct 與 藍牙 通訊。
- 技術全棧化: 深度整合硬體調度、資料加密、檔案傳輸及音視頻通訊等核心模組。
我快速問了 AI:
一個安卓 APP,能不能同時基於 Wi‑Fi LAN、Wi‑Fi Direct 和 藍牙 實現裝置間的點對點(P2P)直接互聯?
答案是:完全可以。
於是在 2026 年 1 月初,正式開啟了 WeChat Lan 的開發之旅。在簡單驗證了 Wi‑Fi Lan、Wi‑Fi Direct 和 藍牙 的可行性後,便開始著手 UI 的開發。在除夕那天晚上就快到 12 點的時候,打通了基於 WebRTC 的通話功能,非常開心。後來又不斷在完善 UI 的過程中,加上了端到端加密、訊息簽名、多主題、多語言、檔案斷點續傳、訊息轉發、對更多訊息類型的支援,以及多模態連線的整合等,還有若干的 bug 修復、穩定性、效能和一致性優化等。今天終於可以和大家見面了!
二、技術選型
核心函式庫 均使用當前最新版本來構建響應式、現代化、高效能的 Android 應用。
- UI 框架:Jetpack Compose 宣告式 UI 全家桶
- 開發語言:Kotlin
- 依賴注入:Hilt
- 資料持久化:Room + DataStore
- 多媒體與互動:WebRTC + CameraX + ML Kit + Coil3 等
- 地圖:AMap(高德地圖)。我對地圖模組進行了可插拔設計,理論上可以方便地切換到其他地圖 SDK,預設已經實作了高德地圖的標準版 SDK 和輕量版 SDK。(輕量版可以透過選擇 Lite 變體切換)
- 專案採用模組化 + 領域驅動設計
三、功能介紹
四、功能說明
1. 經典啟動頁
啟動頁之後會進入歡迎頁面,可以修改 app 語言,點擊開始使用將進入登入頁面

2. 登入頁面
- 也叫個人資料設定頁面,設定頭像和暱稱後就能進入 app。
- 點擊確定後將會自動生成微信號和身份密鑰。
- 私鑰將被系統自動保存在硬體安全模組(TSS/SE)。公鑰將隨個人資料保存在 DataStore。

3. 個人資料頁面
- 頭像可以預覽、更換(裁切)、儲存到本機。
- 名字、性別、簽名等支援修改。
- 微信號暫不支援修改。

二維碼頁面

4. 新增朋友頁面
掃一掃

碰一碰

雷達
- 基於
UDP 組播 + 輕量級 HTTP 頭像伺服器
- 裝置需要在同一 Wi‑Fi 下

加好友邏輯
其實無論基於何種添加方式,上層都只是取得對方的 ID,底層都是走的 BLE(低功耗藍牙)去拉取對方的資料,以及發送和處理好友申請。選擇 BLE 的主要原因包括:
- 完全離線運行
- 可以不配對直接交換資訊
- 可以在廣播封包中攜帶 ID 資訊
- 裝置發現速度和資料交換速度都還不錯
密鑰
在對方同意好友申請後,雙方將交換個人資料,包括各自的公鑰,這時是唯一取得對方公鑰的時機。以後幾乎所有的訊息都要透過各自的私鑰對資料包中幾乎所有的欄位 + 時間戳進行簽名,然後對方透過保存的對方公鑰進行驗簽。這主要是為了解決信任問題,防止竄改與偽造。
好友資料更新機制
每次發送心跳包都會帶一個基於時間戳的個人資料版本號,不是基於 JSON,而是一個輕量級的二進位資料包,這樣每次收到心跳,便與本地好友的個人資料版本號進行比對,如果有更新就主動向對方發起拉取資料的請求。首次加好友後,一開始的頭像其實是縮圖,因為藍牙的頻寬很小,但如果他們在同一個 Wi‑Fi 下,就會自動更新對方完整的資料。
5. 聊天頁面
文字訊息
- 支援表情
- 支援草稿訊息
- 超過 3 行後可進入全螢幕輸入框
輸入框自帶的語音輸入由於沒有接入伺服器,並不好用,可忽略~

語音訊息

表情訊息

圖片/影片訊息
- 支援實況圖片
- 支援顯示上傳進度
- 大影片傳輸,支援雙端進度顯示、雙端傳輸控制(暫停/繼續/取消),且支援斷點續傳、秒傳等
- 點擊將進入 app 內建的媒體選擇器
- 長按將進入系統原生的媒體選擇器(部分手機自帶的選擇器可以選擇擦除地理位置、相機參數等資訊,並提供更好的隱私保護)

相機
- 支援對焦
- 支援變焦
- 支援長按錄影
- 支援切換鏡頭
- 支援開關閃光燈
- 點擊將進入 app 內建的相機
- 長按將進入系統原生的相機(可選拍照/拍影片)

位置訊息
- 支援取得目前位置
- 支援搜尋位置
- 支援位置快照
- 支援拖動地圖自動查詢
- 支援點擊 POI 後聚焦及查詢附近位置
- 支援喚起導航軟體(將顯示已安裝的地圖 app 列表供使用者選擇)

名片訊息

檔案訊息
*為了支援進階傳輸功能,小檔案會直接傳輸,而大檔案則會先協商再傳輸
- 支援大檔秒傳
- 先計算檔案的
SHA-256 雜湊值
- 發送檔案的元資料給對方
- 對方查詢該雜湊值的檔案是否存在
- 已存在則回覆
AlreadyExists
- 不存在則回覆
ReadyToReceive
- 支援分片傳輸 + 斷點續傳
- 不使用傳統的保存若干個小分片檔案,避免合併時的 CPU 與磁碟 I/O 開銷
- 預建立一個與目標檔案大小一致的空檔案,該操作僅佔用 metadata 空間,有效避免了寫入過程中的頻繁磁碟空間申請與檔案碎片化。
- 捨棄傳統的
FileOutputStream 或 RandomAccessFile 阻塞式寫入,而採用 FileChannel 這種接近系統底層效率的 API,利用 FileChannel.position(offset) 精確控制資料落盤位置,顯著提升大檔在高併發寫入時的吞吐量。
- 支援併發傳輸
- 在
write 時加鎖避免資料污染
- 每個分片資料包攜帶訊息
id 和 offset,準確寫入指定訊息檔的指定位置
- 支援最多 3 個檔案同時傳輸
- 藍牙模式下限制為 1 個
- 即時傳送進度顯示
- 支援取消傳送
- 支援開啟檔案
- 支援儲存到本機
- 支援轉發檔案

傳送應用程式
- 支援選擇目前手機已安裝的 App
- 同傳送檔案的邏輯

傳送音樂
- 列表支援點擊預覽播放/暫停
- 音樂播放頁面(參考 NetEase 音樂)
- 暫停和播放時,唱片的啟停模擬物理世界的慣性
- 歌曲名稱支援循環滾動

通話
- 支援語音通話
- 支援視訊通話
- 支援麥克風/相機/喇叭開關或切換等
- 支援切換小窗畫面
- 小窗支援拖動與自動吸附
- 支援點擊空白處收起控制列
- 因為不用考慮帶寬問題,預設超清畫質 + CD 級音質
- 支援完全無網環境接打電話,如:Wi‑Fi 直連、Wi‑Fi 熱點模式
- 支援自訂來電鈴聲;支援播放對方設定的鈴聲
暫未支援懸浮窗、鎖屏接聽等
藍牙模式下支援交換訊令,但不支援通話(頻寬小且無 IP 位址)


聊天訊息 & 列表頁面
- 訊息免打擾
- 釘選聊天
- 設定聊天背景
- 清空聊天記錄
- 標記為未讀/已讀
- 隱藏聊天


6. 聯絡人頁面
聯絡人列表 & 新的朋友

聯絡人詳情
- 支援查看頭像
- 顯示暱稱、性別、個性簽名
- 支援設定備註名與備忘
- 顯示好友來源 & 添加時間

聯絡人設定

7. 設定頁面
通知設定
- 訊息通知開關
- 通話通知開關
- 通知顯示內容設定
- 系統通知設定入口
- 聊天介面的新訊息通知設定
- 訊息提示音設定
- 來電鈴聲設定
- 呼叫我時朋友也可聽見我的來電鈴聲開關

介面與顯示設定

朋友權限 & 更多設定
- 加我為朋友時需要驗證
- 通訊錄黑名單
- 系統權限取得狀態

連線模式 & 聊天 & 聊天記錄管理
Wi‑Fi Lan/Wi‑Fi Direct/藍牙 三種連線方式動態切換
- 設定全域聊天背景
- 使用聽筒播放語音訊息
- 使用獨立的發送按鈕
- 端到端加密:開啟後將使用
AES 加密 所有的資料包,無論是文字資料還是檔案分塊,且密鑰由每次握手時協商,私鑰僅存於記憶體
- 清空全部聊天記錄

8. 連線方式
無論底層基於何種連線方式,在上層都是一套 ConnectionManager,抽象出了共同的方法:發送訊息、接收訊息和心跳機制等。它們的差異主要體現在發現裝置,以及連線裝置的方式。像 Wi‑Fi Lan 和 Wi‑Fi Direct,它們可以基於共同的 TCPSocket,而藍牙則是基於 RfcommSocket。
理論上如果要切換到伺服器連線也是可以的。
Wi‑Fi Lan:需要裝置在同一 Wi‑Fi 下
- 技術實作方案:
- NSD(Network Service Discovery):Android 封裝的一套基於 UDP 的服務發現、註冊與解析機制。
- 局限性與風險
- AP 隔離限制:在旅館、機場、公司等公共 Wi‑Fi 環境中,路由器通常會開啟「AP 隔離」功能。此時,即便裝置在同一 SSID 下,防火牆也會攔截裝置間的 UDP 組播封包,導致 NSD 無法互相發現。
- 多播風暴抑制:部分企業級路由器為節省空口頻寬,會主動丟棄或限制多播資料包頻率。這會導致服務發現延遲較高,或在裝置較多時出現「發現不穩定」的現象。
- 系統級休眠影響:Android 的省電模式可能會在螢幕關閉後限制網路活動或延遲 UDP 包的接收。需要透過前景服務(Foreground Service)或申請忽略電池優化來維持發現機制的活躍。
Wi‑Fi Direct:需要手動選擇裝置並配對,支援無網環境
-
協定原理:與傳統 Wi‑Fi 需要路由器(AP)作為中心節點不同,Wi‑Fi Direct 允許裝置間透過軟體定義的「軟 AP」(Group Owner, GO)直接建立連線。
- 角色協商:連線時,兩台裝置會透過協定協商誰充當 GO (Group Owner),誰充當 GC (Group Client)。GO 負責管理 DHCP 分配 IP,GC 像連接普通 Wi‑Fi 一樣接入。
- 技術優勢
- 支援無網環境:完全脫離路由器限制,在戶外、偏遠地區或公共場所(禁用局域網通訊時)仍可實現高速互聯。
- 吞吐量極大:支援 802.11ac/ax 協定,理論頻寬可達數百 Mbps。由於是點對點直連,減少了路由器中轉的延遲與干擾。
- 安全性高:連線過程強制使用 WPS 機制(如 PIN 碼或 Push Button),確保物理隔離外的第三方無法監聽傳輸內容。

可以看到 Wi‑Fi 直連的傳輸速度是非常可觀的
藍牙:需要手動選擇裝置並配對,支援無網環境
- 技術實作方案:經典藍牙(RFCOMM)
- 透過模擬序列埠,提供相對穩定的串流傳輸。理論峰值速率約 2.1 Mbps,實測在 Android 裝置間約為 100–200 KB/s。
- 技術優勢
- 極強的抗干擾性:採用自適應跳頻(AFH)技術,在 2.4GHz 擁擠的環境下(如展覽、辦公室),藍牙的連線成功率通常高於 Wi‑Fi Direct。
- 協定級普適性:不依賴路由器,不依賴 Wi‑Fi 晶片狀態(即使 Wi‑Fi 正在連接熱點,藍牙也能並行工作)。
- 限制與痛點
- 頻寬瓶頸:由於速率限制,傳輸一個 100MB 的影片可能需要 10 分鐘以上。連傳一個表情包可能都有點慢,大家可以試一下。
- 共存干擾:由於藍牙與 Wi‑Fi 共享天線和 2.4GHz 頻段,在進行藍牙大流量傳輸時,可能會導致 Wi‑Fi 延遲劇增(Ping 值抖動)。
Wi‑Fi 熱點模式
- 其實在戶外環境,一個裝置開熱點,其他裝置連接也是可以的,甚至可以打電話,和 Wi‑Fi Direct 下類似,大家可以試一下~
五、原始程式碼 & 安裝包
原始程式碼
安裝包
註:為了保持鎖屏後的穩定連線,建議修改系統預設的省電策略為無限制。
六、結語
鐘睒睒說:
我們要不斷學習新的東西,打破自己原來知識結構的藩籬。
這個專案讓我學到了很多東西,現在也毫無保留地分享給大家,希望能幫到你~
完^_^
原文出處:https://juejin.cn/post/7621443853845594154