Wi-Fi Aware'e genel bakış

Wi-Fi Aware özellikleri, Android 8.0 (API düzeyi 26) ve üstü sürümleri çalıştıran cihazların aralarında başka herhangi bir bağlantı türü olmadan doğrudan birbirlerini keşfedip bağlanabilmelerini sağlar. Wi-Fi Aware, Komşu Farkındalık Ağ İletişimi (NAN) olarak da bilinir.

Wi-Fi duyarlı ağ, komşu cihazlarla kümeler oluşturarak veya cihaz bir bölgedeki ilk cihazsa yeni bir küme oluşturarak çalışır. Bu kümeleme davranışı cihazın tamamı için geçerlidir ve Wi-Fi-Aware sistem hizmeti tarafından yönetilir. Uygulamaların kümeleme davranışı üzerinde herhangi bir kontrolü yoktur. Uygulamalar, cihazdaki Wi-Fi Aware donanımını yöneten Wi-Fi Aware sistem hizmetiyle konuşmak için Wi-Fi Aware API'lerini kullanır.

Wi-Fi Aware API'leri uygulamaların şu işlemleri gerçekleştirmesini sağlar:

  • Diğer cihazları keşfetme: API'nin, yakındaki diğer cihazları bulmak için kullanabileceği bir mekanizma vardır. Süreç, bir cihaz bir veya daha fazla bulunabilir hizmet yayınladığında başlar. Daha sonra, cihaz bir veya daha fazla hizmete abone olduğunda ve yayıncının kablosuz ağ aralığına girdiğinde, abone eşleşen bir yayıncının bulunduğuna dair bildirim alır. Abone bir yayıncıyı keşfettikten sonra, kısa bir mesaj gönderebilir veya keşfedilen cihazla bir ağ bağlantısı kurabilir. Cihazlar aynı anda hem yayıncılar hem de aboneler olabilir.

  • Ağ bağlantısı oluşturun: İki cihaz birbirini keşfettikten sonra erişim noktası olmadan çift yönlü bir kablosuz ağa duyarlı ağ bağlantısı oluşturabilir.

Wi-Fi Duyarlı ağ bağlantıları, daha uzun mesafelerde Bluetooth bağlantılarından daha yüksek işleme hızı hızlarını destekler. Bu tür bağlantılar, fotoğraf paylaşma uygulamaları gibi kullanıcılar arasında büyük miktarda veri paylaşan uygulamalar için yararlıdır.

Android 12 (API düzeyi 31) geliştirmeleri

Android 12 (API düzeyi 31), Kablosuz Uyumluluğu'na bazı geliştirmeler ekler:

  • Android 12 (API düzeyi 31) veya sonraki sürümleri çalıştıran cihazlarda uygulamanız, hizmetin durması veya kapsama alanı dışına çıkması nedeniyle keşfedilen bir hizmeti kaybettiğinde uyarı almak için onServiceLost() geri çağırma işlevini kullanabilirsiniz.
  • Kablosuz duyarlı veri yollarının kurulumu benzer hale getirildi. Daha önceki sürümlerde, başlatıcının MAC adresini sağlamak için L2 mesajlaşması kullanılıyor ve bu da gecikmeye neden oluyordu. Android 12 ve sonraki sürümleri çalıştıran cihazlarda katılımcı (sunucu) herhangi bir eşi kabul edecek şekilde yapılandırılabilir. Bu durumda, başlatıcının MAC adresini bilmesi gerekmez. Bu, veri yolu toplanmasını hızlandırır ve yalnızca tek bir ağ isteğiyle birden çok noktadan noktaya bağlantı yapılmasına olanak tanır.
  • Android 12 veya sonraki sürümleri çalıştıran uygulamalar şu anda mevcut veri yollarının sayısını, yayınlama oturumlarını ve abone olma oturumlarını almak için WifiAwareManager.getAvailableAwareResources() yöntemini kullanabilir. Bu, uygulamanın istenen işlevi yürütmek için yeterli kaynak olup olmadığını belirlemesine yardımcı olabilir.

İlk kurulum

Uygulamanızı, kablosuz ağa duyarlı keşif ve ağ özelliklerini kullanacak şekilde ayarlamak için aşağıdaki adımları uygulayın:

  1. Uygulamanızın manifest dosyasında aşağıdaki izinleri isteyin:

    <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. Cihazın, aşağıda gösterildiği gibi PackageManager API ile Wi-Fi Aware'i destekleyip desteklemediğini kontrol edin:

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
    

    Java

    context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
    
  3. Wi-Fi Aware özelliğinin şu anda kullanılabilir olup olmadığını kontrol edin. Cihazda Wi-Fi Aware mevcut olabilir, ancak kullanıcı Kablosuz'u veya Konum'u devre dışı bıraktığı için şu anda kullanılamıyor olabilir. Kablosuz Doğrudan Bağlantı, SoftAP veya tethering kullanılıyorsa donanım ve donanım yazılımı özelliklerine bağlı olarak, bazı cihazlar Kablosuz Ağdan Duyarlı'yı desteklemeyebilir. Wi-Fi Aware özelliğinin şu anda kullanılabilir olup olmadığını kontrol etmek için isAvailable() numaralı telefonu arayın.

    Wi-Fi Aware özelliğinin kullanılabilirliği herhangi bir zamanda değiştirilebilir. Uygulamanız, ACTION_WIFI_AWARE_STATE_CHANGED mesajını almak için bir BroadcastReceiver kaydetmelidir. Bu numara, müsaitlik durumu değiştiğinde gönderilir. Uygulamanız yayın niyetini aldığında mevcut tüm oturumları siler (Wi-Fi Aware hizmetinin kesintiye uğradığını varsayın), ardından mevcut kullanılabilirlik durumunu kontrol etmeli ve davranışını buna göre ayarlamalıdır. Örneğin:

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

Daha fazla bilgi için Yayınlar başlıklı makaleye bakın.

Oturum alma

Wi-Fi Aware'i kullanmaya başlamak için uygulamanızın attach() numaralı telefonu arayarak bir WifiAwareSession edinmesi gerekir. Bu yöntem aşağıdakileri yapar:

  • Kablosuz duyarlılık donanımını açar.
  • Wi-Fi duyarlı bir kümeye katılır veya bu kümeyi oluşturur.
  • Bu oturumda oluşturulan tüm keşif oturumları için kapsayıcı görevi gören benzersiz bir ad alanına sahip bir Wi-Fi duyarlı oturumu oluşturur.

Uygulama başarıyla eklenirse sistem, onAttached() geri çağırma işlemini yürütür. Bu geri çağırma, uygulamanızın diğer tüm oturum işlemleri için kullanması gereken bir WifiAwareSession nesnesi sağlar. Bir uygulama, oturumu hizmet yayınlamak veya bir hizmete abone olmak için kullanabilir.

Uygulamanız attach() uygulamasını yalnızca bir kez aramalıdır. Uygulamanız attach() yöntemini birden çok kez çağırırsa her çağrı için her biri kendi ad alanına sahip farklı bir oturum alır. Bu, karmaşık senaryolarda yararlı olabilir, ancak genellikle kaçınılması gerekir.

Hizmet yayınlayın

Bir hizmeti bulunabilir hâle getirmek için aşağıdaki parametreleri alan publish() yöntemini çağırın:

  • PublishConfig, hizmetin adını ve eşleme filtresi gibi diğer yapılandırma özelliklerini belirtir.
  • DiscoverySessionCallback, abonenin bir mesaj alması gibi etkinlikler gerçekleştiğinde yürütülecek işlemleri belirtir.

Aşağıda bununla ilgili bir örnek verilmiştir:

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

Yayın başarılı olursa onPublishStarted() geri çağırma yöntemi çağrılır.

Yayından sonra, eşleşen abone uygulamalarını çalıştıran cihazlar yayınlama cihazının kablosuz bağlantı aralığına geçtiğinde, aboneler hizmeti keşfeder. Abone bir yayıncı keşfettiğinde yayıncı bir bildirim almaz. Ancak yayıncıya mesaj gönderirse yayıncı bir bildirim alır. Böyle bir durumda, onMessageReceived() geri çağırma yöntemi çağrılır. Aboneye geri bir mesaj göndermek veya aboneyle bağlantı oluşturmak için bu yöntemdeki PeerHandle bağımsız değişkenini kullanabilirsiniz.

Hizmetin yayınını durdurmak için DiscoverySession.close() numaralı telefonu arayın. Keşif oturumları üstleri WifiAwareSession ile ilişkilendirilir. Üst oturum kapalıysa ilişkili keşif oturumları da kapatılır. Silinen nesneler de kapatılırken sistem, kapsam dışı oturumların ne zaman kapatılacağını garanti etmez. Bu nedenle, close() yöntemlerini açıkça çağırmanızı öneririz.

Bir hizmete abone olma

Bir hizmete abone olmak için aşağıdaki parametreleri alan subscribe() yöntemini çağırın:

  • SubscribeConfig, abone olunacak hizmetin adını ve diğer yapılandırma özelliklerini (ör. eşleşme filtresi) belirtir.
  • DiscoverySessionCallback, bir yayıncının keşfedilmesi gibi etkinlikler gerçekleştiğinde yürütülecek işlemleri belirtir.

Aşağıda bununla ilgili bir örnek verilmiştir:

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

Abone olma işlemi başarılı olursa sistem, uygulamanızda onSubscribeStarted() geri çağırma işlevini çağırır. Uygulamanız bir yayıncı keşfettikten sonra yayıncıyla iletişim kurmak için geri çağırmadaki SubscribeDiscoverySession bağımsız değişkenini kullanabilirsiniz. Bu nedenle bu referansı kaydetmeniz gerekir. Keşif oturumunda updateSubscribe() yöntemini çağırarak abone olma oturumunu istediğiniz zaman güncelleyebilirsiniz.

Bu noktada aboneliğiniz, eşleşen yayıncıların kablosuz ağ aralığına girmesini bekler. Böyle bir durumda, sistem onServiceDiscovered() geri çağırma yöntemini çalıştırır. Söz konusu yayıncıya mesaj göndermek veya bağlantı oluşturmak için bu geri çağırmadaki PeerHandle bağımsız değişkenini kullanabilirsiniz.

Bir hizmete aboneliği durdurmak için DiscoverySession.close() numaralı telefonu arayın. Keşif oturumları üstleri WifiAwareSession ile ilişkilendirilir. Üst oturum kapalıysa ilişkili keşif oturumları da kapatılır. Silinen nesneler de kapatılırken sistem, kapsam dışı oturumların ne zaman kapatılacağını garanti etmez. Bu nedenle, close() yöntemlerini açıkça çağırmanızı öneririz.

İleti gönderme

Başka bir cihaza mesaj göndermek için aşağıdaki nesnelere ihtiyacınız vardır:

Mesaj göndermek için sendMessage() numaralı telefonu arayın. Bu durumda aşağıdaki geri çağırmalar gerçekleşebilir:

  • İleti eş tarafından başarıyla alındığında, sistem gönderme uygulamasında onMessageSendSucceeded() geri çağırma işlevini çağırır.
  • Eş bir mesaj aldığında sistem, alma uygulamasında onMessageReceived() geri çağırma işlevini çağırır.

PeerHandle, benzerlerle iletişim kurmak için gerekli olsa da benzerlerin kalıcı tanımlayıcısı olarak kullanılmamalıdır. Üst düzey tanımlayıcılar, keşif hizmetinin kendisine veya sonraki mesajlara yerleştirilmiş uygulama tarafından kullanılabilir. Keşif hizmetine, PublishConfig veya SubscribeConfig ya da setMatchFilter() ya da setServiceSpecificInfo() yöntemiyle bir tanımlayıcı yerleştirebilirsiniz. setMatchFilter() yöntemi keşfi etkilerken setServiceSpecificInfo() yöntemi keşfi etkilemez.

Bir tanımlayıcının iletiye yerleştirilmesi, mesaj bayt dizisinin bir tanımlayıcı içerecek şekilde değiştirilmesini gerektirir (örneğin, ilk birkaç bayt olarak).

Bağlantı oluşturma

Wi-Fi Aware, iki Wi-Fi Aware cihaz arasında istemci-sunucu ağını destekler.

İstemci-sunucu bağlantısını kurmak için:

  1. Bir hizmet yayınlamak (sunucuda) ve bir hizmete abone olmak (istemcide) için Wi-Fi duyarlı keşif özelliğini kullanın.

  2. Abone yayıncıyı keşfettikten sonra aboneden yayıncıya bir mesaj gönderin.

  3. Yayıncı cihazında bir ServerSocket başlatın ve bağlantı noktasını ayarlayın veya alın:

    Kotlin

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

    Java

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
    
  4. Yayıncıda WifiAwareNetworkSpecifier kullanarak bir Wi-Fi duyarlı ağı istemek için ConnectivityManager kullanın. Keşif oturumunu ve abone tarafından iletilen mesajdan aldığınız abonenin PeerHandle bilgisini belirtin:

    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. Yayıncı bir ağ isteğinde bulunduğunda aboneye bir mesaj göndermelidir.

  6. Abone, yayıncıdan mesajı aldıktan sonra, yayıncıyla aynı yöntemi kullanarak abonede bir Wi-Fi duyarlı ağ isteyin. NetworkSpecifier oluştururken bağlantı noktası belirtmeyin. Uygun geri çağırma yöntemleri, ağ bağlantısı mevcut olduğunda, değiştirildiğinde veya koptuğunda çağrılır.

  7. Abonede onAvailable() yöntemi çağrıldıktan sonra bir Network nesnesi kullanılabilir. Bu nesneyi kullanarak bir Socket açarak yayıncıda ServerSocket ile iletişim kurabilirsiniz, ancakServerSocket öğesinin IPv6 adresini ve bağlantı noktasını bilmeniz gerekir. Bunları onCapabilitiesChanged() geri çağırmasında sağlanan NetworkCapabilities nesnesinden alırsınız:

    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. Ağ bağlantısını bitirdiğinizde unregisterNetworkCallback() numaralı telefonu arayın.

Benzerleri karşılaştırma ve konuma duyarlı keşif

Kablosuz RTT konumu özelliklerine sahip bir cihaz, benzerlere olan mesafeyi doğrudan ölçebilir ve bu bilgileri Wi-Fi Aware hizmet keşfini sınırlandırmak için kullanabilir.

Wi-Fi RTT API, MAC adresini veya PeerHandle öğesini kullanarak Wi-Fi Aware eşe doğrudan erişim imkanı sunar.

Wi-Fi Duyarlı keşif özelliği, yalnızca belirli bir coğrafi sınır içindeki hizmetleri keşfedecek şekilde kısıtlanabilir. Örneğin, 3 metreden daha yakın (3.000 mm olarak belirtilir) ve 10 metreden (10.000 mm olarak belirtilir) daha yakın olmayan bir "Aware_File_Share_Service_Name" hizmeti yayınlayan cihazın bulunmasını sağlayan bir coğrafi sınır oluşturabilirsiniz.

Coğrafi sınır çizmeyi etkinleştirmek için yayıncının ve abonenin işlem yapması gerekir:

  • Yayıncı, setRangingEnabled(true) değerini kullanarak yayınlanan hizmette aralığı etkinleştirmelidir.

    Yayıncı aralığı etkinleştirmezse abone tarafından belirtilen coğrafi sınır kısıtlamaları yok sayılır ve mesafe göz ardı edilerek normal keşif gerçekleştirilir.

  • Abonenin bir coğrafi sınır belirlemesi için setMinDistanceMm ve setMaxDistanceMm kombinasyonlarını kullanması gerekir.

    Her iki değer için de belirtilmeyen bir mesafe, herhangi bir sınır anlamına gelmez. Yalnızca maksimum mesafe belirtildiğinde, minimum mesafe 0 anlamına gelir. Yalnızca minimum mesafenin belirtilmesi maksimum değer anlamına gelmez.

Coğrafi sınır içinde bir eş hizmet bulunduğunda, onServiceExploreedWithinRange geri çağırması tetiklenir ve bu işlem, eşle ölçülen mesafeyi sağlar. Daha sonra mesafeyi ölçmek için gerektiğinde doğrudan Wi-Fi RTT API'si çağrılabilir.