注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html
Wi-Fi的P2P API允許設備連接到附近的設備,而不需要連接到網絡或熱點(Android的Wi-Fi P2P框架使用 Wi-Fi Direct? 認證程序來編譯)Wi-Fi P2P允許你的應用快速發現并連接到附近的設備,這一功能比起藍牙來說更加強大。
這節課將向你展示如何使用Wi-Fi P2P來發現并連接附近的設備。
一). 設置應用權限聲明
為了使用Wi-Fi P2P,需要添加 CHANGE_WIFI_STATE , ACCESS_WIFI_STATE 和 INTERNET 權限聲明到你的清單文件中。Wi-Fi P2P不需要一個網絡連接,但它使用了標準的Java套接字,而這需要 INTERNET 權限。所以你需要下列權限來使用Wi-Fi P2P。
< 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" /> ...
二). 配置一個廣播接收器和一個P2P管理器
要使用Wi-Fi P2P,你需要監聽在某一事件發生時,用來告知你的應用的廣播Intents。在你的應用中,實例化一個 IntentFilter 并設置它為監聽下列事件:
指出Wi-Fi P2P已經啟用
指出可以獲得的peer列表發生了變化
WIFI_P2P_CONNECTION_CHANGED_ACTION
指出Wi-Fi P2P連接的狀態發生了變化
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
指出設備的配置細節發生了改變
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() 方法的最后,獲取一個 WifiP2pManager 的實例,然后調用其 initialize() 方法。這一方法返回一個 WifiP2pManager.Channel 對象,在之后你將會用到它將你的應用連接到Wi-Fi P2P框架。
@Override Channel mChannel; public void onCreate(Bundle savedInstanceState) { .... mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); mChannel = mManager.initialize( this , getMainLooper(), null ); }
現在創建一個新的 BroadcastReceiver 類,來監聽系統的Wi-Fi P2P狀態的改變。在 onReceive() 方法中,添加一個條件分支來處理每一個之前列舉出來的P2P狀態變化。
@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過濾器和廣播接收器,并在activity被暫停時注銷它們。做這兩件事情最好的位置是在 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); } ?
三). 初始化Peer搜索
要使用Wi-Fi P2P來搜索附近的設備,調用 discoverPeers() 方法。這一方法接收如下參數:
- 當你初始化P2P管理器時你所收回的 WifiP2pManager.Channel ;
- 一個 WifiP2pManager.ActionListener 的實現,具有一些在搜索成功或失敗時系統所要調用的方法。
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搜索。 discoverPeers() 方法啟動搜索進程,然后迅速返回。系統會通知你搜索進程是否被監聽器初始化成功。同時搜索會保持激活狀態知道一個連接被初始化或者一個P2P組被構建完成。
四). 獲取Peers列表
現在寫下獲取和處理Peers列表的代碼。首先實現 WifiP2pManager.PeerListListener 接口,它提供了檢測到的Wi-Fi P2P的peer信息。請看下面的代碼:
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 ; } } }
現在修改你的廣播接收器的 onReceive() 方法,當一個具有 WIFI_P2P_PEERS_CHANGED_ACTION 的intent被接收時,來調用 requestPeers() 方法。你需要通過某種方法將監聽器傳遞給廣播接收器。一種方法是將它作為一個參數傳遞給廣播接收器的構造函數:
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" ); }... }
現在,一個具有 WIFI_P2P_PEERS_CHANGED_ACTION 的intent將會激活一個更新Peer列表的請求。
五). 與一個Peer發起連接
為了和一個Peer發起連接,創建一個新的 WifiP2pConfig 對象,然后從代表你想要連接的設備的 WifiP2pDevice 中把數據拷貝到這個對象里面。然后調用 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 僅在當初始化成功或失敗時向你發起通知。要監聽連接狀態的變化,需要實現 WifiP2pManager.ConnectionInfoListener 接口。它的 onConnectionInfoAvailable() 回調函數將會在連接狀態變化后向你發出通知。在一些情況下,許多設備會向一個設備發起連接(比如一個多人連接的游戲,或者一個聊天的應用),其中一個設備會被任命為一個“組所有者(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. } }
現在回到廣播接收器的 onReceive() 方法中,修改監聽 WIFI_P2P_CONNECTION_CHANGED_ACTION 的intent的部分。當這個intent接收到了以后,調用 requestConnectionInfo() 。這是一個異步的調用,所以結果會被之前你所提供的作為參數的連接信息監聽器接收:
... } 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); } ...
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
