Las capacidades de reconocimiento de Wi-Fi habilitan dispositivos con Android 8.0 (nivel de API 26) y más arriba para descubrirse y conectarse directamente entre sí sin ningún otro tipo de conectividad entre ellas. El reconocimiento de Wi-Fi también se conoce como conocimiento de vecinos. Herramientas de redes (NAN).
Las redes de reconocimiento de Wi-Fi funcionan mediante la formación de clústeres con dispositivos cercanos. mediante la creación de un clúster nuevo si el dispositivo es el primero en un área. Esta el comportamiento del agrupamiento en clústeres se aplica a todo el dispositivo y es administrado por la red Wi-Fi Servicio de sistema Aware apps no tienen control sobre el comportamiento de agrupamiento en clústeres. Uso de las apps que las API de reconocimiento de Wi-Fi se comuniquen con el servicio del sistema de reconocimiento de Wi-Fi, que administra el hardware de reconocimiento de Wi-Fi del dispositivo.
Las API de reconocimiento de Wi-Fi permiten que las apps realicen las siguientes operaciones:
Descubrir otros dispositivos: La API tiene un mecanismo para encontrar otros dispositivos. dispositivos cercanos. El proceso comienza cuando un dispositivo publica uno. o servicios más detectables. Luego, cuando un dispositivo se suscriba a uno o más servicios e ingresa al rango de Wi-Fi del editor, el suscriptor recibe un notificación de que se descubrió un editor coincidente. Después del un suscriptor descubre un publicador, puede enviar o establecer una conexión de red con el dispositivo detectado. Los dispositivos pueden ser simultáneamente publicadores y suscriptores.
Crear una conexión de red: después de que dos dispositivos han detectado cada uno pueden crear un una conexión de red bidireccional de Wi-Fi Aware sin un punto de acceso.
Las conexiones de red de reconocimiento de Wi-Fi admiten tasas de capacidad de procesamiento más altas por más tiempo distancias que con Bluetooth conexiones de red. Estos tipos de conexiones son útiles para apps que comparten cantidades de datos entre usuarios, como las apps para compartir fotos.
Mejoras de Android 13 (nivel de API 33)
En dispositivos con Android 13 (nivel de API 33) y versiones posteriores que admiten apps instantáneas
modo de comunicación, las aplicaciones pueden usar el
PublishConfig.Builder.setInstantCommunicationModeEnabled()
y
SubscribeConfig.Builder.setInstantCommunicationModeEnabled()
métodos para
habilitar o inhabilitar el modo de comunicación instantánea para un editor o suscriptor,
de descubrimiento. El modo de comunicación instantánea acelera el intercambio de mensajes
descubrimiento de servicios y cualquier ruta de datos configurada como parte de un publicador o suscriptor
de descubrimiento. Cómo determinar si un dispositivo admite comunicación instantánea
usa el método isInstantCommunicationModeSupported()
.
Mejoras en Android 12 (nivel de API 31)
Android 12 (nivel de API 31) agrega algunas mejoras a Reconocimiento de Wi-Fi:
- En dispositivos con Android 12 (nivel de API 31) o versiones posteriores, puedes usar la
onServiceLost()
para recibir alertas cuando tu app pierda un servicio detectado debido al el servicio se detiene o se sale de alcance. - Se simplificó la configuración de las rutas de datos de reconocimiento de Wi-Fi. Versiones anteriores usó el mensaje L2 para proporcionar la dirección MAC del iniciador, que introdujo la latencia. En dispositivos con Android 12 y versiones posteriores, la persona que responde (server) se puede configurar para aceptar cualquier intercambio de tráfico; es decir, no necesita sepa la dirección MAC del iniciador por adelantado. Esto acelera la ruta de datos y habilita múltiples enlaces punto a punto con una sola red para cada solicitud.
- Las apps que se ejecutan en Android 12 o versiones posteriores pueden usar la
WifiAwareManager.getAvailableAwareResources()
para obtener la cantidad de rutas de datos, sesiones de publicación, y suscribir sesiones. Esto puede ayudar a la app a determinar tener los recursos disponibles para ejecutar la funcionalidad deseada.
Configuración inicial
Si quieres configurar tu app para usar el descubrimiento y la red de reconocimiento de Wi-Fi, realiza lo siguiente: los siguientes pasos:
Solicita los siguientes permisos en el manifiesto de tu 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" />
Comprueba si el dispositivo admite el reconocimiento de Wi-Fi con el
PackageManager
API, como se muestra a continuación:Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
Comprueba si el reconocimiento de Wi-Fi está disponible actualmente. Es posible que el reconocimiento de Wi-Fi exista en el dispositivo, pero es posible que no esté disponible actualmente porque el usuario inhabilitó Wi-Fi o ubicación. Según las capacidades de hardware y firmware, algunos dispositivos Es posible que el reconocimiento de Wi-Fi no admita Wi-Fi si se activó Wi-Fi directo, SoftAP o la conexión mediante dispositivo móvil usar. Para comprobar si el reconocimiento de Wi-Fi está disponible, llama
isAvailable()
La disponibilidad del reconocimiento de Wi-Fi puede cambiar en cualquier momento. Tu app debe registra un
BroadcastReceiver
para recibirACTION_WIFI_AWARE_STATE_CHANGED
, que se envía cuando cambia la disponibilidad. Cuando tu app recibe el de transmisión, debería descartar todas las sesiones existentes (supón que se interrumpió el reconocimiento de Wi-Fi), luego revisa el el estado actual de disponibilidad y ajustar su comportamiento en consecuencia. Por ejemplo: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 obtener más información, consulta Transmisiones.
Obtén una sesión
Para comenzar a usar el reconocimiento de Wi-Fi, tu app debe obtener un
WifiAwareSession
llamando
attach()
Este método
hace lo siguiente:
- Activa el hardware de reconocimiento de Wi-Fi.
- Se une a un clúster de reconocimiento de Wi-Fi o forma uno.
- Crea una sesión de reconocimiento de Wi-Fi con un espacio de nombres único que actúa como un para todas las sesiones de descubrimiento creadas en él.
Si la app se conecta correctamente, el sistema ejecuta
onAttached()
.
Esta devolución de llamada proporciona un objeto WifiAwareSession
.
que tu app debe usar para todas las demás operaciones de sesión. Una aplicación puede usar la
sesión para publicar un servicio o
suscribirse a un servicio.
Tu app debería llamar
attach()
solo una vez. Si
tu app llama a attach()
varias veces, la app recibe una sesión diferente para cada llamada, cada una con
su propio espacio de nombres. Esto podría ser útil en situaciones complejas, pero
en general, evitarlo.
Publica un servicio
Para que un servicio sea detectable, llama al
publish()
, que
toma los siguientes parámetros:
PublishConfig
especifica el nombre de la y otras propiedades de configuración, como el filtro de coincidencias.DiscoverySessionCallback
especifica la acciones para ejecutar cuando ocurren eventos, como cuando el suscriptor recibe un mensaje.
Por ejemplo:
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);
Si la publicación se realiza con éxito,
onPublishStarted()
de devolución de llamada.
Después de la publicación, cuando los dispositivos que ejecutan apps de suscriptor coincidentes pasen a la
a través del alcance de Wi-Fi del dispositivo de publicación, los suscriptores descubren el servicio. Cuándo
el suscriptor descubre al publicador, el publicador no recibe
notificación; Sin embargo, si el suscriptor envía un mensaje al publicador,
el publicador recibe una notificación. Cuando eso sucede, el
onMessageReceived()
de devolución de llamada. Puedes usar la
PeerHandle
de este método para
enviar un mensaje al suscriptor
crea una conexión con él.
Para dejar de publicar el servicio, llama a
DiscoverySession.close()
Las sesiones de descubrimiento están asociadas a su elemento superior
WifiAwareSession
Si la sesión superior es
cerrado, las sesiones de descubrimiento asociadas también se cierran. Mientras se descartaba
los objetos también están cerrados, el sistema no garantiza cuándo están fuera del alcance
las sesiones están cerradas, por lo que te recomendamos que llames explícitamente a close()
.
Suscríbete a un servicio
Para suscribirte a un servicio, llama al
método subscribe()
,
que toma los siguientes parámetros:
-
SubscribeConfig
especifica el nombre de la servicio al cual suscribirse y otras propiedades de configuración, como las filtro. DiscoverySessionCallback
especifica la acciones para ejecutar cuando ocurren eventos, como cuando se descubre a un publicador.
Por ejemplo:
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);
Si la operación de suscripción se realiza correctamente, el sistema llama a
onSubscribeStarted()
en tu app. Debido a que puedes usar el
el argumento SubscribeDiscoverySession
en
para comunicarte con un editor después de que tu aplicación haya descubierto uno,
debe guardar esta referencia. Puedes actualizar la sesión de suscripción en cualquier momento si
llamando
updateSubscribe()
en la sesión de descubrimiento.
En este punto, tu suscripción espera a que lleguen los editores coincidentes
Rango de Wi-Fi. Cuando esto sucede, el sistema ejecuta
onServiceDiscovered()
de devolución de llamada. Puedes usar el PeerHandle
argumento de esta devolución de llamada para enviar un mensaje o
Crea una conexión con ese publicador.
Para cancelar la suscripción a un servicio, llama a
DiscoverySession.close()
Las sesiones de descubrimiento están asociadas a su elemento superior
WifiAwareSession
Si la sesión superior es
cerrado, las sesiones de descubrimiento asociadas también se cierran. Mientras se descartaba
los objetos también están cerrados, el sistema no garantiza cuándo están fuera del alcance
las sesiones están cerradas, por lo que te recomendamos que llames explícitamente a close()
.
Cómo enviar un mensaje
Para enviar un mensaje a otro dispositivo, necesitas los siguientes objetos:
Un objeto
DiscoverySession
. Este objeto te permite para llamarsendMessage()
Tu app obtiene unDiscoverySession
de alguna de las siguientes maneras: publicar un servicio o suscribirse a un servicio.El
PeerHandle
del otro dispositivo, para enrutar el mensaje. Tu app recibe la de otro dispositivoPeerHandle
de dos maneras:- Tu app publica un servicio y recibe un mensaje de un suscriptor.
Tu app obtiene la señal del suscriptor
PeerHandle
desdeonMessageReceived()
devolución de llamada. - Tu app se suscribe a un servicio. Luego, cuando descubre una coincidencia
publicador, tu app obtiene los datos del publicador
PeerHandle
desdeonServiceDiscovered()
devolución de llamada.
- Tu app publica un servicio y recibe un mensaje de un suscriptor.
Tu app obtiene la señal del suscriptor
Para enviar un mensaje, llama
sendMessage()
El
pueden ocurrir las siguientes devoluciones de llamada:
- Cuando el par recibe correctamente el mensaje, el sistema llama al
onMessageSendSucceeded()
en la app emisora. - Cuando el par recibe un mensaje, el sistema llama al
onMessageReceived()
en la app receptora.
Si bien el PeerHandle
es obligatorio para comunicarse con tus pares, no debes hacerlo
confiar en él como un identificador permanente de pares. Los identificadores de nivel superior pueden
que usa la aplicación, incorporadas en el servicio de descubrimiento o en
mensajes posteriores. Puedes incorporar un identificador en el servicio de descubrimiento con
el
setMatchFilter()
o
setServiceSpecificInfo()
método de PublishConfig
o
SubscribeConfig
. El
El método setMatchFilter()
afecta el descubrimiento, mientras que el
El método setServiceSpecificInfo()
no afecta el descubrimiento.
Incorporar un identificador en un mensaje implica modificar el array de bytes del mensaje a Debe incluir un identificador (por ejemplo, como el primer par de bytes).
Crea una conexión
El reconocimiento de Wi-Fi admite la red cliente-servidor entre dos dispositivos con esa función.
Para configurar la conexión cliente-servidor:
Usa el descubrimiento de reconocimiento de Wi-Fi para publicar un servicio (en la servidor) y suscribirte a un servicio (en el cliente).
Una vez que el suscriptor descubre al publicador, Enviar un mensaje del suscriptor al publicador
Inicia un
ServerSocket
en el publicador y configurar u obtener su puerto:Kotlin
val ss = ServerSocket(0) val port = ss.localPort
Java
ServerSocket ss = new ServerSocket(0); int port = ss.getLocalPort();
Usa
ConnectivityManager
para solicita una red de reconocimiento de Wi-Fi en el editor mediante unWifiAwareNetworkSpecifier
, especificando la sesión de descubrimiento yPeerHandle
del suscriptor que obtuviste del mensaje transmitido por el suscriptor: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 vez que el publicador solicita una red, debería Envía un mensaje al suscriptor.
Una vez que el suscriptor reciba el mensaje del publicador, solicita una conexión Wi-Fi. Reconoce la red del suscriptor y usa el mismo método que el publicador. Lo que debes hacer no especificar un puerto cuando se crea la
NetworkSpecifier
El se llama a los métodos de devolución de llamada adecuados cuando se cambia la conexión de red están disponibles, cambiaron o se perdieron.Una vez que se llama al método
onAvailable()
en el suscriptor, se produce un El objetoNetwork
está disponible con puedes abrir unaSocket
para comunicarte con elServerSocket
en el publicador, pero debes conocer Dirección IPv6 y puerto deServerSocket
. Los obtienes del ObjetoNetworkCapabilities
en la devolución de llamadaonCapabilitiesChanged()
: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);
Cuando termines la conexión de red, llama
unregisterNetworkCallback()
Rango de app similares y descubrimiento del conocimiento de la ubicación
Un dispositivo con ubicación de Wi-Fi RTT pueden medir directamente la distancia a las colegas y usar esta información para restringir el descubrimiento de servicios de reconocimiento de Wi-Fi.
La API de Wi-Fi RTT permite el rango directo a una app similar con reconocimiento de Wi-Fi usando su Dirección MAC o su PeerHandle.
El descubrimiento de reconocimiento de Wi-Fi puede estar restringido a solo descubrir servicios dentro de un
un geovallado en particular. Por ejemplo, puedes configurar un geovallado que permita el descubrimiento
de un dispositivo que publica un servicio de "Aware_File_Share_Service_Name"
que no está
menos de 3 metros (especificado como 3,000 mm) y no más de 10 metros
(especificado como 10,000 mm).
Para habilitar el geovallado, tanto el publicador como el suscriptor deben tomar medidas:
El editor debe habilitar el rango en el servicio publicado usando setRangingEnabled(true)
Si el publicador no habilita el rango, se aplicarán las restricciones de geovallado. especificadas por el suscriptor se ignoran y se realiza el descubrimiento normal, ignorando la distancia.
El suscriptor debe especificar un geovallado usando alguna combinación de setMinDistanceMm y setMaxDistanceMm
Para cualquier valor, si no se especifica una distancia, esto implica que no hay un límite. Solo se especifica la distancia máxima implica una distancia mínima de 0. Solo se especifica el la distancia mínima implica que no hay un máximo.
Cuando se descubre un servicio de intercambio de tráfico en un geovallado, onServiceDiscoveredWithinRange se activa la devolución de llamada, que proporciona la distancia medida con la app similar. El a la API de Wi-Fi RTT directa se puede llamar según sea necesario para medir la distancia en en otro momento.