Os recursos do Wi-Fi Aware permitem que dispositivos com Android 8.0 (nível 26 da API) e mais alto para se descobrirem e se conectarem diretamente uns com os outros, sem qualquer outro tipo de conectividade entre eles. O Wi-Fi Aware também é conhecido como Reconhecimento do vizinho Rede (NAN, na sigla em inglês).
A rede Wi-Fi Aware funciona formando clusters com dispositivos vizinhos ou criando um novo cluster se o dispositivo for o primeiro em uma área. Isso O comportamento de clustering se aplica a todo o dispositivo e é gerenciado pelo Wi-Fi Serviço de sistema baseado em reconhecimento os aplicativos não têm controle sobre o comportamento de clustering. Os apps usam as APIs Wi-Fi Aware para se comunicar com o serviço do sistema Wi-Fi Aware, que gerencia o hardware do Wi-Fi Aware no dispositivo.
As APIs do Wi-Fi Aware permitem que os apps realizem as seguintes operações:
Descobrir outros dispositivos: a API tem um mecanismo para encontrar outros dispositivos por perto. O processo começa quando um dispositivo publica outro. ou mais serviços detectáveis. Então, quando um dispositivo assinar um ou mais e entra no alcance do Wi-Fi do editor, o assinante recebe notificação de que um editor correspondente foi descoberto. Após o o assinante descobre um editor, ele pode enviar um Short ou estabelecer uma conexão de rede com o dispositivo descoberto. Os dispositivos podem ser editores e inscritos ao mesmo tempo.
Criar uma conexão de rede:depois que dois dispositivos descobrirem cada um eles podem criar uma conexão de rede Wi-Fi Aware bidirecional sem um ponto de acesso.
As conexões de rede Wi-Fi Aware oferecem suporte a taxas de capacidade de processamento mais altas distâncias do que o Bluetooth conexões de rede. Esses tipos de conexões são úteis para apps que compartilham quantidades de dados entre usuários, como apps de compartilhamento de fotos.
Melhorias no Android 13 (nível 33 da API)
Em dispositivos com o Android 13 (nível 33 da API) e versões mais recentes com suporte a apps instantâneos
modo de comunicação, os apps podem usar o
PublishConfig.Builder.setInstantCommunicationModeEnabled()
e
SubscribeConfig.Builder.setInstantCommunicationModeEnabled()
para
ativar ou desativar o modo de comunicação instantânea para um editor ou assinante
sessão de descoberta. O modo de comunicação instantânea acelera a troca de mensagens,
descoberta de serviços e qualquer caminho de dados configurado como parte de um editor ou assinante
sessão de descoberta. Para determinar se um dispositivo é compatível com comunicação instantânea
use o método isInstantCommunicationModeSupported()
.
Melhorias do Android 12 (nível 31 da API)
O Android 12 (nível 31 da API) adiciona algumas melhorias ao Wi-Fi Aware:
- Em dispositivos com o Android 12 (nível 31 da API) ou versões mais recentes, é possível usar o
onServiceLost()
que seja alertado quando o app perder um serviço descoberto por causa da interrupção ou transferência de um serviço para fora do alcance. - A configuração dos caminhos de dados do Wi-Fi Aware foi simplificada. Versões anteriores usou mensagens L2 para fornecer o endereço MAC do iniciador, que a latência. Em dispositivos com o Android 12 e versões mais recentes, (servidor) pode ser configurado para aceitar qualquer saber o endereço MAC do iniciador antecipadamente. Isso acelera o caminho de dados exibir e ativar diversos links ponto a ponto com apenas uma rede solicitação.
- Apps com o Android 12 ou versões mais recentes podem usar o
WifiAwareManager.getAvailableAwareResources()
para obter o número de caminhos de dados disponíveis, sessões de publicação e sessões de inscrição. Isso pode ajudar o app a determinar se há recursos suficientes disponíveis para executar a funcionalidade desejada.
Configuração inicial
Para configurar seu app para usar a descoberta e redes Wi-Fi Aware, execute o etapas a seguir:
Solicite as seguintes permissões no manifesto do 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" />
Verifique se o dispositivo é compatível com o Wi-Fi Aware com o
PackageManager
API, conforme mostrado abaixo:Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
Verifique se o Wi-Fi Aware está disponível. Talvez o Wi-Fi Aware esteja ativado dispositivo, mas pode não estar disponível no momento porque o usuário desativou Wi-Fi ou Localização. Dependendo dos recursos de hardware e firmware, alguns dispositivos pode não ser compatível com o Wi-Fi Aware se o Wi-Fi Direct, SoftAP ou tethering estiver ativado usar. Para verificar se o Wi-Fi Aware está disponível, ligue
isAvailable()
:A disponibilidade do Wi-Fi Aware pode mudar a qualquer momento. Seu app precisa registre um
BroadcastReceiver
para receberACTION_WIFI_AWARE_STATE_CHANGED
, que é enviado sempre que a disponibilidade muda. Quando o app recebe o transmissão, ele deve descartar todas as sessões existentes (suponha que o serviço Wi-Fi Aware foi interrompido), depois verifique estado atual de disponibilidade e ajustar seu comportamento de acordo. Exemplo: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);
Para mais informações, consulte Visão geral de transmissões.
Conseguir uma sessão
Para começar a usar o Wi-Fi Aware, seu app precisa ter um
WifiAwareSession
ao chamar
attach()
. Esse método
faz o seguinte:
- ativa o hardware do Wi-Fi Aware;
- une ou forma um cluster do Wi-Fi Aware;
- Cria uma sessão do Wi-Fi Aware com um namespace exclusivo que atua como um contêiner para todas as sessões de descoberta criadas nele.
Se o aplicativo for anexado corretamente, o sistema executará a
onAttached()
.
Esse callback fornece um objeto WifiAwareSession
que o app deve usar para todas as outras operações de sessão. Um app pode usar o
para publicar um serviço ou
assinar um serviço.
Seu app deve chamar
attach()
apenas uma vez. Se
seu app chama attach()
várias vezes, o aplicativo recebe uma sessão diferente para cada chamada, cada uma com
um namespace próprio. Isso pode ser útil em cenários complexos,
devem ser evitados.
Publicar um serviço
Para tornar um serviço detectável, chame o método
método publish()
, que
usa os seguintes parâmetros:
PublishConfig
especifica o nome do serviço e outras propriedades de configuração, como filtro de correspondência.DiscoverySessionCallback
especifica ações a serem executadas quando ocorrerem eventos, como quando o assinante recebe uma mensagem.
Veja um exemplo:
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 a publicação for bem-sucedida, o
onPublishStarted()
é chamado.
Após a publicação, quando os dispositivos que executam apps de assinantes correspondentes passarem para o
Alcance do Wi-Fi do dispositivo editor, os assinantes descobrem o serviço. Quando
um assinante descobre um editor, este não recebe uma
notificação Porém, se o assinante enviar
uma mensagem ao editor,
o editor recebe uma notificação. Quando isso acontece,
onMessageReceived()
é chamado. Você pode usar o
argumento PeerHandle
deste método para
envie uma mensagem de volta ao assinante ou
criar uma conexão com ele.
Para interromper a publicação do serviço, chame
DiscoverySession.close()
:
As sessões de descoberta estão associadas ao familiar responsável
WifiAwareSession
: Se a sessão principal for
fechadas, as sessões de descoberta associadas também serão encerradas. Descartado
também são fechados, o sistema não garante que estão fora do escopo
sessões são encerradas, por isso recomendamos que você chame explicitamente o método close()
métodos.
Inscrever-se em um serviço
Para assinar um serviço, chame o método
método subscribe()
,
que usa os seguintes parâmetros:
-
SubscribeConfig
especifica o nome do serviço no qual se inscrever e outras propriedades de configuração, como correspondência filtro. DiscoverySessionCallback
especifica ações a serem executadas quando ocorrerem eventos, como quando um editor é descoberto.
Veja um exemplo:
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 a operação de assinatura for bem-sucedida, o sistema chamará a
onSubscribeStarted()
no seu app. Como é possível usar
SubscribeDiscoverySession
na
para se comunicar com um editor depois que o app o descobriu,
deve salvar esta referência. Você pode atualizar a sessão de assinatura a qualquer momento
chamar
updateSubscribe()
na sessão de descoberta.
Neste ponto, sua assinatura aguarda a chegada dos editores correspondentes
Alcance do Wi-Fi. Quando isso acontece, o sistema executa
onServiceDiscovered()
método de callback. Você pode usar o PeerHandle
deste retorno de chamada para enviar uma mensagem ou
criar uma conexão com esse editor.
Para cancelar a assinatura de um serviço, chame
DiscoverySession.close()
:
As sessões de descoberta estão associadas ao familiar responsável
WifiAwareSession
: Se a sessão principal for
fechadas, as sessões de descoberta associadas também serão encerradas. Descartado
objetos também são fechados, o sistema não garante quando estão fora do escopo
sessões são encerradas, por isso recomendamos que você chame explicitamente o método close()
métodos.
Enviar uma mensagem
Para enviar uma mensagem para outro dispositivo, você precisa dos seguintes objetos:
DiscoverySession
. Esse objeto permite que você para ligarsendMessage()
: Seu app recebe umaDiscoverySession
ao publicar um serviço ou assinar um serviço.O
PeerHandle
do outro dispositivo, para rotear o mensagem. Seu app recebe o URL de outro dispositivoPeerHandle
de duas maneiras:- Seu app publica um serviço e recebe uma mensagem de um inscrito.
Seu app conquista
PeerHandle
do dispositivoonMessageReceived()
o retorno de chamada. - Seu app é inscrito em um serviço. Então, quando ele descobre
editor, seu app recebe
PeerHandle
doonServiceDiscovered()
o retorno de chamada.
- Seu app publica um serviço e recebe uma mensagem de um inscrito.
Seu app conquista
Para enviar uma mensagem, ligue
sendMessage()
: A
podem ocorrer os seguintes callbacks:
- Quando a mensagem é recebida com êxito pelo ponto, o sistema chama o
onMessageSendSucceeded()
no app de envio. - Quando o dispositivo semelhante recebe uma mensagem, o sistema chama
onMessageReceived()
no app de recebimento.
Embora o PeerHandle
seja necessário para se comunicar com pares, não recomendamos
confiar nele como um identificador permanente de pares. Identificadores de nível superior podem ser
usada pelo aplicativo, incorporada ao serviço de descoberta ou ao
as mensagens seguintes. É possível incorporar um identificador no serviço de descoberta com
as
setMatchFilter()
ou
setServiceSpecificInfo()
método de PublishConfig
ou
SubscribeConfig
A
O método setMatchFilter()
afeta a descoberta, enquanto
O método setServiceSpecificInfo()
não afeta a descoberta.
A incorporação de um identificador em uma mensagem implica a modificação da matriz de bytes da mensagem para inclua um identificador (por exemplo, os primeiros bytes).
Criar uma conexão
O Wi-Fi Aware é compatível com a rede cliente-servidor entre dois dispositivos Wi-Fi Aware.
Para configurar a conexão cliente-servidor:
Use a descoberta do Wi-Fi Aware para publicar um serviço (na servidor) e assinar um serviço (no cliente).
Quando o assinante descobre o editor, enviar uma mensagem do assinante para o editor.
Iniciar um
ServerSocket
no editor e definir ou obter sua porta:Kotlin
val ss = ServerSocket(0) val port = ss.localPort
Java
ServerSocket ss = new ServerSocket(0); int port = ss.getLocalPort();
Use o
ConnectivityManager
para solicitar uma rede Wi-Fi Aware no editor usando umWifiAwareNetworkSpecifier
, especificando a sessão de descobertaPeerHandle
dos inscritos, que você recebeu da mensagem transmitida pelo assinante: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);
Depois que o editor solicita uma rede, ela deve envie uma mensagem ao assinante.
Quando o assinante receber a mensagem do editor, solicite uma conexão Wi-Fi. rede ciente no assinante usando o mesmo método que no editor. O que fazer não especificar uma porta ao criar
NetworkSpecifier
A métodos de callback apropriados são chamados quando a conexão de rede é disponíveis, alterados ou perdidos.Depois que o método
onAvailable()
é chamado no assinante, umaNetwork
está disponível com e você pode abrir umSocket
para se comunicar com oServerSocket
no editor, mas você precisa saber Endereço IPv6 e porta deServerSocket
. Você as encontra no ObjetoNetworkCapabilities
fornecidos no 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);
Quando você terminar com a conexão de rede, chame
unregisterNetworkCallback()
Definir o alcance de dispositivos semelhantes e da descoberta com reconhecimento de local
Um dispositivo com localização por Wi-Fi RTT podem medir a distância diretamente para outros pares e usar essa informação para restringem a descoberta de serviços do Wi-Fi Aware.
A API Wi-Fi RTT permite alcance direto até um ponto Wi-Fi Aware usando Endereço MAC ou o PeerHandle.
A descoberta do Wi-Fi Aware pode ser restringida a descobrir apenas serviços em uma
uma fronteira geográfica virtual específica. Por exemplo, configure uma fronteira geográfica virtual para
de um dispositivo que publica um serviço "Aware_File_Share_Service_Name"
que não está
mais próximo de 3 metros (especificados como 3.000 mm) e não mais do que 10 metros
(especificado como 10.000 mm).
Para ativar a fronteira geográfica virtual, algumas ações são necessárias, tanto por parte do editor como do inscrito:
O editor precisa ativar a definição de alcance no serviço publicado usando setRangingEnabled(true).
Se o editor não ativar o alcance, as restrições da fronteira geográfica virtual especificados pelo assinante são ignorados e uma descoberta normal é executada, ignorando a distância.
O assinante deve especificar uma fronteira geográfica virtual usando alguma combinação de setMinDistanceMm (link em inglês) e setMaxDistanceMm.
Para qualquer um dos valores, uma distância não especificada implica ausência de limite. Especificar apenas a distância máxima implica uma distância mínima de 0. Especificar somente o distância mínima não implica em um máximo.
Quando um serviço de peering é descoberto dentro de uma fronteira geográfica virtual, o onServiceDiscoveredWithinRange (link em inglês) é acionado, o que informa a distância medida ao outro ponto. A A API Wi-Fi RTT direta pode ser chamada conforme necessário para medir a distância mais tarde.