W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
編寫:naizhengtan - 原文:http://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html
在本章第一節(jié)“使用網(wǎng)絡(luò)服務(wù)發(fā)現(xiàn)”中介紹了如何在局域網(wǎng)中發(fā)現(xiàn)已連接到網(wǎng)絡(luò)的服務(wù)。然而,即使在不接入網(wǎng)絡(luò)的情況下,Wi-Fi P2P 服務(wù)發(fā)現(xiàn)也可以使我們的應(yīng)用直接發(fā)現(xiàn)附近的設(shè)備。我們也可以向外公布自己設(shè)備上的服務(wù)。這些能力可以在沒有局域網(wǎng)或者網(wǎng)絡(luò)熱點的情況下,在應(yīng)用間進(jìn)行通信。
雖然本節(jié)所述的 API 與第一節(jié) NSD(Network Service Discovery)的 API 相似,但是具體的實現(xiàn)代碼卻截然不同。本節(jié)將講述如何通 過Wi-Fi P2P 技術(shù)發(fā)現(xiàn)其它設(shè)備中可用的服務(wù)。本節(jié)假設(shè)讀者已經(jīng)對 Wi-Fi P2P 的 API 有一定了解。
使用 Wi-Fi P2P 技術(shù),需要添加 CHANGE_WIFI_STATE、ACCESS_WIFI_STATE 以及 INTERNET 三種權(quán)限到應(yīng)用的 manifest 文件。雖然 Wi-Fi P2P 技術(shù)不需要訪問互聯(lián)網(wǎng),但是它會使用 Java 中的標(biāo)準(zhǔn) socket,而使用 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"/>
...
如果我們想提供一個本地服務(wù),就需要在服務(wù)發(fā)現(xiàn)框架中注冊該服務(wù)。當(dāng)本地服務(wù)被成功注冊,系統(tǒng)將自動回復(fù)所有來自附近的服務(wù)發(fā)現(xiàn)請求。
三步創(chuàng)建本地服務(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
}
});
}
Android 使用回調(diào)函數(shù)通知應(yīng)用程序附近可用的服務(wù),因此首先要做的是設(shè)置這些回調(diào)函數(shù)。新建一個 WifiP2pManager.DnsSdTxtRecordListener 實例監(jiān)聽實時收到的記錄(record)。這些記錄可以是來自其他設(shè)備的廣播。當(dāng)收到記錄時,將其中的設(shè)備地址和其他相關(guān)信息拷貝到當(dāng)前方法之外的外部數(shù)據(jù)結(jié)構(gòu)中,供之后使用。下面的例子假設(shè)這條記錄包含一個帶有用戶身份的“buddyname”域(field)。
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"));
}
};
...
}
接下來創(chuàng)建 WifiP2pManager.DnsSdServiceResponseListener 對象,用以獲取服務(wù)的信息。這個對象將接收服務(wù)的實際描述以及連接信息。上一段代碼構(gòu)建了一個包含設(shè)備地址和“buddyname”鍵值對的 Map 對象。WifiP2pManager.DnsSdServiceResponseListener 對象使用這些配對信息將 DNS 記錄和對應(yīng)的服務(wù)信息對應(yīng)起來。當(dāng)上述兩個 listener 構(gòu)建完成后,調(diào)用 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)在調(diào)用 addServiceRequest() 創(chuàng)建服務(wù)請求。這個方法也需要一個 Listener 報告請求成功與失敗。
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(...)
...
}
});
如果所有部分都配置正確,我們應(yīng)該就能看到正確的結(jié)果了!如果遇到了問題,可以查看 WifiP2pManager.ActionListener 中的回調(diào)函數(shù)。它們能夠指示操作是否成功。我們可以將 debug 的代碼放置在 onFailure() 中來診斷問題。其中的一些錯誤碼(Error Code)也許能為我們帶來不小啟發(fā)。下面是一些常見的錯誤:
當(dāng)前的設(shè)備不支持 Wi-Fi P2P
系統(tǒng)忙,無法處理當(dāng)前請求
內(nèi)部錯誤導(dǎo)致操作失敗
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: