Le funzionalità Wi-Fi Aware consentono i dispositivi con Android 8.0 (livello API 26) e per scoprire e connettersi direttamente l'uno all'altro senza alcun altro tipo di e la connettività tra di loro. Il Wi-Fi Aware è anche noto come Nearby Awareness Networking (NAN).
La rete Wi-Fi Aware funziona formando cluster con dispositivi vicini, oppure creando un nuovo cluster se il dispositivo è il primo in un'area. Questo comportamento di clustering si applica all'intero dispositivo ed è gestito dal servizio di sistema Wi-Fi aware. Le app non hanno alcun controllo sul comportamento di clustering. Le app utilizzano le API Wi-Fi Aware per comunicare con il servizio di sistema Wi-Fi Aware, che gestisce l'hardware Wi-Fi Aware sul dispositivo.
Le API Wi-Fi Aware consentono alle app di eseguire le seguenti operazioni:
Rilevamento di altri dispositivi: l'API dispone di un meccanismo per trovare altri dispositivi dispositivi nelle vicinanze. Il processo inizia quando un dispositivo pubblica uno o più servizi rilevabili. Quando un dispositivo si abbona a uno o più servizi e entra nel raggio d'azione del Wi-Fi del publisher, l'abbonato riceve una notifica che lo informa che è stato rilevato un publisher corrispondente. Dopo aver rilevato un publisher, l'abbonato può inviare un breve messaggio o stabilire una connessione di rete con il dispositivo rilevato. I dispositivi possono essere contemporaneamente publisher e iscritti.
Creare una connessione di rete: dopo che due dispositivi si sono scoperti tra loro, possono creare una connessione di rete Wi-Fi Aware bidirezionale senza un punto di accesso.
Le connessioni di rete Wi-Fi Aware supportano velocità di velocità effettiva superiori per tempi più lunghi distanze rispetto al Bluetooth e connessioni a Internet. Questi tipi di connessioni sono utili per le app che condividono contenuti quantità di dati tra gli utenti, ad esempio le app di condivisione di foto.
Miglioramenti ad Android 13 (livello API 33)
Sui dispositivi con Android 13 (livello API 33) e versioni successive che supportano la modalità di comunicazione istantanea, le app possono utilizzare i metodi PublishConfig.Builder.setInstantCommunicationModeEnabled()
e SubscribeConfig.Builder.setInstantCommunicationModeEnabled()
per attivare o disattivare la modalità di comunicazione istantanea per una sessione di scoperta di publisher o abbonati. La modalità di comunicazione istantanea velocizza lo scambio di messaggi,
Service Discovery ed eventuali percorsi di dati impostati come parte di un publisher o di un abbonato
durante una sessione di rilevamento. Per determinare se un dispositivo supporta la comunicazione istantanea
utilizza il metodo isInstantCommunicationModeSupported()
.
Miglioramenti ad Android 12 (livello API 31)
Android 12 (livello API 31) aggiunge alcuni miglioramenti a Wi-Fi Aware:
- Sui dispositivi con Android 12 (livello API 31) o versioni successive, puoi utilizzare il callback
onServiceLost()
per ricevere un avviso quando la tua app ha perso un servizio rilevato a causa dell'interruzione o del superamento del raggio d'azione del servizio. - La configurazione dei percorsi dati Wi-Fi Aware è stata semplificata. Versioni precedenti ha utilizzato la messaggistica L2 per fornire l'indirizzo MAC dell'iniziatore, abbiamo introdotto la latenza. Sui dispositivi con Android 12 e versioni successive, l'interlocutore (server) può essere configurato in modo da accettare qualsiasi peer, ovvero non necessita per conoscere in anticipo l'indirizzo MAC dell'iniziatore. Questo accelera il percorso dei dati generare e abilitare più collegamenti point-to-point con una sola rete richiesta.
- Le app in esecuzione su Android 12 o versioni successive possono utilizzare il metodo
WifiAwareManager.getAvailableAwareResources()
per ottenere il numero di percorsi dati attualmente disponibili, pubblicare sessioni e iscriversi alle sessioni. Ciò può aiutare l'app a determinare se sono presenti abbastanza risorse disponibili per eseguire la funzionalità desiderata.
Configurazione iniziale
Per configurare l'app per l'utilizzo del rilevamento e della rete Wi-Fi Aware, esegui la seguenti passaggi:
Richiedi le seguenti autorizzazioni nel file manifest dell'app:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <!-- If your app targets Android 13 (API level 33) or higher, you must declare the NEARBY_WIFI_DEVICES permission. --> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" <!-- If your app derives location information from Wi-Fi APIs, don't include the "usesPermissionFlags" attribute. --> android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" <!-- If any feature in your app relies on precise location information, don't include the "maxSdkVersion" attribute. --> android:maxSdkVersion="32" />
Verifica se il dispositivo supporta Wi-Fi Aware con l'
PackageManager
API, come mostrato di seguito:Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
Controlla se Wi-Fi Aware è attualmente disponibile. La connessione Wi-Fi potrebbe essere attiva su il dispositivo, ma potrebbe non essere attualmente disponibile perché l'utente ha disattivato Wi-Fi o Posizione. A seconda delle funzionalità hardware e firmware, alcuni dispositivi potrebbe non supportare la funzionalità Wi-Fi Aware se è attivo Wi-Fi Direct, SoftAP o tethering per gli utilizzi odierni. Per verificare se Wi-Fi Aware è attualmente disponibile, chiama
isAvailable()
.La disponibilità di Wi-Fi Aware può cambiare in qualsiasi momento. L'app deve registrare un
BroadcastReceiver
per ricevereACTION_WIFI_AWARE_STATE_CHANGED
, che viene inviato ogni volta che la disponibilità cambia. Quando la tua app riceve per intent di trasmissione, dovrebbe ignorare tutte le sessioni esistenti (supponendo che Il servizio Wi-Fi Aware è stato interrotto), quindi controlla la lo stato di disponibilità attuale e regolarne il comportamento di conseguenza. Ad esempio:Kotlin
val wifiAwareManager = context.getSystemService(Context.WIFI_AWARE_SERVICE) as WifiAwareManager? val filter = IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED) val myReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // discard current sessions if (wifiAwareManager?.isAvailable) { ... } else { ... } } } context.registerReceiver(myReceiver, filter)
Java
WifiAwareManager wifiAwareManager = (WifiAwareManager)context.getSystemService(Context.WIFI_AWARE_SERVICE) IntentFilter filter = new IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); BroadcastReceiver myReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // discard current sessions if (wifiAwareManager.isAvailable()) { ... } else { ... } } }; context.registerReceiver(myReceiver, filter);
Per ulteriori informazioni, vedi Trasmissioni.
Ottieni una sessione
Per iniziare a utilizzare Wi-Fi Aware, la tua app deve ottenere un
WifiAwareSession
chiamando
attach()
. Questo metodo
esegue le seguenti operazioni:
- Attiva l'hardware Wi-Fi Aware.
- Si unisce a un cluster Wi-Fi Aware o ne forma uno.
- Crea una sessione Wi-Fi Aware con uno spazio dei nomi univoco che funge da per tutte le sessioni di rilevamento create al suo interno.
Se l'app si collega correttamente, il sistema esegue
Chiamata di onAttached()
.
Questo callback fornisce un oggetto WifiAwareSession
che la tua app deve utilizzare per tutte le ulteriori operazioni della sessione. Un'app può utilizzare
sessione per pubblicare un servizio o
sottoscrivere un abbonamento a un servizio.
L'app deve chiamare
attach()
solo una volta. Se la tua app chiama attach()
più volte, riceve una sessione diversa per ogni chiamata, ciascuna con il proprio spazio dei nomi. Questa opzione potrebbe essere utile in scenari complessi, ma dovrebbe
in genere evitate.
Pubblicare un servizio
Per rendere rilevabile un servizio, chiama il metodo publish()
, che accetta i seguenti parametri:
PublishConfig
specifica il nome del e altre proprietà di configurazione, come il filtro di corrispondenza.DiscoverySessionCallback
specifica le azioni da eseguire quando si verificano eventi, ad esempio quando l'abbonato riceve un messaggio.
Ecco un esempio:
Kotlin
val config: PublishConfig = PublishConfig.Builder() .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME) .build() awareSession.publish(config, object : DiscoverySessionCallback() { override fun onPublishStarted(session: PublishDiscoverySession) { ... } override fun onMessageReceived(peerHandle: PeerHandle, message: ByteArray) { ... } })
Java
PublishConfig config = new PublishConfig.Builder() .setServiceName(“Aware_File_Share_Service_Name”) .build(); awareSession.publish(config, new DiscoverySessionCallback() { @Override public void onPublishStarted(PublishDiscoverySession session) { ... } @Override public void onMessageReceived(PeerHandle peerHandle, byte[] message) { ... } }, null);
Se la pubblicazione va a buon fine,
onPublishStarted()
viene chiamato il metodo di callback.
Dopo la pubblicazione, quando i dispositivi che eseguono app per abbonati corrispondenti passano alla
Raggio d'azione Wi-Fi del dispositivo di pubblicazione, gli abbonati scoprono il servizio. Quando
un abbonato scopre un editore, l'editore non riceve
notifica; se invece il sottoscrittore invia un messaggio all'editore
il publisher riceve una notifica. In questo caso, viene chiamato il metodo callback onMessageReceived()
. Puoi utilizzare l'argomento PeerHandle
di questo metodo per inviare un messaggio all'abbonato o per creare una connessione con lui.
Per interrompere la pubblicazione del servizio, chiama
DiscoverySession.close()
.
Le sessioni di rilevamento sono associate al genitore
WifiAwareSession
. Se la sessione principale viene chiusa, vengono chiuse anche le sessioni di rilevamento associate. Anche se gli oggetti eliminati vengono chiusi, il sistema non garantisce quando vengono chiuse le sessioni fuori ambito, pertanto ti consigliamo di chiamare esplicitamente i metodi close()
.
Abbonarsi a un servizio
Per abbonarti a un servizio, chiama il
subscribe()
metodo,
che accetta i seguenti parametri:
-
SubscribeConfig
specifica il nome del servizio a cui iscriversi e altre proprietà di configurazione, ad esempio il filtro di corrispondenza. DiscoverySessionCallback
specifica le azioni da eseguire quando si verificano eventi, ad esempio quando viene rilevato un publisher.
Ecco un esempio:
Kotlin
val config: SubscribeConfig = SubscribeConfig.Builder() .setServiceName(AWARE_FILE_SHARE_SERVICE_NAME) .build() awareSession.subscribe(config, object : DiscoverySessionCallback() { override fun onSubscribeStarted(session: SubscribeDiscoverySession) { ... } override fun onServiceDiscovered( peerHandle: PeerHandle, serviceSpecificInfo: ByteArray, matchFilter: List<ByteArray> ) { ... } }, null)
Java
SubscribeConfig config = new SubscribeConfig.Builder() .setServiceName("Aware_File_Share_Service_Name") .build(); awareSession.subscribe(config, new DiscoverySessionCallback() { @Override public void onSubscribeStarted(SubscribeDiscoverySession session) { ... } @Override public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, List<byte[]> matchFilter) { ... } }, null);
Se l'operazione di sottoscrizione va a buon fine, il sistema chiama il callback
onSubscribeStarted()
nella tua app. Poiché puoi utilizzare l'argomento
onSubscribeStarted()
nel callback per comunicare con un publisher dopo che la tua app ne ha individuato uno,
dovresti salvare questo riferimento. Puoi aggiornare la sessione di iscrizione in qualsiasi momento:
chiamata
updateSubscribe()
durante la sessione di rilevamento.
A questo punto, il tuo abbonamento attende l'arrivo degli editori corrispondenti
Portata Wi-Fi. In questo caso, il sistema esegue il metodo callback
onServiceDiscovered()
. Puoi utilizzare l'argomento PeerHandle
di questo callback per inviare un messaggio o
creare una connessione con il publisher.
Per annullare l'abbonamento a un servizio, chiama
DiscoverySession.close()
.
Le sessioni di rilevamento sono associate al genitore
WifiAwareSession
. Se la sessione principale è
vengono chiuse anche le relative sessioni di rilevamento. Anche se gli oggetti eliminati vengono chiusi, il sistema non garantisce quando vengono chiuse le sessioni fuori ambito, pertanto ti consigliamo di chiamare esplicitamente i metodi close()
.
Inviare un messaggio
Per inviare un messaggio a un altro dispositivo, sono necessari i seguenti oggetti:
A
DiscoverySession
. Questo oggetto ti consente di chiamaresendMessage()
. La tua app ottiene unDiscoverySession
se pubblica un servizio o si abbona a un servizio.PeerHandle
dell'altro dispositivo per instradare il messaggio. L'app ottiene ilPeerHandle
di un altro dispositivo in due modi:- La tua app pubblica un servizio e riceve un messaggio da un sottoscrittore.
La tua app recupera il valore
PeerHandle
dell'abbonato dal callbackonMessageReceived()
. - La tua app si abbona a un servizio. Quando viene rilevato un editore corrispondente, l'app riceve il valore
PeerHandle
dell'editore dal callbackonServiceDiscovered()
.
- La tua app pubblica un servizio e riceve un messaggio da un sottoscrittore.
La tua app recupera il valore
Per inviare un messaggio, chiama
sendMessage()
. La
potrebbero verificarsi i seguenti callback:
- Quando il messaggio viene ricevuto correttamente dal peer, il sistema chiama la
onMessageSendSucceeded()
callback nell'app invio. - Quando il peer riceve un messaggio, il sistema chiama
onMessageReceived()
nell'app di ricezione.
Sebbene il PeerHandle
sia necessario per comunicare con i compagni, non dovresti
come identificatore permanente dei peer. Gli identificatori di livello superiore possono essere
utilizzate dall'applicazione, incorporate nel servizio di rilevamento stesso o nelle
messaggi successivi. Puoi incorporare un identificatore nel servizio di rilevamento con
il
setMatchFilter()
o
setServiceSpecificInfo()
di PublishConfig
o
SubscribeConfig
. Il metodo setMatchFilter()
influisce sulla scoperta, mentre il metodo setServiceSpecificInfo()
no.
L'inserimento di un identificatore in un messaggio implica la modifica dell'array di byte del messaggio per includere un identificatore (ad esempio, come prima coppia di byte).
Crea una connessione
Wi-Fi Aware supporta la rete client-server tra due dispositivi Wi-Fi Aware.
Per configurare la connessione client-server:
Utilizza il rilevamento Wi-Fi Aware per pubblicare un servizio (sulla server) e sottoscrivere un servizio (sulla cliente).
Una volta che l'abbonato scopre l'editore, Inviare un messaggio dal sottoscrittore all'editore.
Avvia un
ServerSocket
sul dispositivo del publisher e imposta o ottieni la relativa porta:Kotlin
val ss = ServerSocket(0) val port = ss.localPort
Java
ServerSocket ss = new ServerSocket(0); int port = ss.getLocalPort();
Utilizza
ConnectivityManager
per richiedere una rete Wi-Fi Aware sul publisher utilizzando unWifiAwareNetworkSpecifier
, specificando la sessione di rilevamento e ilPeerHandle
dell'abbonato, che hai ottenuto dal messaggio trasmesso dall'abbonato:Kotlin
val networkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle) .setPskPassphrase("somePassword") .setPort(port) .build() val myNetworkRequest = NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE) .setNetworkSpecifier(networkSpecifier) .build() val callback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { ... } override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) { ... } override fun onLost(network: Network) { ... } } connMgr.requestNetwork(myNetworkRequest, callback);
Java
NetworkSpecifier networkSpecifier = new WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle) .setPskPassphrase("somePassword") .setPort(port) .build(); NetworkRequest myNetworkRequest = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE) .setNetworkSpecifier(networkSpecifier) .build(); ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { ... } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { ... } @Override public void onLost(Network network) { ... } }; ConnectivityManager connMgr.requestNetwork(myNetworkRequest, callback);
Una volta che il publisher richiede una rete, deve inviare un messaggio all'abbonato.
Una volta che l'abbonato riceve il messaggio dal publisher, richiedi una rete Wi-Fi consapevole sull'abbonato utilizzando lo stesso metodo utilizzato sul publisher. Non specificare una porta quando crei il
NetworkSpecifier
. La vengono chiamati metodi di callback appropriati quando la connessione di rete disponibile, modificato o smarrito.Una volta che il metodo
onAvailable()
viene chiamato al sottoscrittore, viene L'oggettoNetwork
è disponibile con che puoi aprire in unaSocket
per comunicare con ilServerSocket
del publisher, ma devi conoscere Indirizzo e porta IPv6 diServerSocket
. Puoi recuperarli dall'oggettoNetworkCapabilities
fornito nel callbackonCapabilitiesChanged()
:Kotlin
val peerAwareInfo = networkCapabilities.transportInfo as WifiAwareNetworkInfo val peerIpv6 = peerAwareInfo.peerIpv6Addr val peerPort = peerAwareInfo.port ... val socket = network.getSocketFactory().createSocket(peerIpv6, peerPort)
Java
WifiAwareNetworkInfo peerAwareInfo = (WifiAwareNetworkInfo) networkCapabilities.getTransportInfo(); Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr(); int peerPort = peerAwareInfo.getPort(); ... Socket socket = network.getSocketFactory().createSocket(peerIpv6, peerPort);
Al termine della connessione di rete, chiama
unregisterNetworkCallback()
Ranging peer e rilevamento basato sulla posizione
Un dispositivo dotato della posizione RTT Wi-Fi possono misurare direttamente la distanza rispetto ai colleghi e usare queste informazioni per limitare il rilevamento del servizio Wi-Fi Aware.
L'API Wi-Fi RTT consente il rilevamento diretto di un peer Wi-Fi Aware utilizzando il suo indirizzo MAC o il suo PeerHandle.
La rilevamento Wi-Fi Aware può essere limitata in modo da rilevare solo i servizi all'interno di un determinato recinto virtuale. Ad esempio, puoi configurare un recinto virtuale che permetta il rilevamento
di un dispositivo che pubblica un servizio "Aware_File_Share_Service_Name"
che non è
meno di 3 metri (specificati come 3000 mm) e non più di 10 metri
(specificata come 10.000 mm).
Per attivare il geofencing, sia l'editore sia l'abbonato devono intervenire:
L'editore deve abilitare il raggio d'azione sul servizio pubblicato utilizzando setRangingEnabled(true).
Se il publisher non abilita il raggio d'azione, i vincoli del recinto virtuale specificate dall'abbonato vengono ignorati e viene eseguita la normale scoperta, ignorando la distanza.
L'abbonato deve specificare un recinto virtuale utilizzando una combinazione di setMinDistanceMm e setMaxDistanceMm.
Per entrambi i valori, una distanza non specificata implica che non esiste alcun limite. Specificando solo la distanza massima implica una distanza minima pari a 0. Specificando solo la distanza minima non implica un valore massimo.
Quando un servizio peer viene rilevato all'interno di un recinto virtuale, onServiceDiscoveryed WithinRange viene attivato, che fornisce la distanza misurata dal peer. L'API RTT Wi-Fi diretta può quindi essere chiamata in base alle necessità per misurare la distanza in un secondo momento.