android - studio - El descubrimiento del servicio Wifi P2P funciona intermitentemente
wifi direct para pc (2)
WifiP2p
(en general):
Hace algún tiempo estaba desarrollando una aplicación con un sistema de conectividad de red bastante complejo basado en WifiP2p
con Service Broadcasting/Discovery
. Y en base a esa experiencia, ya escribí algunas publicaciones aquí sobre SO sobre cuán difícil, desgastado y problemático es. Aquí hay dos de ellos (están bastante llenos del conocimiento interno que adquirí sobre WifiP2p
con Service Discovery
, y el mismo WifiP2p
):
¿Por qué es tan poco fiable descubrir compañeros para Android WifiDirect?
Wi-fi P2P. Informar a todos los compañeros disponibles de algún evento.
Le aconsejaría que leyera mis dos respuestas (aunque están un poco más centradas en el WifiP2p
). Deben darle una perspectiva sobre las cosas que debe buscar cuando trabaje con el WifiP2p Service Discovery
. Puedo decir fácilmente que si desea construir un sistema de conexión WifiP2p
eficiente, relativamente confiable y robusto (especialmente con Service Discovery
), tendrá que trabajar duro.
WifiP2p Service Discovery
:
Para responder mejor a su pregunta exacta, le diré lo que hice (diferente a usted) para que mi Service Discovery
funcione de manera bastante confiable.
1. Service
radiodifusión:
En primer lugar: antes de registrar su Service
(con el método addLocalService
), debe usar el método clearLocalServices
del clearLocalServices
. Y es importante, que solo debe llamar a addLocalService
si el escucha pasó en los clearLocalServices
devueltos con la onSuccess
llamada onSuccess
.
Aunque esto configura la transmisión bastante bien, descubrí que otros nodos no siempre podían detectar el service
transmitido (especialmente cuando esos nodos no detectaban activamente los servicios en el momento de registrar su Service
local, pero se "unieron" más tarde ). No pude encontrar una manera de solucionar este problema de forma 100% confiable. Y créeme, estaba intentando probablemente todo WifiP2p
relacionado con WifiP2p
. Y no, la secuencia clearLocalServices
- addLocalService
no estaba dando resultados satisfactorios. O más aún: hacer algo diferente funcionaba mucho mejor. Lo que decidí hacer fue después de haber agregado exitosamente el servicio local (devolución de llamada addLocalService
de addLocalService
), comencé un Thread
que periódicamente llamaba WifiP2pManager
método WifiP2pManager
de WifiP2pManager
. Eso parecía estar obligando a retransmitir toda la información del service
.
Entonces ... básicamente, la base de su código de transmisión debería tener un aspecto más o menos así (tenga en cuenta que cada pieza de código que publicaré aquí se eliminará de todas las "comprobaciones" si el sistema de conectividad de la red es correcto Estado, debe diseñarlas usted mismo para que se adapte mejor a su solución):
public void startBroadcastingService(){
mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// service broadcasting started
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable,
SERVICE_BROADCASTING_INTERVAL);
}
@Override
public void onFailure(int error) {
// react to failure of adding the local service
}
});
}
@Override
public void onFailure(int error) {
// react to failure of clearing the local services
}
});
}
donde mServiceBroadcastingRunnable
debe ser:
private Runnable mServiceBroadcastingRunnable = new Runnable() {
@Override
public void run() {
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int error) {
}
});
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
}
};
2. Descubriendo Service
:
Para el descubrimiento de su service
he utilizado un enfoque similar. Tanto con la configuración del descubrimiento como con el intento de forzar el "redescubrimiento" de los services
.
La configuración se realizó con la secuencia de los siguientes tres métodos de WifiP2pManager
:
addServiceRequest
, addServiceRequest
, discoverServices
Se llamaron en este orden exacto y se ha llamado a un método particular (el segundo o el tercero para ser exactos) solo después de que el anterior hubiera "regresado" con la onSuccess
llamada onSuccess
.
El redescubrimiento de services
se estaba realizando con el método intuitivo (solo repitiendo la secuencia mencionada: removeServiceRequest
-> addServiceRequest
-> discoverServices
).
La base de mi código se veía más o menos así (para iniciar Service Discovery
, primero llamaría a prepareServiceDiscovery()
y luego startServiceDiscovery()
):
public void prepareServiceDiscovery() {
mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// do all the things you need to do with detected service
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
// do all the things you need to do with detailed information about detected service
}
});
mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}
private void startServiceDiscovery() {
mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.discoverServices(mWifiP2pChannel,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
//service discovery started
mServiceDiscoveringHandler.postDelayed(
mServiceDiscoveringRunnable,
SERVICE_DISCOVERING_INTERVAL);
}
@Override
public void onFailure(int error) {
// react to failure of starting service discovery
}
});
}
@Override
public void onFailure(int error) {
// react to failure of adding service request
}
});
}
@Override
public void onFailure(int reason) {
// react to failure of removing service request
}
});
}
El mServiceDiscoveringRunnable
era justo:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
@Override
public void run() {
startServiceDiscovery();
}
};
Todo esto hizo que mi sistema funcionara bastante bien. Todavía no era perfecto, pero con la falta de documentación sobre este tema, creo que no podría hacer mucho más para mejorarlo.
Si prueba este enfoque, asegúrese de decirme cómo funciona para usted (o si funciona para usted;)).
El descubrimiento del servicio Wifi P2P no se está comportando como se esperaba. Estoy viendo problemas intermitentes en los que no siempre se llama a los oyentes de DNSSD y, por lo tanto, no tengo ni idea de los dispositivos cercanos que ejecutan la misma aplicación. Estoy usando las siguientes dos API: una para registrar un servicio que descubrirán otros dispositivos y la otra para descubrir los servicios cercanos que se ejecutan en otros dispositivos. Cualquier idea de si estoy haciendo algo incorrecto aquí o si hay alguna secuencia específica de otras llamadas a la API de Android que se debe hacer antes de llamar a estas API para asegurar que siempre se llame a los oyentes siempre que haya un nuevo servicio registrado o incluso si un servicio Se registra antes de que llamemos a la API para descubrir los servicios locales.
API para registrar un servicio local:
private void registerService() {
Map<String, String> values = new HashMap<String, String>();
values.put("name", "Steve");
values.put("port", "8080");
WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);
manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(WiFiDirectActivity.this, "Local service added successfully",
Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int reasonCode) {
Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
Toast.LENGTH_SHORT).show();
}
});
}
API para descubrir servicios locales:
public void discoverService() {
manager.clearServiceRequests(channel, null);
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
@Override
/* Callback includes:
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
* record: TXT record data 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());
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest, new ActionListener() {
@Override
public void onSuccess() {
// Success!
Log.d(TAG, "addServiceRequest success");
}
@Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.d(TAG, "addServiceRequest failure with code " + code);
}
});
manager.discoverServices(channel, new ActionListener() {
@Override
public void onSuccess() {
// Success!
Log.d(TAG, "discoverServices 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 {
Log.d(TAG, "discoverServices failure");
}
}
});
}
Nota: el administrador y el canal se inicializan como
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
Si el problema es la detección del servicio, creo que crear un grupo es la mejor manera de hacer que el dispositivo y el servicio sean detectables, pero el grupo creado en todos los dispositivos no se puede conectar directamente. Pero como red wifi. Lo hago todos los días y funciona.