W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
編寫:naizhengtan - 原文:http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html
Wi-Fi 點對點(P2P)API 允許應(yīng)用程序在無需連接到網(wǎng)絡(luò)和熱點的情況下連接到附近的設(shè)備。(Android Wi-Fi P2P 使用 Wi-Fi Direct? 驗證程序進行編譯)。Wi-Fi P2P 技術(shù)使得應(yīng)用程序可以快速發(fā)現(xiàn)附近的設(shè)備并與之交互。相比于藍(lán)牙技術(shù),Wi-Fi P2P 的優(yōu)勢是具有較大的連接范圍。
本節(jié)主要內(nèi)容是使用 Wi-Fi P2P 技術(shù)發(fā)現(xiàn)并連接到附近的設(shè)備。
使用 Wi-Fi P2P 技術(shù),需要添加 CHANGE_WIFI_STATE,ACCESS_WIFI_STATE 以及 INTERNET 三種權(quán)限到應(yīng)用的 manifest 文件。Wi-Fi P2P 技術(shù)雖然不需要訪問互聯(lián)網(wǎng),但是它會使用標(biāo)準(zhǔn)的 Java socket(需要 INTERNET 權(quán)限)。下面是使用 Wi-Fi P2P 技術(shù)需要申請的權(quán)限。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.nsdchat"
...
<uses-permission
android:required="true"
android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission
android:required="true"
android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission
android:required="true"
android:name="android.permission.INTERNET"/>
...
使用 Wi-Fi P2P 的時候,需要偵聽當(dāng)某個事件出現(xiàn)時發(fā)出的broadcast intent。在應(yīng)用中,實例化一個 IntentFilter,并將其設(shè)置為偵聽下列事件:
指示 Wi-Fi P2P 是否開啟
代表對等節(jié)點(peer)列表發(fā)生了變化
WIFI_P2P_CONNECTION_CHANGED_ACTION
表明Wi-Fi P2P的連接狀態(tài)發(fā)生了改變
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
指示設(shè)備的詳細(xì)配置發(fā)生了變化
private final IntentFilter intentFilter = new IntentFilter();
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Indicates a change in the Wi-Fi P2P status.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
// Indicates a change in the list of available peers.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
// Indicates the state of Wi-Fi P2P connectivity has changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
// Indicates this device's details have changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
...
}
在 onCreate() 方法的最后,需要獲得 WifiPpManager 的實例,并調(diào)用它的 initialize() 方法。該方法將返回 WifiP2pManager.Channel 對象。 我們的應(yīng)用將在后面使用該對象連接 Wi-Fi P2P 框架。
@Override
Channel mChannel;
public void onCreate(Bundle savedInstanceState) {
....
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
}
接下來,創(chuàng)建一個新的 BroadcastReceiver 類偵聽系統(tǒng)中 Wi-Fi P2P 狀態(tài)的變化。在 onReceive() 方法中,加入對上述四種不同 P2P 狀態(tài)變化的處理。
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// Determine if Wifi P2P mode is enabled or not, alert
// the Activity.
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
activity.setIsWifiP2pEnabled(true);
} else {
activity.setIsWifiP2pEnabled(false);
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// The peer list has changed! We should probably do something about
// that.
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// Connection state changed! We should probably do something about
// that.
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
.findFragmentById(R.id.frag_list);
fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
}
}
最后,在主 activity 開啟時,加入注冊 intent filter 和 broadcast receiver 的代碼,并在 activity 暫?;蜿P(guān)閉時,注銷它們。上述做法最好放在 onResume() 和 onPause() 方法中。
/** register the BroadcastReceiver with the intent values to be matched */
@Override
public void onResume() {
super.onResume();
receiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
registerReceiver(receiver, intentFilter);
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
調(diào)用 discoverPeers() 開始搜尋附近帶有 Wi-Fi P2P 的設(shè)備。該方法需要以下參數(shù):
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// Code for when the discovery initiation is successful goes here.
// No services have actually been discovered yet, so this method
// can often be left blank. Code for peer discovery goes in the
// onReceive method, detailed below.
}
@Override
public void onFailure(int reasonCode) {
// Code for when the discovery initiation fails goes here.
// Alert the user that something went wrong.
}
});
需要注意的是,這僅僅表示對Peer發(fā)現(xiàn)(Peer Discovery)完成初始化。discoverPeers() 方法開啟了發(fā)現(xiàn)過程并且立即返回。系統(tǒng)會通過調(diào)用 WifiP2pManager.ActionListener 中的方法通知應(yīng)用對等節(jié)點發(fā)現(xiàn)過程初始化是否正確。同時,對等節(jié)點發(fā)現(xiàn)過程本身仍然繼續(xù)運行,直到一條連接或者一個 P2P 小組建立。
在完成對等節(jié)點發(fā)現(xiàn)過程的初始化后,我們需要進一步獲取附近的對等節(jié)點列表。第一步是實現(xiàn) WifiP2pManager.PeerListListener 接口。該接口提供了 Wi-Fi P2P 框架發(fā)現(xiàn)的對等節(jié)點信息。下列代碼實現(xiàn)了相應(yīng)功能:
private List peers = new ArrayList();
...
private PeerListListener peerListListener = new PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
// Out with the old, in with the new.
peers.clear();
peers.addAll(peerList.getDeviceList());
// If an AdapterView is backed by this data, notify it
// of the change. For instance, if you have a ListView of available
// peers, trigger an update.
((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
if (peers.size() == 0) {
Log.d(WiFiDirectActivity.TAG, "No devices found");
return;
}
}
}
接下來,完善 Broadcast Receiver 的 onReceiver() 方法。 當(dāng)收到 WIFI_P2P_PEERS_CHANGED_ACTION 事件時, 調(diào)用 requestPeer() 方法獲取對等節(jié)點列表。我們需要將 WifiP2pManager.PeerListListener 傳遞給 receiver。一種方法是在 broadcast receiver 的構(gòu)造函數(shù)中,將對象作為參數(shù)傳入。
public void onReceive(Context context, Intent intent) {
...
else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Request available peers from the wifi p2p manager. This is an
// asynchronous call and the calling activity is notified with a
// callback on PeerListListener.onPeersAvailable()
if (mManager != null) {
mManager.requestPeers(mChannel, peerListListener);
}
Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
}...
}
現(xiàn)在,一個帶有 WIFI_P2P_PEERS_CHANGED_ACTION action 的 intent 將觸發(fā)應(yīng)用對 Peer 列表的更新。
為了連接到一個對等節(jié)點,我們需要創(chuàng)建一個新的 WifiP2pConfig 對象,并將要連接的設(shè)備信息從表示我們想要連接設(shè)備的 WifiP2pDevice 拷貝到其中。然后調(diào)用 connect() 方法。
@Override
public void connect() {
// Picking the first device found on the network.
WifiP2pDevice device = peers.get(0);
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
mManager.connect(mChannel, config, new ActionListener() {
@Override
public void onSuccess() {
// WiFiDirectBroadcastReceiver will notify us. Ignore for now.
}
@Override
public void onFailure(int reason) {
Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
Toast.LENGTH_SHORT).show();
}
});
}
在本段代碼中的 WifiP2pManager.ActionListener 實現(xiàn)僅能通知我們初始化的成功或失敗。想要監(jiān)聽連接狀態(tài)的變化,需要實現(xiàn) WifiP2pManager.ConnectionInfoListener 接口。接口中的 onConnectionInfoAvailable() 回調(diào)函數(shù)會在連接狀態(tài)發(fā)生改變時通知應(yīng)用程序。當(dāng)有多個設(shè)備同時試圖連接到一臺設(shè)備時(例如多人游戲或者聊天群),這一臺設(shè)備將被指定為“群主”(group owner)。
@Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
// InetAddress from WifiP2pInfo struct.
InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress());
// After the group negotiation, we can determine the group owner.
if (info.groupFormed && info.isGroupOwner) {
// Do whatever tasks are specific to the group owner.
// One common case is creating a server thread and accepting
// incoming connections.
} else if (info.groupFormed) {
// The other device acts as the client. In this case,
// you'll want to create a client thread that connects to the group
// owner.
}
}
此時,回頭繼續(xù)完善 broadcast receiver 的 onReceive()
方法,并修改對 WIFI_P2P_CONNECTION_CHANGED_ACTION intent 的監(jiān)聽部分的代碼。當(dāng)接收到該 intent 時,調(diào)用 requestConnectionInfo() 方法。此方法為異步,所以結(jié)果將會被我們提供的 WifiP2pManager.ConnectionInfoListener 所獲取。
...
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
if (mManager == null) {
return;
}
NetworkInfo networkInfo = (NetworkInfo) intent
.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
// We are connected with the other device, request connection
// info to find group owner IP
mManager.requestConnectionInfo(mChannel, connectionListener);
}
...
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: