Présentation de Wi-Fi Aware

Les fonctionnalités Wi-Fi Aware permettent aux appareils équipés d'Android 8.0 (niveau d'API 26) et de se découvrir et de communiquer directement les uns avec les autres sans avoir la connectivité entre eux. L'abonnement Wi-Fi Aware est également connu sous le nom de Neighbor Awareness Mise en réseau (NAN).

La mise en réseau Wi-Fi Aware consiste à former des clusters avec les appareils voisins. en créant un cluster si l'appareil est le premier dans une zone donnée. Ce le regroupement s'applique à l'ensemble de l'appareil et est géré par le réseau Wi-Fi Service système conscient les applications n'ont aucun contrôle sur le comportement du clustering. Utilisation des applications les API Wi-Fi Aware pour communiquer avec le service système Wi-Fi Aware, qui gère le matériel Wi-Fi Aware sur l'appareil.

Les API Wi-Fi Aware permettent aux applications d'effectuer les opérations suivantes:

  • Détecter d'autres appareils:l'API dispose d'un mécanisme permettant de trouver d'autres appareils à proximité. Le processus commence lorsqu'un appareil en publie un ou des services plus visibles. Ensuite, lorsqu'un appareil s'abonne à un ou plusieurs et entre dans la plage Wi-Fi de l'éditeur, l'abonné reçoit une notification indiquant qu'un éditeur correspondant a été détecté. Après le l'abonné découvre un éditeur, il peut envoyer un Short ou établir une connexion réseau avec l'appareil détecté. Les appareils peuvent être à la fois des éditeurs et des abonnés.

  • Créez une connexion réseau:après que deux appareils ont détecté chacun. Ils peuvent aussi créer une connexion Wi-Fi-Aware bidirectionnelle sans point d'accès.

Les connexions réseau Wi-Fi Aware offrent des débits plus élevés sur des par rapport au Bluetooth connexions externes. Ces types de connexions sont utiles pour les applications qui partagent de grandes de données entre les utilisateurs, comme les applications de partage de photos.

Améliorations apportées à Android 13 (niveau d'API 33)

Sur les appareils équipés d'Android 13 (niveau d'API 33) ou version ultérieure prenant en charge les instantanés mode de communication, les applications peuvent utiliser PublishConfig.Builder.setInstantCommunicationModeEnabled() et Méthodes SubscribeConfig.Builder.setInstantCommunicationModeEnabled() permettant de activer ou désactiver le mode de communication instantanée pour un éditeur ou un abonné la session de découverte. Le mode de communication instantané accélère l'échange de messages, la détection de services, et tout chemin de données configuré dans le cadre d'un éditeur ou d'un abonné la session de découverte. Pour déterminer si un appareil prend en charge la communication instantanée utilisez la méthode isInstantCommunicationModeSupported().

Améliorations apportées à Android 12 (niveau d'API 31)

Android 12 (niveau d'API 31) ajoute quelques améliorations à Wi-Fi Aware:

  • Sur les appareils équipés d'Android 12 (niveau d'API 31) ou version ultérieure, vous pouvez utiliser la onServiceLost() pour être alerté lorsque votre application a perdu un service détecté en raison de la le service s'arrête ou se déplace en dehors de la plage.
  • La configuration des chemins de données Wi-Fi Aware a été simplifiée. Versions antérieures utilisé la messagerie L2 pour fournir l'adresse MAC de l'initiateur, qui la latence a été introduite. Sur les appareils équipés d'Android 12 ou version ultérieure, (serveur) peut être configuré pour accepter n'importe quel pair, c'est-à-dire qu'il n'a pas besoin de connaître l’adresse MAC de l’initiateur à l’avance. Cela accélère le chemin de données et permet plusieurs liaisons point à point avec un seul réseau requête.
  • Les applications fonctionnant sous Android 12 ou version ultérieure peuvent utiliser WifiAwareManager.getAvailableAwareResources() pour obtenir le nombre de chemins de données actuellement disponibles, publier des sessions, et "S'abonner". Cela peut aider l'application à déterminer s'il y a suffisamment de ressources disponibles pour exécuter la fonctionnalité souhaitée.

Configuration initiale

Pour configurer votre application afin d'utiliser la détection et la mise en réseau Wi-Fi Aware, effectuez les procédez comme suit:

  1. Demandez les autorisations suivantes dans le fichier manifeste de votre application:

    <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" />
    
  2. Vérifiez si l'appareil est compatible avec Wi-Fi Aware à l'aide de l' PackageManager comme indiqué ci-dessous:

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
    

    Java

    context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
    
  3. Vérifiez si Wi-Fi Aware est actuellement disponible. Wi-Fi Aware peut être activé l'appareil, mais il est possible qu'elle ne soit pas disponible, car l'utilisateur a désactivé Wi-Fi ou localisation. Selon les capacités de leur matériel et de leur micrologiciel, certains appareils risque de ne pas être compatible avec le Wi-Fi Aware si le mode Wi-Fi Direct, SoftAP ou le partage de connexion est activé utiliser. Pour vérifier si Wi-Fi Aware est actuellement disponible, appelez isAvailable()

    La disponibilité de Wi-Fi Aware peut changer à tout moment. Votre application doit enregistrez un BroadcastReceiver pour recevoir ACTION_WIFI_AWARE_STATE_CHANGED, qui est envoyé dès que la disponibilité change. Lorsque votre application reçoit le de diffusion, il doit supprimer toutes les sessions existantes (en supposant que le service Wi-Fi Aware a été interrompu), puis vérifiez le l'état actuel de la disponibilité et ajustez son comportement en conséquence. Exemple :

    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);
    

Pour en savoir plus, consultez la section Diffusions.

Obtenir une session

Pour commencer à utiliser Wi-Fi Aware, votre application doit obtenir un WifiAwareSession en appelant attach() Cette méthode effectue les opérations suivantes:

  • Active le matériel Wi-Fi Aware.
  • Joint ou forme un cluster Wi-Fi Aware.
  • Crée une session Wi-Fi Aware avec un espace de noms unique faisant office de pour toutes les sessions de découverte créées dans celui-ci.

Si l'application est correctement associée, le système exécute Rappel onAttached(). Ce rappel fournit un objet WifiAwareSession. que votre application doit utiliser pour toutes les opérations de session ultérieures. Une application peut utiliser une session pour publier un service, s'abonner à un service.

Votre application doit appeler attach() une seule fois. Si votre application appelle attach() plusieurs fois, l'application reçoit une session différente pour chaque appel, chacun avec son propre espace de noms. Cela peut être utile dans des scénarios complexes, généralement à éviter.

Publier un service

Pour rendre un service visible, appelez la méthode publish(), qui utilise les paramètres suivants:

  • PublishConfig spécifie le nom du de service et d'autres propriétés de configuration, telles que le filtre de correspondance.
  • DiscoverySessionCallback spécifie des actions à exécuter lorsque des événements se produisent, par exemple lorsque l'abonné reçoit un message.

Exemple :

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 publication réussit, onPublishStarted() est appelée.

Après la publication, lorsque les appareils exécutant les applications d'abonnés correspondantes sont déplacés vers la portée Wi-Fi de l'appareil publié, les abonnés découvrent le service. Quand ? un abonné découvre un éditeur, l'éditeur ne reçoit pas notification si l'abonné envoie un message à l'éditeur : l'éditeur reçoit une notification. Lorsque cela se produit, le onMessageReceived() est appelée. Vous pouvez utiliser l'argument PeerHandle de cette méthode pour renvoyer un message à l'abonné créer une connexion à celle-ci.

Pour arrêter la publication du service, appelez DiscoverySession.close() Les sessions de découverte sont associées à leurs parents WifiAwareSession Si la session parente est les sessions de découverte associées sont également fermées. Après suppression sont également fermés, le système ne garantit pas s'ils sont hors du champ d'application sessions sont fermées. Nous vous recommandons donc d'appeler explicitement close() méthodes.

S'abonner à un service

Pour vous abonner à un service, appelez la méthode subscribe(), qui utilise les paramètres suivants:

  • SubscribeConfig spécifie le nom du auquel s'abonner et d'autres propriétés de configuration, comme la correspondance filtre.
  • DiscoverySessionCallback spécifie des actions à exécuter lorsque des événements se produisent, par exemple lorsqu'un éditeur est découvert.

Exemple :

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 l'opération d'abonnement aboutit, le système appelle onSubscribeStarted() dans votre application. Comme vous pouvez utiliser le l'argument SubscribeDiscoverySession dans pour communiquer avec un éditeur lorsque votre application en a identifié un, vous doit enregistrer cette référence. Vous pouvez modifier la session d'abonnement à tout moment en Appel en cours updateSubscribe() lors de la session de découverte.

À ce stade, votre abonnement attend que les éditeurs correspondants Portée du Wi-Fi. Dans ce cas, le système exécute onServiceDiscovered() . Vous pouvez utiliser l'PeerHandle un argument de ce rappel pour envoyer un message ou créer un lien avec cet éditeur.

Pour arrêter de vous abonner à un service, appelez DiscoverySession.close() Les sessions de découverte sont associées à leurs parents WifiAwareSession Si la session parente est les sessions de découverte associées sont également fermées. Après suppression sont également fermés, le système ne garantit pas s'ils sont hors du champ d'application sessions sont fermées. Nous vous recommandons donc d'appeler explicitement close() méthodes.

Envoyer un message

Pour envoyer un message à un autre appareil, vous avez besoin des objets suivants:

Pour envoyer un message, appelez sendMessage() La Les rappels suivants peuvent alors se produire:

  • Lorsque le message est reçu avec succès par le pair, le système appelle la méthode onMessageSendSucceeded() dans l'application sending.
  • Lorsque le pair reçoit un message, le système appelle la méthode onMessageReceived() dans l'application receve.

Bien que PeerHandle soit obligatoire pour communiquer avec les pairs, vous ne devez pas l'utiliser comme identifiant permanent des pairs. Les identifiants de niveau supérieur peuvent être utilisées par l'application, qu'elles soient intégrées au service de découverte lui-même ou messages suivants. Vous pouvez intégrer un identifiant dans le service de découverte la setMatchFilter() ou setServiceSpecificInfo() méthode PublishConfig ou SubscribeConfig. La La méthode setMatchFilter() affecte la découverte, tandis que la méthode La méthode setServiceSpecificInfo() n'affecte pas la découverte.

L'intégration d'un identifiant dans un message implique la modification du tableau d'octets du message pour incluent un identifiant (par exemple, dans les premiers octets).

Créer une connexion

Wi-Fi Aware est compatible avec la mise en réseau client-serveur entre deux appareils Wi-Fi Aware.

Pour configurer la connexion client-serveur:

  1. Utilisez la détection Wi-Fi Aware pour publier un service (sur la serveur) et vous abonner à un service (sur le client).

  2. Une fois que l'abonné a trouvé l'éditeur, Envoyer un message de l'abonné à l'éditeur

  3. Démarrer une ServerSocket sur l'éditeur et définir ou obtenir son port:

    Kotlin

    val ss = ServerSocket(0)
    val port = ss.localPort
    

    Java

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
    
  4. Utilisez ConnectivityManager pour demander un réseau Wi-Fi Aware de l'éditeur à l'aide d'un WifiAwareNetworkSpecifier, en spécifiant la session de découverte PeerHandle de l'abonné, obtenue à partir du message transmis par l'abonné:

    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);
    
  5. Lorsque l'éditeur demande un réseau, envoyer un message à l'abonné.

  6. Une fois que l'abonné a reçu le message de l'éditeur, demandez une connexion Wi-Fi réseau Aware sur l'abonné à l'aide de la même méthode que sur l'éditeur. À faire et non de port lors de la création NetworkSpecifier La les méthodes de rappel appropriées sont appelées lorsque la connexion réseau est disponibles, modifiées ou perdues.

  7. Une fois la méthode onAvailable() appelée sur l'abonné, une L'objet Network est disponible avec que vous pouvez ouvrir un Socket pour communiquer avec ServerSocket sur l'éditeur, mais vous devez connaître Adresse IPv6 et port de ServerSocket. Vous pouvez les obtenir via Objet NetworkCapabilities fournies dans le rappel onCapabilitiesChanged():

    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);
    
  8. Une fois la connexion réseau établie, appelez unregisterNetworkCallback()

Comparaison des applications similaires et détection de la position

Un appareil avec localisation texte en temps réel via le Wi-Fi peuvent mesurer directement la distance par rapport aux pairs et utiliser ces informations pour la détection de services Wi-Fi Aware.

L'API Wi-Fi DAR permet une portée directe vers un pair Wi-Fi Aware à l'aide de son adresse MAC ou son PeerHandle.

La détection Wi-Fi Aware peut être limitée à certains services au sein d'une une zone de géorepérage spécifique. Par exemple, vous pouvez configurer une zone de géorepérage pour permettre la découverte d'un appareil publiant un service "Aware_File_Share_Service_Name" qui n'est pas entre moins de 3 mètres (3 000 mm) et 10 mètres au maximum (valeur spécifiée : 10 000 mm).

Pour activer le géorepérage, l'éditeur et l'abonné doivent tous deux prendre les mesures suivantes:

  • L'éditeur doit activer les plages sur le service publié à l'aide de setRangingEnabled(true).

    Si l'éditeur n'active pas la mesure des distances, les contraintes de géorepérage spécifiée par l'abonné sont ignorées et la découverte normale est effectuée, en ignorant la distance.

  • L'abonné doit spécifier une zone de géorepérage en utilisant une combinaison des éléments suivants : setMinDistanceMm. et setMaxDistanceMm.

    Pour l'une ou l'autre des valeurs, une distance non spécifiée n'implique aucune limite. Spécifier uniquement la distance maximale implique une distance minimale de 0. En spécifiant uniquement la distance minimale n'implique pas de maximum.

Lorsqu'un service pair est découvert dans une zone de géorepérage, onServiceDiscoveredWithinRange qui indique la distance mesurée jusqu'au pair. La l'API de DAR Wi-Fi direct peut ensuite être appelée si nécessaire pour mesurer la distance à plus tard.