凡具備 INTERNET 權限的應用程式,都能存取區域網路 (LAN) 上的裝置。雖然應用程式可因此輕鬆連線到本機裝置,但也帶來隱私疑慮,例如建立使用者數位指紋,或成為推算位置資訊的依據。
區域網路保護措施專案旨在保護使用者隱私,因此會透過新的執行階段權限,限制對區域網路的存取。
影響
自 Android 17 (API 級別 37) 起,指定 Android 17 以上版本的應用程式會強制執行區域網路保護措施。先前的 Android 16 選擇加入設定已淘汰;如需目前的實作規定,請參閱「Android 17 強制執行」。
如果應用程式使用下列方式存取使用者的區域網路,就會受到影響:
- 直接或透過程式庫使用區域網路位址上的原始通訊端,例如
Multicast DNS (mDNS)或Simple Service Discovery Protocol (SSDP)。 - 使用存取區域網路的架構層級類別,例如
NsdManager。
影響詳情
往返區域網路位址的流量需要區域網路存取權限。下表列出一些常見情況:
| 應用程式低層級網路作業 | 必須授予區域網路權限 |
|---|---|
| 建立傳出 TCP 連線 | 是 |
| 接受傳入的 TCP 連線 | 是 |
| 傳送 UDP 單點傳播、多點傳送、廣播 | 是 |
| 接收傳入的 UDP 單點傳播、多點傳播、廣播 | 是 |
這些限制是在網路堆疊深處實施,因此適用於所有網路 API。包括在平台或代管程式碼中建立的通訊端、Cronet 和 OkHttp 等網路程式庫,以及在這些程式庫上實作的任何 API。如要嘗試解析區域網路上具有 .local 尾碼的服務,必須具備區域網路權限。
上述規則的例外狀況:
- 如果裝置的 DNS 伺服器位於區域網路,則往返該伺服器的流量 (通訊埠 53) 不需要區域網路存取權限。
- 如果應用程式使用輸出切換器做為應用程式內挑選器,就不需要區域網路權限 (後續版本會提供更多指引)。
Android 17 違規處置
自 Android 17 起,指定 Android 17 以上版本的應用程式必須強制執行區域網路保護措施。
| 切面 | Android 16 | Android 17 |
|---|---|---|
| 目標 SDK 版本 | 36 | 37 以上 |
| 權限 | 暫時使用 NEARBY_WIFI_DEVICES | ACCESS_LOCAL_NETWORK |
| 預設存取權 | 已開放區域網路存取權 | 根據預設,所有更新目標 SDK 的應用程式都會封鎖區域網路 |
| 權限群組 | 屬於現有 NEARBY_DEVICES 權限群組 | |
為確保應用程式功能在強制執行後不會中斷,指定 SDK 37 以上版本的應用程式必須採用下列其中一種路徑,管理區域網路存取權:
路徑 A:使用隱私權保護挑選器
如果是系統中介的探索和連線工作,請使用挑選器,完全避免要求廣泛的執行階段權限。請根據您的用途,使用下列挑選器:
- 媒體串流:支援 Google Cast 的應用程式可以使用輸出端切換器功能。這樣一來,開發人員就能讓使用者選取特定串流裝置,而應用程式不必要求廣泛的
ACCESS_LOCAL_NETWORK權限。 - 一般連線能力:
NsdManager包含系統執行的服務挑選器,用於 mDNS 探索。系統不會讓應用程式掃描整個網路,而是顯示對話方塊,讓使用者選取要讓應用程式存取的單一裝置。
val discoveryRequest = DiscoveryRequest.Builder("_http._tcp")
.setFlags(DiscoveryRequest.FLAG_SHOW_PICKER)
.build()
nsdManager.registerServiceInfoCallback(discoveryRequest, executor, object : NsdManager.ServiceInfoCallback {
override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {
// Handle the user-selected and discovered service
// NsdServiceInfo.getHostAddresses() can now be connected to
// without ACCESS_LOCAL_NETWORK permission
}
})
路徑 B:要求執行階段權限 (廣泛存取權)
如果用途較複雜,例如家用裝置自動化或物聯網裝置管理,需要廣泛且持續存取區域網路,就必須採用這個路徑。
在資訊清單中宣告權限:在
AndroidManifest.xml中明確宣告ACCESS_LOCAL_NETWORK。在執行階段要求權限:應用程式必須先檢查是否已取得權限,才能嘗試存取區域網路。否則,必須呼叫
Activity.requestPermission()觸發標準系統提示。預先授予情境:
ACCESS_LOCAL_NETWORK權限屬於NEARBY_DEVICES權限群組。如果使用者已授予這個群組中的其他權限 (例如藍牙權限),系統就不會再次提示要求授予區域網路存取權。處理拒絕和撤銷:如果使用者拒絕要求,或之後在系統設定中撤銷權限,應用程式必須妥善處理。在這種情況下,區域網路流量會遭到封鎖。
權限要求重設計數器策略
平台會實施計數器重設策略,解決應用程式先前拒絕 NEARBY_DEVICES 權限群組 (現在包含 ACCESS_LOCAL_NETWORK),導致應用程式在充分說明理由後無法要求權限的情況。這項機制可讓應用程式有更多機會叫用 requestPermission() API,有效重設 ACCESS_LOCAL_NETWORK 權限的拒絕次數。這樣一來,您就能更細緻地重新與使用者互動,尤其是在應用程式尚未說明核心功能需要區域網路存取權,使用者就拒絕授權的情況下。
拆分權限模型
區域網路權限採用分割權限遷移策略,根據目標 SDK 版本,以不同方式處理新版和舊版應用程式。
| 類別 | 目標 SDK 級別 | 區域網路存取行為 | 開發人員敬請配合 |
|---|---|---|---|
| 新應用程式/更新的應用程式 | >= 37 (Android 17) | 預設封鎖 | 宣告並要求 ACCESS_LOCAL_NETWORK 執行階段權限 |
| 舊版應用程式 | < 37 | 具備 INTERNET 權限的應用程式會獲得 ACCESS_LOCAL_NETWORK 的隱性權限,因此可繼續存取。這是暫時性措施,應用程式將目標 SDK 升級至 37 後,系統就會預設封鎖這項功能 |
目前不需要立即變更程式碼。在指定 SDK 37 之前,請勿在執行階段要求 ACCESS_LOCAL_NETWORK。 |
依用途區分 LNP 策略
投放:針對媒體投放功能,最合適且能保護隱私權的策略是使用輸出切換器。這個方法可讓系統代表使用者處理區域網路探索和連線,應用程式就不需要要求
ACCESS_LOCAL_NETWORK權限。瀏覽器:處理錯誤時,必須根據通訊協定採取不同做法。UDP 錯誤會導致
EPERM錯誤代碼。如果是 TCP 連線,瀏覽器應使用 NDK APIandroid_getnetworkblockedreason(int sockFd)判斷封包是否遭到 LNP 封鎖,這個 API 會傳回ANDROID_NETWORK_BLOCKED_REASON_LNP。其他用途 (例如 IoT):使用 mDNS 尋找裝置的應用程式應使用
android.net.nsd.DiscoveryRequest#FLAG_SHOW_PICKER,這樣不需權限即可尋找裝置,並使用NsdManager#registerServiceInfoCallback/NsdManager#resolveService取得 IP 位址。透過這種方式取得的 IP 位址連線不需要ACCESS_LOCAL_NETWORK權限。
如果應用程式需要直接進行區域網路通訊,且無法使用系統中介的挑選器,建議在指定 Android 17 (SDK 37) 以上版本時,採用權限重設計數器策略。如果使用者撤銷 ACCESS_LOCAL_NETWORK 權限,這項機制可讓應用程式有機會再次要求權限,開發人員也能向使用者清楚說明原因。
Android 16 指南 (已淘汰)
如要在 Android 16 上啟用區域網路限制,請按照下列步驟操作:
- 將裝置刷入 Android 16 Beta 3 以上版本
- 安裝要測試的應用程式
使用 ADB 切換 Appcompat 設定
adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>重新啟動裝置
現在,應用程式對區域網路的存取權已受限,任何嘗試存取區域網路的行為都會導致通訊端錯誤。如果您使用的 API 會在應用程式程序之外執行區域網路作業 (例如 NsdManager),則在選擇加入期間不會受到影響。
如要恢復存取權,請授予應用程式NEARBY_WIFI_DEVICES權限。
- 確認應用程式在
manifest中宣告NEARBY_WIFI_DEVICES權限。 - 依序前往「設定」>「應用程式」> [應用程式名稱] >「權限」>「鄰近裝置」>「允許」
現在,應用程式應可重新存取區域網路,且所有情境都應能正常運作,就像在應用程式啟用這項功能前一樣。以下說明應用程式網路流量受到的影響。
| 權限 | 傳出 LAN 要求 | 傳出/傳入網際網路要求 | 傳入 LAN 要求 |
|---|---|---|---|
| 已授予 | Works | Works | Works |
| 未授予 | 凸槌影片 | Works | 凸槌影片 |
使用下列指令關閉 Appcompat 設定
adb shell am compat disable RESTRICT_LOCAL_NETWORK <package_name>
錯誤
如果區域網路存取要求因缺少權限而失敗:
TCP 連線通常會導致逾時錯誤。
UDP 錯誤和一般權限遭拒通常會導致 EPERM 錯誤代碼
錯誤
回報錯誤和提供意見:
- 區域網路存取權不一致 (您認為不應將特定存取權視為「區域網路」存取權)
- LAN 存取權應遭封鎖,但未封鎖的錯誤
- LAN 存取權不應遭到封鎖,但卻遭到封鎖
下列項目應不受這項異動影響:
- 連上網際網路
- 行動網路