區域網路權限

凡具備 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 API android_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 上啟用區域網路限制,請按照下列步驟操作:

  1. 將裝置刷入 Android 16 Beta 3 以上版本
  2. 安裝要測試的應用程式
  3. 使用 ADB 切換 Appcompat 設定

    adb shell am compat enable RESTRICT_LOCAL_NETWORK <package_name>
    
  4. 重新啟動裝置

現在,應用程式對區域網路的存取權已受限,任何嘗試存取區域網路的行為都會導致通訊端錯誤。如果您使用的 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 存取權不應遭到封鎖,但卻遭到封鎖

下列項目應不受這項異動影響:

  • 連上網際網路
  • 行動網路