Android WiFi協議之P2P介紹與實踐

Android WiFi P2P

WiFi P2P (Peer-to-Peer) 是 Android 提供的一種允許設備之間直接通過 WiFi 進行通信的技術,無需接入傳統的 WiFi 網絡或互聯網。這種技術也被稱為 WiFi Direct。

一、WiFi P2P 基本概念

1. 核心組件

  • P2P 設備:支持 WiFi P2P 的 Android 設備

  • P2P 組:由一個組所有者(Group Owner, GO)和多個客戶端組成

  • 組所有者(GO):相當于傳統 WiFi 網絡中的接入點(AP)

  • 客戶端:連接到 GO 的設備

2. 工作流程

  1. 發現附近設備

  2. 請求連接

  3. 建立 P2P 組

  4. 數據傳輸

  5. 斷開連接

二、WiFi P2P API 詳解

1. 主要類

  • WifiP2pManager:主管理類,提供發現、連接等方法

  • WifiP2pManager.Channel:與 WiFi P2P 框架通信的通道

  • WifiP2pDevice:表示一個 P2P 設備

  • WifiP2pInfo:包含 P2P 連接信息

  • WifiP2pGroup:表示 P2P 組信息

  • WifiP2pConfig:用于配置 P2P 連接

2. 權限要求

在 AndroidManifest.xml 中添加:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />

注意:從 Android 12 開始,需要 NEARBY_WIFI_DEVICES 權限來發現和連接附近的設備

三、WiFi P2P 實現代碼

1. 初始化

// 獲取 WifiP2pManager 和 Channel
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);// 創建廣播接收器
private final IntentFilter intentFilter = new IntentFilter();@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 添加必要的 Intent 過濾器intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);// 注冊廣播接收器receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);registerReceiver(receiver, intentFilter);
}

2. 廣播接收器實現

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {private WifiP2pManager manager;private Channel channel;private Activity activity;public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel, Activity activity) {this.manager = manager;this.channel = channel;this.activity = activity;}@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {// 檢查 WiFi P2P 是否啟用int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {// WiFi P2P 已啟用} else {// WiFi P2P 未啟用}} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// 發現對等設備列表已更新if (manager != null) {manager.requestPeers(channel, peerListListener);}} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// P2P 連接狀態改變if (manager != null) {NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {// 已連接,請求連接信息manager.requestConnectionInfo(channel, connectionInfoListener);}}} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {// 本設備信息已更新}}
}

3. 發現附近設備

// 開始發現設備
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 發現過程成功啟動}@Overridepublic void onFailure(int reason) {// 發現過程啟動失敗}
});// 處理發現的設備列表
private WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {@Overridepublic void onPeersAvailable(WifiP2pDeviceList peers) {// 處理發現的設備列表List<WifiP2pDevice> devices = new ArrayList<>(peers.getDeviceList());// 更新UI或進行其他處理}
};

4. 連接設備

// 選擇要連接的設備
WifiP2pDevice device = ...; // 從發現的設備列表中選擇// 創建連接配置
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC; // 使用按鈕配置方式// 發起連接
manager.connect(channel, config, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 連接請求成功發送}@Overridepublic void onFailure(int reason) {// 連接失敗}
});

5. 獲取連接信息

private WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {@Overridepublic void onConnectionInfoAvailable(WifiP2pInfo info) {// 處理連接信息InetAddress groupOwnerAddress = info.groupOwnerAddress;if (info.groupFormed && info.isGroupOwner) {// 當前設備是組所有者(GO)// 需要在此處設置服務器套接字} else if (info.groupFormed) {// 當前設備是客戶端// 需要連接到GO的IP地址}}};

6. 數據傳輸

建立連接后,可以使用套接字進行數據傳輸:

組所有者(GO)端代碼
// 創建服務器套接字
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept();// 獲取輸入輸出流
DataInputStream inputStream = new DataInputStream(client.getInputStream());
DataOutputStream outputStream = new DataOutputStream(client.getOutputStream());// 讀取數據
String message = inputStream.readUTF();// 發送數據
outputStream.writeUTF("Hello from GO!");
客戶端端代碼
// 連接到GO
Socket socket = new Socket(groupOwnerAddress.getHostAddress(), 8888);// 獲取輸入輸出流
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());// 發送數據
outputStream.writeUTF("Hello from client!");// 讀取數據
String message = inputStream.readUTF();

7. 斷開連接

manager.removeGroup(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 成功斷開連接}@Overridepublic void onFailure(int reason) {// 斷開連接失敗}
});

四、常見問題與解決方案

  1. 設備無法發現其他設備

    • 確保兩臺設備都啟用了 WiFi P2P

    • 檢查是否授予了必要權限(特別是位置權限)

    • 確保設備之間距離足夠近(通常不超過10米)

  2. 連接失敗

    • 檢查設備是否支持 WiFi Direct

    • 嘗試不同的 WPS 配置方法(PBC 或 KEYPAD)

    • 重啟設備的 WiFi

  3. 數據傳輸問題

    • 確保在獲取連接信息后才嘗試建立套接字連接

    • 檢查防火墻設置是否阻止了端口通信

    • 確保正確處理了網絡操作線程(不要在UI線程執行網絡操作)

  4. Android 12 及更高版本的兼容性

    • 添加 NEARBY_WIFI_DEVICES 權限

    • 如果不需要位置信息,設置 usesPermissionFlags="neverForLocation"

    • 考慮添加 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 權限以獲得更好的兼容性

五、最佳實踐

  1. 用戶體驗優化

    • 在發現和連接過程中顯示適當的進度指示

    • 提供明確的連接狀態反饋

    • 處理各種錯誤情況并提供恢復選項

  2. 性能考慮

    • 發現過程消耗較多電量,應在必要時才啟動

    • 連接建立后及時停止發現過程

    • 考慮使用服務來處理長時間運行的網絡操作

  3. 安全性

    • 驗證連接設備的身份(如設備名稱或其他標識)

    • 考慮在應用層添加加密機制

    • 敏感數據傳輸使用安全協議

  4. 兼容性處理

    • 檢查設備是否支持 WiFi P2P:manager != null && channel != null

    • 為舊版本 Android 提供備用方案

    • 處理不同廠商設備的兼容性問題

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76435.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76435.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76435.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

淺談在HTTP中GET與POST的區別

從 HTTP 報文來看&#xff1a; GET請求方式將請求信息放在 URL 后面&#xff0c;請求信息和 URL 之間以 &#xff1f;隔開&#xff0c;請求信息的格式為鍵值對&#xff0c;這種請求方式將請求信息直接暴露在 URL 中&#xff0c;安全性比較低。另外從報文結構上來看&#xff0c…

若依微服務集成Flowable仿釘釘工作流

項目簡介 本項目工作流模塊集成在若依項目單獨一個模塊&#xff0c;可實現單獨運行部署&#xff0c; 前端采用微前端&#xff0c;嵌入在若依的前端項目中。因博主是后端開發&#xff0c;對前端不是太屬性&#xff0c;沒將工作流模塊前端代碼移到若依前端。下面貼上代碼工程結構…

WPS JS宏編程教程(從基礎到進階)-- 第六部分:JS集合與映射在 WPS 的應用

目錄 第6章 JS集合與映射在 WPS 的應用6-1 集合的創建(實例:唯一值提取)示例代碼詳細解析Excel 環境模擬說明6-2 集合的不重復特性應用(案例:提取唯一值記錄)示例代碼詳細解析案例說明6-3 集合成員添加與刪除示例代碼代碼解析直觀示意(Excel 模擬表格)6-4 集合成員添加…

MySQL 約束(入門版)

目錄 一、約束的基本概念 二、約束演示 三、外鍵約束 &#xff08;一&#xff09;介紹 &#xff08;二&#xff09;外鍵約束語法 &#xff08;三&#xff09;刪除/更新行為 一、約束的基本概念 1、概念&#xff1a;約束是作用于表中字段上的規則&#xff0c;用于限制存儲…

【ISP】ISP pipeline(AI)

ISP Pipeline 全流程概覽 ISP&#xff08;Image Signal Processing&#xff0c;圖像信號處理&#xff09;流程通常從原始 Bayer 數據出發&#xff0c;經過一系列模塊處理&#xff0c;逐步完成圖像校正和增強&#xff0c;最終生成用于顯示或編碼的標準圖像。常見處理模塊包括&a…

【Rust開發】Rust快速入門,開發出Rust的第一個Hello World

?? 歡迎大家來到景天科技苑?? &#x1f388;&#x1f388; 養成好習慣&#xff0c;先贊后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者簡介&#xff1a;景天科技苑 &#x1f3c6;《頭銜》&#xff1a;大廠架構師&#xff0c;華為云開發者社區專家博主&#xff0c;…

Google Chrome下載受限制的解決方案【方法指南】

在國內使用網絡時&#xff0c;部分用戶在嘗試訪問Google Chrome官網下載谷歌瀏覽器時&#xff0c;常常遇到網頁無法打開或文件下載失敗的情況。這種下載受限制的問題多由網絡訪問政策或DNS解析異常導致。為了正常獲取Google Chrome的最新版安裝程序&#xff0c;用戶需要通過一些…

使用 new EventSource 實現前端實時通信

示例&#xff1a; eventSource單向通信 1. 什么是 EventSource&#xff1f; EventSource 是瀏覽器提供的一種實現服務器推送&#xff08;Server-Sent Events&#xff0c;簡稱 SSE&#xff09;功能的 API。它是基于 HTTP 協議的單向通信機制&#xff0c;可以通過服務器將實時數…

Android Input——查找并添加目標窗口(七)

在 Android 輸入系統中,InputDispatcher 的核心職責之一是將輸入事件正確地傳遞到目標窗口。上一篇文章我們介紹到 InputDispatcher 事件分發調用到 findFocusedWindowTargetsLocked() 函數查找焦點窗口,并將焦點窗口添加到目標窗口,這里我們繼續往下看。 一、獲取焦點窗口…

Spring Boot中Spring MVC相關配置的詳細描述及表格總結

以下是Spring Boot中Spring MVC相關配置的詳細描述及表格總結&#xff1a; Spring MVC 配置項詳解 1. 異步請求配置 spring.mvc.async.request-timeout 描述&#xff1a;設置異步請求的超時時間&#xff08;單位&#xff1a;毫秒&#xff09;。默認值&#xff1a;未設置&…

HTTP GET 和 POST 請求有什么區別

HTTP 的 GET 和 POST 請求是兩種常見的 HTTP 請求方法&#xff0c;它們有不同的特點和應用場景。以下是它們的主要區別&#xff1a; 1. 用途 GET&#xff1a;用于從服務器獲取數據或資源。GET 請求會附帶查詢參數在 URL 中&#xff0c;通常用于請求數據&#xff0c;如加載網頁…

從入門到精通【MySQL】 聯合查詢

文章目錄 &#x1f4d5;摘要&#x1f4d5;1. 多表聯合查詢時MySQL內部原理??1.1 實例&#xff1a;一個完整的聯合查詢過程 &#x1f4d5;2. 內連接&#x1f4d5;3. 外連接&#x1f4d5;4. 自連接&#x1f4d5;5. 子查詢??5.1 單行子查詢??5.2 多行子查詢??5.3 多列子查…

高可用之戰:Redis Sentinal(哨兵模式)

參考&#xff1a;Redis系列24&#xff1a;Redis使用規范 - Hello-Brand - 博客園 1 背景 在我們的《Redis高可用之戰&#xff1a;主從架構》篇章中&#xff0c;介紹了Redis的主從架構模式&#xff0c;可以有效的提升Redis服務的可用性&#xff0c;減少甚至避免Redis服務發生完…

加密≠安全:文件夾密碼遺忘背后的數據丟失風險與應對

在數字化時代&#xff0c;保護個人隱私和數據安全變得尤為重要。許多人選擇對重要文件夾進行加密&#xff0c;以防止未經授權的訪問。然而&#xff0c;一個常見且令人頭疼的問題也隨之而來——文件夾加密密碼遺忘。當你突然發現自己無法訪問那些加密的文件夾時&#xff0c;那種…

WPS宏開發手冊——附錄

目錄 系列文章7、附錄 系列文章 使用、工程、模塊介紹 JSA語法 JSA語法練習題 Excel常用Api Excel實戰 常見問題 附錄 7、附錄 顏色序列&#xff1a;在excel中設置顏色&#xff0c;只能設置顏色序號&#xff0c;不能直接設置rgb顏色 1、黑色 (Black)…

C++基礎精講-02

文章目錄 1.C/C申請、釋放堆空間的方式對比1.1C語言申請、釋放堆空間1.2C申請、釋放堆空間1.2.1 new表達式申請數組空間 1.3回收空間時的注意事項1.4malloc/free 和 new/delete 的區別 2.引用2.1 引用的概念2.2 引用的本質2.3 引用與指針的聯系與區別2.4 引用的使用場景2.4.1 引…

Spring Boot MongoDB 分頁工具類封裝 (新手指南)

Spring Boot MongoDB 分頁工具類封裝 (新手指南) 目錄 引言&#xff1a;為何需要分頁工具類&#xff1f;工具類一&#xff1a;PaginationUtils - 簡化 Pageable 創建 設計目標代碼實現 (PaginationUtils.java)如何使用 PaginationUtils 工具類二&#xff1a;PageResponse<…

MyBatis的緩存、逆向工程、使用PageHelper、使用PageHelper

一、MyBatis的緩存 緩存&#xff1a;cache 緩存的作用&#xff1a;通過減少IO的方式&#xff0c;來提高程序的執行效率。 mybatis的緩存&#xff1a;將select語句的查詢結果放到緩存&#xff08;內存&#xff09;當中&#xff0c;下一次還是這條select語句的話&#xff0c;直…

java中的JNI調用c庫

1. 簡單demo 如果是在某個項目中有包名就需要自己找ai問問去改寫下cmd命令去編譯執行等 java文件&#xff08;HelloJNI.java&#xff09; public class HelloJNI {// 聲明 native 方法public native void sayHello();// 加載本地庫static {System.loadLibrary("hello&quo…

人工智能:GPT技術應用與未來展望

GPT(Generative Pre-trained Transformer)作為自然語言處理領域的代表性技術,近年來在各行業的實際應用中展現出廣泛潛力。結合其技術特性與行業需求,以下是GPT的主要應用場景、案例分析及未來挑戰的總結: 一、核心應用領域與案例 文本生成與內容創作 自動化內容生產:GPT…