1. 程式人生 > >Android中的WiFi P2P(二)

Android中的WiFi P2P(二)

Android中的WiFi P2P能夠允許一定範圍內的裝置通過Wifi直接互連而不必通過熱點或網際網路。

使用WiFi P2P需要Android API Level >= 14才可以,而且不要忘記在Manifest檔案中加入下面5個許可權:

● android.permission.ACCESS_WIFI_STATE

● android.permission.CHANGE_WIFI_STATE

● android.permission.ACCESS_NETWORK_STATE

● android.permission.CHANGE_NETWORK_STATE

● android.permission.INTERNET (WiFi P2P並不需要連線網際網路,但是因為要用到

Java Socket,所以要加這個許可權)

關於WiFi P2P的操作幾乎都靠WifiP2pManager來進行,所以如果你的程式要用到WiFi P2P功能,可以設定一個全域性變數wifiP2pManager,然後在onCreate()生命函式中獲取系統WifiP2pManager物件:

?
1 <span style="font-family:Microsoft YaHei;">wifiP2pManager = (WifiP2pManager) getApplicationContext().getSystemService(Context.WIFI_P2P_SERVICE);</span>

WifiP2pManager有如下方法可以很方便的進行P2P操作:
方法 功能
initialize() 在使用WiFi P2P功能時必須先呼叫這個方法,用來通過WiFi P2P框架註冊我們的應用
connect() 根據配置(WifiP2pConfig物件)與指定裝置(WifiP2pDevice物件)進行P2P連線
cancelConnect() 關閉某個P2P連線
requestConnectInfo() 獲取裝置的連線資訊
createGroup() 以當前的裝置為組長建立P2P小組
removeGroup() 移除當前的P2P小組
requestGroupInfo() 獲取P2P小組的資訊
discoverPeers() 初始化peers發現操作
requestPeers() 獲取當前的peers列表(通過discoverPeers發現來的)
每當WifiP2pManager執行某個P2P操作時,可以通過不同的監聽器來檢測這些操作的反饋結果,這些監聽器的型別如下:
監聽器 關聯的行為
WifiP2pManager.ActionListener connect(), cancelConnect(), createGroup(), removeGroup()discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

那麼接下來就可以講解如何使用WiFi P2P了。

一. 準備工作

準備階段需要讓我們的應用可以接受P2P訊號,這就需要一個意圖廣播接收器,要建立一個符合我們要求的廣播接收器需要準備下面3個要素:

(1) 一個意圖廣播接收器,用來接受意圖廣播。

(2) 通過WifiP2pManager的initialize()初始化操作來獲取一個Channel物件,用於以後和WiFi P2P框架保持通訊。

(3) 自己包裝BroadcastReceiver類,實現一個接收器。

意圖過濾器使用如下方法建立:

?
1 2 3 4 5 6 // 設定intent過濾器 intentFilter = new IntentFilter();  //一個全域性的intentFilter物件 intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);       // WiFi P2P是否可用 intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);       // peers列表發生變化 intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);  // WiFi P2P連線發生變化 intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); // WiFi P2P裝置資訊發生變化(比如更改了裝置名)

Channel的獲取方法:
?
1 channel = wifiP2pManager.initialize(getApplicationContext(), getMainLooper(), null); // channel是一個全域性的Channel物件
意圖廣播接收器的建立需要通過繼承BroadcastReceiver類來自己實現,下面給出了一段示例: ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class MyBroadcastReceiver extends BroadcastReceiver { // 使用WiFi P2P時,自己定義的BroadcastReceiver的建構函式一定要包含下面這三個要素 private WifiP2pManager wifiP2pManager; private Channel channel; private Activity activity; public MyBroadcastReceiver(WifiP2pManager wifiP2pManager, Channel channel, Activity activity) { this.wifiP2pManager = wifiP2pManager; this.channel = channel; this.activity = activity; } // onReceiver對相應的intent進行處理 @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { 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)) { } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { } } }

定義完了之後就可以再需要的地方例項化一個意圖廣播接收器物件了:

?
1 broadcastReceiver = new MyBroadcastReceiver(wifiP2pManager, channel, this);
那麼三個要素都具備了之後就要嚮應用註冊我們的接收器,好讓它可以開始工作: ?
1 registerReceiver(broadcastReceiver, intentFilter);

二. 啟動peers發現

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void discoverPeers(View view) { peerListListener = new WifiP2pManager.PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList peerList) { peers.clear();   // peers是一個全域性ArrayList物件,用於儲存發現的peers的資訊 peers.addAll(peerList.getDeviceList()); // 如果你有一個控制元件用來顯示這些peers的資訊,就可以再這裡更新了 } }; wifiP2pManager.discoverPeers(channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "discover peers!", Toast.LENGTH_SHORT); } @Override public void onFailure(int arg0) { } }); // discoverPeers是非同步執行的,呼叫了之後會立刻返回,但是發現的過程一直在進行, // 直到發現了某個裝置時就會通知你 }
當發現了裝置之後就會觸發WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION意圖廣播,你可以再之前自己包裝的BroadcastReceiver類中加入對這一意圖的處理: ?
1 2 3 4 5 else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { if (wifiP2pManager != null) { wifiP2pManager.requestPeers(channel, peerListListener); } }

三. 與peers建立連線

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public void connect() { final WifiP2pDevice device = (WifiP2pDevice) peers.get(0); //從peers列表中獲取發現來的第一個裝置 WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; wifiP2pManager.connect(channel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { // 連線成功 Toast.makeText(getApplicationContext(), "與裝置" + device.deviceName + "連線成功", Toast.LENGTH_LONG).show(); } @Override public void onFailure(int arg0) { // 連線失敗 Toast.makeText(getApplicationContext(), "與裝置" + device.deviceName + "連線失敗", Toast.LENGTH_LONG).show(); } }); }
每當有P2P連線狀態發生改變時,就會觸發WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION意圖廣播,可以在之前你自己包裝的BroadcastReceiver類中加入對這一意圖的處理: ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { if (wifiP2pManager == null) return; NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); <span style="white-space:pre">  </span>if (networkInfo.isConnected()) { // We are connected with the other device, request // connection // info to find group owner IP wifiP2pManager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() { @Override public void onConnectionInfoAvailable(WifiP2pInfo info) { // 這裡可以檢視變化後的網路資訊 // 通過傳遞進來的WifiP2pInfo引數獲取變化後的地址資訊 InetAddress groupOwnerAddress = info.groupOwnerAddress; // 通過協商,決定一個小組的組長 if (info.groupFormed && info.isGroupOwner) { // 這裡執行P2P小組組長的任務。 // 通常是建立一個服務執行緒來監聽客戶端的請求 } else if (info.groupFormed) { // 這裡執行普通組員的任務 // 通常是建立一個客戶端向組長的伺服器傳送請求 } } }); } }