注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術(shù)一般,由于喜愛安卓而產(chǎn)生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html
在這系列課程的第一節(jié)課中(博客鏈接:
http://www.cnblogs.com/jdneo/p/3579936.html
),向你展示了如何發(fā)現(xiàn)連接到本地網(wǎng)絡(luò)上的服務(wù)。然而,使用Wi-Fi Peer-to-Peer(P2P)服務(wù)搜索會允許你直接發(fā)現(xiàn)附近設(shè)備的服務(wù),而不需要連接到網(wǎng)絡(luò)中。你也可以對外廣播目前正在你的設(shè)備上運行的服務(wù)。這些功能幫助你和其它應(yīng)用進行通信,甚至是當(dāng)無法獲取本地網(wǎng)絡(luò)或者熱點的情況下。
雖然此API所要達到的目的,和之前課程中所說的NSD API非常類似,但是實現(xiàn)它們的代碼卻是不同的。這節(jié)課將向你展示如何使用Wi-Fi P2P從其他設(shè)備發(fā)現(xiàn)可獲得的服務(wù)。這節(jié)課假設(shè)你已經(jīng)對 Wi-Fi P2P 的API有了一定的了解。
一). 配置清單文件
為了使用Wi-Fi P2P,需要在你的清單文件中添加 CHANGE_WIFI_STATE , ACCESS_WIFI_STATE 和 INTERNET 權(quán)限。雖然Wi-Fi P2P不需要網(wǎng)絡(luò)連接,但是它使用的是標準的Java套接字,而在Android中使用它們則需要聲明對應(yīng)的權(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" /> ...
二). 添加一個本地服務(wù)
如果你正在提供一個本地服務(wù),你需要為服務(wù)搜索注冊它。一旦你的本地服務(wù)注冊了,框架將會自動響應(yīng)Peer所發(fā)起的服務(wù)搜索請求。
要創(chuàng)建一個本地服務(wù):
- 創(chuàng)建一個 WifiP2pServiceInfo 對象;
- 用你的服務(wù)的信息來填充它;
- 調(diào)用 addLocalService() 來為服務(wù)搜索注冊本地服務(wù)
private void startRegistration() { // Create a string map containing information about your service. Map record = new HashMap(); record.put( "listenport" , String.valueOf(SERVER_PORT)); record.put( "buddyname", "John Doe" + ( int ) (Math.random() * 1000 )); record.put( "available", "visible" ); // Service information. Pass it an instance name, service type // _protocol._transportlayer , and the map containing // information other devices will want once they connect to this one. WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance( "_test", "_presence._tcp" , record); // Add the local service, sending the service info, network channel, // and listener that will be used to indicate success or failure of // the request. mManager.addLocalService(channel, serviceInfo, new ActionListener() { @Override public void onSuccess() { // Command successful! Code isn't necessarily needed here, // Unless you want to update the UI or add logging statements. } @Override public void onFailure( int arg0) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } }); }
二). 發(fā)現(xiàn)附近的服務(wù)
Android會使用回調(diào)函數(shù)來通知你的應(yīng)用可以獲取的服務(wù),所以要做的第一件事情就是配置它們。創(chuàng)建一個 WifiP2pManager.DnsSdTxtRecordListener 來監(jiān)聽進入的記錄。這個記錄作為一個可選項被廣播至其它設(shè)備。當(dāng)有一個記錄進來了,可以將設(shè)備地址以及其它 你想要的其它信息拷貝到一個當(dāng)前方法之外的一個數(shù)據(jù)結(jié)構(gòu)中,這樣你可以在之后的某一個階段去訪問它。下面的例子假設(shè)收到的記錄包含有一個“ buddyname ”字段,用以用戶身份識別。
final HashMap<String, String> buddies = new HashMap<String, String> (); ... private void discoverService() { DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() { @Override /* Callback includes: * fullDomain: full domain name: e.g "printer._ipp._tcp.local." * record: TXT record dta as a map of key/value pairs. * device: The device running the advertised service. */ public void onDnsSdTxtRecordAvailable( String fullDomain, Map record, WifiP2pDevice device) { Log.d(TAG, "DnsSdTxtRecord available -" + record.toString()); buddies.put(device.deviceAddress, record.get( "buddyname" )); } }; ... }
要獲取服務(wù)信息,創(chuàng)建一個 WifiP2pManager.DnsSdServiceResponseListener 。它接收了實際的描述信息和連接信息。上述代碼實現(xiàn)了一個 Map 對象來將“buddy name”和設(shè)備地址配對在一起。服務(wù)響應(yīng)監(jiān)聽器會使用它將DNS記錄和對應(yīng)的服務(wù)信息連接到一起。一旦這兩個監(jiān)聽器都實現(xiàn)了,使用 setDnsSdResponseListeners() 方法將它們添加到 WifiP2pManager 中。
private void discoverService() { ... DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() { @Override public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) { // Update the device name with the human-friendly version from // the DnsTxtRecord, assuming one arrived. resourceType.deviceName = buddies .containsKey(resourceType.deviceAddress) ? buddies .get(resourceType.deviceAddress) : resourceType.deviceName; // Add to the custom adapter defined specifically for showing // wifi devices. WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager() .findFragmentById(R.id.frag_peerlist); WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment .getListAdapter()); adapter.add(resourceType); adapter.notifyDataSetChanged(); Log.d(TAG, "onBonjourServiceAvailable " + instanceName); } }; mManager.setDnsSdResponseListeners(channel, servListener, txtListener); ... }
現(xiàn)在創(chuàng)建一個服務(wù)請求并且調(diào)用 addServiceRequest() 。該方法必須接受一個監(jiān)聽器參數(shù)來報告結(jié)果是成功的還是失敗的。
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance(); mManager.addServiceRequest(channel, serviceRequest, new ActionListener() { @Override public void onSuccess() { // Success! } @Override public void onFailure( int code) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY } });
最后,調(diào)用 discoverServices()
mManager.discoverServices(channel, new ActionListener() { @Override public void onSuccess() { // Success! } @Override public void onFailure( int code) { // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY if (code == WifiP2pManager.P2P_UNSUPPORTED) { Log.d(TAG, "P2P isn't supported on this device." ); else if (...) ... } });
如果所有代碼都運行正常,太好了,你已經(jīng)做到了!如果你遇到了問題,記住你執(zhí)行的異步調(diào)用會接受一個 WifiP2pManager.ActionListener 作為參數(shù),然后它會提供給你回調(diào)函數(shù)來指明成果或失敗。若要診斷問題所在,在 onFailure() 中添加調(diào)試代碼。該方法提供的錯誤代碼會提示問題產(chǎn)生的原因。下面是一些可能的錯誤值及它們的含義:
在運行程序的設(shè)備上不支持Wi-Fi P2P。
系統(tǒng)太忙以致無法處理請求。
由于一個內(nèi)部錯誤導(dǎo)致操作失敗。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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