Network Service Discovery (NSD) consente alla tua app di accedere a servizi dai dispositivi connessi a una rete locale. I dispositivi che supportano NSD includono stampanti, webcam, server HTTPS e altri dispositivi mobili.
NSD implementa il meccanismo di Service Discovery (DNS-SD) basato su DNS, che consente alla tua app di richiedere servizi specificando un tipo di servizio e il nome di un'istanza di dispositivo che fornisce il tipo di servizio desiderato. DNS-SD corrente supportata sia su Android che su altre piattaforme mobile.
L'aggiunta di NSD alla tua app consente agli utenti di identificare altri dispositivi sulla che supporti i servizi richiesti dalla tua app. Questo è utile per una varietà di applicazioni peer-to-peer, come la condivisione di file o la modalità multiplayer gaming. Le API NSD di Android semplificano l'impegno richiesto per l'implementazione tali funzionalità.
Questa lezione mostra come creare un'applicazione in grado di trasmettere nome e informazioni di connessione alla rete locale e cercare informazioni da altre applicazioni che fanno lo stesso. Infine, questa lezione mostra di connettersi alla stessa applicazione in esecuzione su un altro dispositivo.
Registrazione del servizio sulla rete
Nota: questo passaggio è facoltativo. Se non ti interessa trasmettere i servizi della tua app sulla rete locale, puoi passare direttamente prossima sezione, Scopri i servizi sulla rete.
Per registrare il tuo servizio sulla rete locale, devi prima creare un oggetto NsdServiceInfo
. Questo oggetto fornisce le informazioni
usati dagli altri dispositivi sulla rete per decidere se connettersi o meno al tuo
completamente gestito di Google Cloud.
Kotlin
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) ... } }
Java
public void registerService(int port) { // Create the NsdServiceInfo object, and populate it. NsdServiceInfo serviceInfo = new NsdServiceInfo(); // The name is subject to change based on conflicts // with other services advertised on the same network. serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_nsdchat._tcp"); serviceInfo.setPort(port); ... }
Questo snippet di codice imposta il nome del servizio su "NsdChat". Il nome del servizio è il nome dell'istanza, ovvero il nome visibile agli altri dispositivi nella rete. Il nome è visibile a qualsiasi dispositivo nella rete che utilizza NSD per cercare servizi locali. Tieni presente che il nome deve essere univoco per qualsiasi servizio della e Android gestisce automaticamente la risoluzione dei conflitti. Se su due dispositivi sulla rete sia installata l'applicazione NsdChat, uno dei cambia automaticamente il nome del servizio in qualcosa come "NsdChat (1)".
Il secondo parametro imposta il tipo di servizio, specifica il protocollo e il trasporto il livello utilizzato dall'applicazione. La sintassi è "_<protocollo>._<transportlayer>". Nella snippet di codice, il servizio utilizza il protocollo HTTP in esecuzione su TCP. Un'applicazione che offre un servizio di stampa (ad esempio, una stampante di rete) imposta in "_ipp._tcp".
Nota: i numeri assegnati internazionali Authority (IANA) gestisce un sistema di gestione elenco autorevoli dei tipi di servizi utilizzati dai protocolli di Service Discovery come NSD e Bonjour. Puoi scaricare l'elenco dal Elenco IANA dei nomi dei servizi e dei numeri di porta Se intendi utilizzare un nuovo tipo di servizio, devi prenotarlo compilando IANA Ports and Service modulo di registrazione.
Quando imposti la porta per il tuo servizio, evita l'hardcoded della porta perché questa sono in conflitto con altre applicazioni. Ad esempio, supponendo l'applicazione usa sempre la porta 1337 e la mette in potenziale conflitto con e le altre applicazioni installate che usano la stessa porta. Utilizza invece il metodo la prossima porta disponibile. Poiché queste informazioni vengono fornite ad altre app da un di servizio, non c'è bisogno della porta utilizzata dall'applicazione noti da altre applicazioni al momento della compilazione. Le applicazioni possono invece queste informazioni provenienti dalla trasmissione del tuo servizio, subito prima di connetterti al tuo completamente gestito di Google Cloud.
Se utilizzi i socket, di seguito puoi scoprire come inizializzare un socket a qualsiasi disponibile solo su 0.
Kotlin
fun initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = ServerSocket(0).also { socket -> // Store the chosen port. mLocalPort = socket.localPort ... } }
Java
public void initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = new ServerSocket(0); // Store the chosen port. localPort = serverSocket.getLocalPort(); ... }
Ora che hai definito l'oggetto NsdServiceInfo
, devi implementare l'interfaccia RegistrationListener
. Questo
contiene i callback utilizzati da Android per avvisare l'applicazione del
esito positivo o negativo della registrazione del servizio e dell'annullamento della registrazione.
Kotlin
private val registrationListener = object : NsdManager.RegistrationListener { override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) { // Save the service name. Android may have changed it in order to // resolve a conflict, so update the name you initially requested // with the name Android actually used. mServiceName = NsdServiceInfo.serviceName } override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Registration failed! Put debugging code here to determine why. } override fun onServiceUnregistered(arg0: NsdServiceInfo) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Unregistration failed. Put debugging code here to determine why. } }
Java
public void initializeRegistrationListener() { registrationListener = new NsdManager.RegistrationListener() { @Override public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { // Save the service name. Android may have changed it in order to // resolve a conflict, so update the name you initially requested // with the name Android actually used. serviceName = NsdServiceInfo.getServiceName(); } @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Registration failed! Put debugging code here to determine why. } @Override public void onServiceUnregistered(NsdServiceInfo arg0) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Unregistration failed. Put debugging code here to determine why. } }; }
Ora hai tutti i componenti per registrare il tuo servizio. Chiama il metodo
registerService()
.
Tieni presente che questo metodo è asincrono, quindi qualsiasi codice da eseguire
Dopo la registrazione del servizio, devi usare il metodo onServiceRegistered()
.
Kotlin
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) } nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager).apply { registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener) } }
Java
public void registerService(int port) { NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_http._tcp."); serviceInfo.setPort(port); nsdManager = Context.getSystemService(Context.NSD_SERVICE); nsdManager.registerService( serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener); }
Scopri i servizi sulla rete
La rete brulica di vita, dalle bestionali stampanti di rete ai di webcam, per le brutali e infuocate battaglie dei tris giocatori. La chiave per far vedere alla tua applicazione questo vivace ecosistema di è Service Discovery. La tua applicazione deve ascoltare il servizio gli annunci in rete per vedere quali servizi sono disponibili e filtrare tutto ciò con cui l'applicazione non può funzionare.
Il rilevamento dei servizi, ad esempio la registrazione, prevede due passaggi:
impostando un listener di rilevamento con i callback pertinenti e creando un singolo
Chiamata API a discoverServices()
.
Innanzitutto, crea un'istanza per un corso anonimo che implementa NsdManager.DiscoveryListener
. Il seguente snippet mostra un
esempio semplice:
Kotlin
// Instantiate a new DiscoveryListener private val discoveryListener = object : NsdManager.DiscoveryListener { // Called as soon as service discovery begins. override fun onDiscoveryStarted(regType: String) { Log.d(TAG, "Service discovery started") } override fun onServiceFound(service: NsdServiceInfo) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success$service") when { service.serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: ${service.serviceType}") service.serviceName == mServiceName -> // The name of the service tells the user what they'd be // connecting to. It could be "Bob's Chat App". Log.d(TAG, "Same machine: $mServiceName") service.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener) } } override fun onServiceLost(service: NsdServiceInfo) { // When the network service is no longer available. // Internal bookkeeping code goes here. Log.e(TAG, "service lost: $service") } override fun onDiscoveryStopped(serviceType: String) { Log.i(TAG, "Discovery stopped: $serviceType") } override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } }
Java
public void initializeDiscoveryListener() { // Instantiate a new DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() { // Called as soon as service discovery begins. @Override public void onDiscoveryStarted(String regType) { Log.d(TAG, "Service discovery started"); } @Override public void onServiceFound(NsdServiceInfo service) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success" + service); if (!service.getServiceType().equals(SERVICE_TYPE)) { // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: " + service.getServiceType()); } else if (service.getServiceName().equals(serviceName)) { // The name of the service tells the user what they'd be // connecting to. It could be "Bob's Chat App". Log.d(TAG, "Same machine: " + serviceName); } else if (service.getServiceName().contains("NsdChat")){ nsdManager.resolveService(service, resolveListener); } } @Override public void onServiceLost(NsdServiceInfo service) { // When the network service is no longer available. // Internal bookkeeping code goes here. Log.e(TAG, "service lost: " + service); } @Override public void onDiscoveryStopped(String serviceType) { Log.i(TAG, "Discovery stopped: " + serviceType); } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } }; }
L'API NSD utilizza i metodi in questa interfaccia per informare l'applicazione durante il rilevamento all'avvio, in caso di errore e quando i servizi vengono trovati e persi (la perdita significa non più disponibile"). Tieni presente che questo snippet esegue diversi controlli quando viene trovato un servizio.
- Il nome del servizio trovato viene confrontato con quello del servizio nome del servizio locale per determinare se il dispositivo ha appena rilevato broadcast (valido).
- Il tipo di servizio è selezionato, per verificare che si tratti di un tipo di servizio a cui può connettersi l'applicazione.
- Il nome del servizio viene controllato per verificare la connessione all'account di servizio corretto un'applicazione.
La verifica del nome del servizio non è sempre necessaria ed è pertinente solo se vuoi connetterti a un'applicazione specifica. Ad esempio, l'applicazione Vogliono connettersi solo a istanze di sé in esecuzione su altri dispositivi. Tuttavia, se connessione a una stampante di rete, è sufficiente vedere che il tipo di servizio è "_ipp._tcp".
Dopo aver configurato il listener, chiama discoverServices()
, passando il tipo di servizio
l'applicazione deve cercare, il protocollo di rilevamento da utilizzare e
che hai appena creato.
Kotlin
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
Java
nsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
Connettiti ai servizi sulla rete
Quando l'applicazione trova sulla rete un servizio a cui connettersi,
deve prima determinare le informazioni di connessione per tale servizio, utilizzando
resolveService()
.
Implementa un NsdManager.ResolveListener
da passare in questo
e usalo per ottenere un NsdServiceInfo
che contiene
le informazioni di connessione.
Kotlin
private val resolveListener = object : NsdManager.ResolveListener { override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed: $errorCode") } override fun onServiceResolved(serviceInfo: NsdServiceInfo) { Log.e(TAG, "Resolve Succeeded. $serviceInfo") if (serviceInfo.serviceName == mServiceName) { Log.d(TAG, "Same IP.") return } mService = serviceInfo val port: Int = serviceInfo.port val host: InetAddress = serviceInfo.host } }
Java
public void initializeResolveListener() { resolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed: " + errorCode); } @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { Log.e(TAG, "Resolve Succeeded. " + serviceInfo); if (serviceInfo.getServiceName().equals(serviceName)) { Log.d(TAG, "Same IP."); return; } mService = serviceInfo; int port = mService.getPort(); InetAddress host = mService.getHost(); } }; }
Una volta risolto il servizio, l'applicazione riceve informazioni dettagliate le informazioni sul servizio, tra cui l'indirizzo IP e il numero di porta. Questo è tutto devi creare la tua connessione di rete al servizio.
Annulla la registrazione del servizio alla chiusura dell'applicazione
È importante abilitare e disabilitare NSD le funzionalità più appropriate durante il deployment durante il ciclo di vita di attività. L'annullamento della registrazione dell'applicazione alla chiusura contribuisce a evitare altre applicazioni pensi che sia ancora attiva e tenta di connettersi li annotino. Inoltre, il Service Discovery è un'operazione costosa e deve essere arrestata quando l'attività principale viene messa in pausa e riattivata quando l'attività viene ripristinato. Esegui l'override dei metodi del ciclo di vita dell'attività principale e inserisci il codice per avviare e interrompere la trasmissione e il rilevamento del servizio in base alle esigenze.
Kotlin
// In your application's Activity override fun onPause() { nsdHelper?.tearDown() super.onPause() } override fun onResume() { super.onResume() nsdHelper?.apply { registerService(connection.localPort) discoverServices() } } override fun onDestroy() { nsdHelper?.tearDown() connection.tearDown() super.onDestroy() } // NsdHelper's tearDown method fun tearDown() { nsdManager.apply { unregisterService(registrationListener) stopServiceDiscovery(discoveryListener) } }
Java
// In your application's Activity @Override protected void onPause() { if (nsdHelper != null) { nsdHelper.tearDown(); } super.onPause(); } @Override protected void onResume() { super.onResume(); if (nsdHelper != null) { nsdHelper.registerService(connection.getLocalPort()); nsdHelper.discoverServices(); } } @Override protected void onDestroy() { nsdHelper.tearDown(); connection.tearDown(); super.onDestroy(); } // NsdHelper's tearDown method public void tearDown() { nsdManager.unregisterService(registrationListener); nsdManager.stopServiceDiscovery(discoveryListener); }