La découverte du service P2P Wifi ne se comporte pas comme prévu. Je vois des problèmes intermittents dans lesquels les auditeurs de DNSSD ne sont pas toujours appelés et par conséquent, je n'ai aucune idée des appareils à proximité exécutant la même application. J'utilise les deux API suivantes: une pour enregistrer un service devant être découvert par d'autres périphériques et l'autre pour découvrir les services à proximité s'exécutant sur d'autres périphériques. Toute idée si je fais quelque chose de mal ici ou existe-t-il une séquence spécifique d'autres appels d'API Android à effectuer avant d'appeler ces API afin de m'assurer que les écouteurs sont toujours appelés chaque fois qu'un nouveau service est enregistré ou même s'il s'agit d'un service est enregistré avant d'appeler l'API pour découvrir les services locaux.
API pour enregistrer un service 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 pour découvrir les services locaux:
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");
}
}
});
}
Remarque: le gestionnaire et le canal sont initialisés en tant que
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
WifiP2p
(en général): Il y a quelque temps, je développais une application avec un système de connectivité réseau assez complexe basé sur WifiP2p
avec Service Broadcasting/Discovery
. Et sur la base de cette expérience, j’ai déjà écrit quelques articles ici sur SO sur la difficulté, l’usure et la problématique. En voici deux (ils regorgent des connaissances que j'ai acquises à propos de WifiP2p
avec Service Discovery
et WifiP2p
lui-même):
Pourquoi la découverte de pairs pour Android WifiDirect est-elle si peu fiable
P2P Wi-Fi. Informer tous les pairs disponibles d'un événement
Je vous conseillerais de lire mes deux réponses (même si elles sont un peu plus centrées sur le WifiP2p
lui-même). Ils devraient vous donner une idée des choses que vous devriez rechercher lorsque vous travaillez avec WifiP2p Service Discovery
. Je peux facilement dire que si vous voulez construire un système de connexion WifiP2p
efficace, relativement fiable et robuste (en particulier avec Service Discovery
), vous devrez vous débrouiller.
WifiP2p Service Discovery
: Pour mieux répondre à votre question exacte, je vous dirai ce que j’ai fait (différent de vous) pour que mon Service Discovery
fonctionne de manière assez fiable.
1. Broadcasting Service
:
Tout d'abord: avant d'enregistrer votre Service
(avec la méthode addLocalService
), vous devez utiliser la méthode WifiP2pManager
's clearLocalServices
. Et il est important que vous n'ayez seulement appelez addLocalService
si le programme d'écoute a été transmis dans la clearLocalServices
renvoyé avec le rappel onSuccess
.
Bien que cela règle assez bien la diffusion, j’ai constaté que les autres noeuds n’étaient pas toujours en mesure de détecter la variable service
diffusée (en particulier lorsque ces noeuds ne détectaient pas déjà activement les services au moment de l’enregistrement de votre Service
locale, mais ils ont "rejoint" plus tard ). Je ne pouvais pas trouver un moyen de résoudre ce problème à 100% de manière fiable. Et croyez-moi, j'essayais probablement tout ce qui était lié au WifiP2p
-. Et non, la séquence clearLocalServices
-addLocalService
ne donnait pas vraiment de résultats satisfaisants. Ou plus encore: faire quelque chose de différent fonctionnait beaucoup mieux. Ce que j’ai décidé de faire, c’est après que j’ai avec succès ajouté le service local (rappel onSuccess
de addLocalService
), j’ai lancé une Thread
qui appellerait périodiquement la méthode WifiP2pManager
discoverPeers
. Cela semblait obliger à retransmettre toutes les informations service
.
Donc ... en gros, la base de votre code de diffusion devrait ressembler moins à ceci (gardez à l'esprit que chaque morceau de code que je vais poster ici est dépouillé de tous les "contrôles" si le système de connectivité réseau est à droite vous devez les concevoir vous-même pour adapter au mieux votre solution):
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
}
});
}
où la mServiceBroadcastingRunnable
devrait être:
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. Découverte de Service
:
Pour la découverte de votre service
j'ai utilisé une approche similaire. À la fois avec la mise en place de la découverte, et en essayant de forcer la "redécouverte" de services
.
La configuration a été effectuée avec la séquence des trois méthodes WifiP2pManager
suivantes:
removeServiceRequest
, addServiceRequest
, discoverServices
Ils ont été appelés dans cet ordre exact et une méthode particulière (la deuxième ou la troisième pour être exacte) a été appelée uniquement après que la précédente a été "renvoyée" avec le rappel onSuccess
.
La redécouverte de services
a été effectuée avec la méthode intuitive (il suffit de répéter la séquence mentionnée suivante: removeServiceRequest
-> addServiceRequest
-> discoverServices
).
La base de mon code ressemblait de moins en moins à ceci (pour commencer Service Discovery
, je commencerais par appeler prepareServiceDiscovery()
, puis 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
}
});
}
la mServiceDiscoveringRunnable
était simplement:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
@Override
public void run() {
startServiceDiscovery();
}
};
Tout cela a fait fonctionner mon système assez bien. Ce n'était pas encore parfait, mais avec le manque de documentation sur ce sujet, je pense que je ne pourrais rien faire de plus pour l'améliorer.
Si vous testez cette approche, assurez-vous de me dire comment cela fonctionne pour vous (ou si cela fonctionne pour vous;)).
si le problème est la détection du service, j’estime que le groupe créatif est le meilleur moyen de rendre l’appareil et le service détectables, mais le groupe s’il est créé dans tous les appareils, vous ne pouvez pas vous connecter en direct. mais en tant que réseau wifi . Je le fais tous les jours et ça marche.