Wi-Fi Aware'e genel bakış

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

Wi-Fi Aware ağ iletişimi, 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ışı tüm cihaz için geçerlidir ve Wi-Fi Aware sistem hizmeti tarafından yönetilir. Uygulamaların kümeleme davranışı üzerinde kontrolü yoktur. Uygulamalar, cihazdaki Wi-Fi Aware donanımını yöneten Wi-Fi Aware sistem hizmetiyle iletişim kurmak için Wi-Fi Aware API'lerini kullanır.

Wi-Fi Aware API'leri, uygulamaların aşağıdaki işlemleri gerçekleştirmesine olanak tanır:

  • Yakındaki cihazları keşfetme: API, yakındaki diğer cihazları bulmak için bir mekanizmaya sahiptir. Süreç, bir cihazın bir veya daha fazla keşfedilebilir hizmeti yayınlamasıyla başlar. Ardından, bir cihaz bir veya daha fazla hizmete abone olduğunda ve yayıncının kablosuz ağ menziline girdiğinde abone, eşleşen bir yayıncının keşfedildiğine dair bildirim alır. Abone, yayıncıyı keşfettikten sonra kısa bir mesaj gönderebilir veya keşfedilen cihazla ağ bağlantısı kurabilir. Cihazlar aynı anda hem yayıncı hem de abone olabilir.

  • Ağ bağlantısı oluşturma: İki cihaz birbirini keşfettikten sonra erişim noktası olmadan çift yönlü bir Wi-Fi Aware ağ bağlantısı oluşturabilir.

Wi-Fi Aware ağ bağlantıları, Bluetooth bağlantılarına kıyasla daha uzun mesafelerde daha yüksek veri aktarım hızlarını destekler. Bu tür bağlantılar, kullanıcılar arasında büyük miktarda veri paylaşan uygulamalar (ör. fotoğraf paylaşımı uygulamaları) için kullanışlıdır.

Android 13 (API düzeyi 33) geliştirmeleri

Anlık iletişim modunu destekleyen Android 13 (API düzeyi 33) ve sonraki sürümlerin yüklü olduğu cihazlarda uygulamalar, yayıncı veya abone keşif oturumu için anlık iletişim modunu etkinleştirmek ya da devre dışı bırakmak üzere PublishConfig.Builder.setInstantCommunicationModeEnabled() ve SubscribeConfig.Builder.setInstantCommunicationModeEnabled() yöntemlerini kullanabilir. Anlık iletişim modu; mesaj alışverişini, hizmet keşfini ve yayıncı ya da abone keşif oturumunun bir parçası olarak ayarlanan tüm veri yollarını hızlandırır. Bir cihazın anlık iletişim modunu destekleyip desteklemediğini belirlemek için isInstantCommunicationModeSupported() yöntemini kullanın.

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

Android 12 (API düzeyi 31), Wi-Fi Aware'e bazı iyileştirmeler ekler:

  • Android 12 (API düzeyi 31) veya sonraki sürümleri çalıştıran cihazlarda, uygulamanızın hizmetin durması veya kapsama alanı dışına çıkması nedeniyle keşfedilen bir hizmeti kaybettiği durumlarda uyarı almak için onServiceLost() geri çağırma işlevini kullanabilirsiniz.
  • Wi-Fi Aware veri yollarının kurulumu basitleştirildi. Önceki sürümlerde, başlatıcının MAC adresini sağlamak için L2 mesajlaşması kullanılıyordu. Bu da gecikmeye neden oluyordu. Android 12 ve sonraki sürümleri çalıştıran cihazlarda yanıtlayıcı (sunucu), herhangi bir eşi kabul edecek şekilde yapılandırılabilir. Yani başlatıcının MAC adresini önceden bilmesi gerekmez. Bu, veri yolu başlatma işlemini hızlandırır ve tek bir ağ isteğiyle birden fazla noktadan noktaya bağlantı sağlar.
  • Android 12 veya sonraki sürümlerde çalışan uygulamalar, mevcut veri yollarının, yayınlama oturumlarının ve abone oturumlarının sayısını almak için WifiAwareManager.getAvailableAwareResources() yöntemini kullanabilir. Bu sayede uygulama, istenen işlevi yürütmek için yeterli kaynak olup olmadığını belirleyebilir.

İlk kurulum

Uygulamanızı Wi-Fi Aware 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 Wi-Fi Aware'i destekleyip desteklemediğini aşağıdaki gibi PackageManager API'si ile kontrol edin:

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)

    Java

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

    Wi-Fi Aware'in kullanılabilirliği herhangi bir zamanda değişebilir. Uygulamanız, kullanılabilirlik durumu değiştiğinde gönderilen ACTION_WIFI_AWARE_STATE_CHANGED öğesini almak için bir BroadcastReceiver kaydetmelidir. Uygulamanız yayın intent'ini aldığında mevcut tüm oturumları silmeli (Wi-Fi Aware hizmetinin kesintiye uğradığını varsayarak) ve ardından mevcut kullanılabilirlik durumunu kontrol edip 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 bölümüne bakın.

Oturum alma

Wi-Fi Aware'i kullanmaya başlamak için uygulamanızın attach() yöntemini çağırarak WifiAwareSession alması gerekir. Bu yöntem şu işlemleri yapar:

  • Wi-Fi Aware donanımını etkinleştirir.
  • Wi-Fi Aware kümesine katılır veya küme oluşturur.
  • İçinde oluşturulan tüm keşif oturumları için kapsayıcı görevi gören benzersiz bir ad alanına sahip bir Wi-Fi Aware oturumu oluşturur.

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

Uygulamanız attach() yöntemini yalnızca bir kez çağırmalıdır. Uygulamanız attach() yöntemini birden fazla kez çağırırsa her çağrı için farklı bir oturum alır ve her oturumun kendi ad alanı olur. Bu, karmaşık senaryolarda yararlı olabilir ancak genellikle kaçınılmalıdır.

Hizmet yayınlama

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

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

Örneğin:

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ınlama başarılı olursa onPublishStarted() geri çağırma yöntemi çağrılır.

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

Hizmeti yayınlamayı durdurmak için DiscoverySession.close() yöntemini çağırın. Keşif oturumları, üst öğeleriyle ilişkilendirilir WifiAwareSession. Üst oturum kapatılırsa ilişkili keşif oturumları da kapatılır. Atılan nesneler de kapatılır ancak 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 eşleşme filtresi gibi diğer yapılandırma özelliklerini belirtir.
  • DiscoverySessionCallback, bir yayıncı keşfedildiğinde olduğu gibi etkinlikler gerçekleştiğinde yürütülecek işlemleri belirtir.

Örneğin:

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ğırmasını çağırır. Uygulamanız bir yayıncıyı keşfettikten sonra yayıncıyla iletişim kurmak için geri çağırmadaki SubscribeDiscoverySession bağımsız değişkenini kullanabileceğinizden bu referansı kaydetmeniz gerekir. Keşif oturumunda updateSubscribe() yöntemini çağırarak abone oturumunu istediğiniz zaman güncelleyebilirsiniz.

Bu noktada, aboneliğiniz eşleşen yayıncıların kablosuz ağ kapsama alanına girmesini bekler. Bu durumda sistem, onServiceDiscovered() geri çağırma yöntemini yürütür. Bu geri çağırmadaki PeerHandle bağımsız değişkenini kullanarak ilgili yayıncıya mesaj gönderebilir veya bağlantı oluşturabilirsiniz.

Bir hizmete aboneliği durdurmak için DiscoverySession.close() işlevini çağırın. Keşif oturumları, üst öğeleriyle ilişkilendirilir WifiAwareSession. Üst oturum kapatılırsa ilişkili keşif oturumları da kapatılır. Atılan nesneler de kapatılır ancak sistem, kapsam dışı oturumların ne zaman kapatılacağını garanti etmez. Bu nedenle, close() yöntemlerini açıkça çağırmanızı öneririz.

Mesaj gönder

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

Mesaj göndermek için sendMessage() numarasını arayın. Ardından aşağıdaki geri çağırmalar gerçekleşebilir:

  • Mesaj, eş tarafından başarıyla alındığında sistem, gönderen uygulamadaki onMessageSendSucceeded() geri çağırma işlevini çağırır.
  • Mesaj alındığında sistem, alan uygulamada onMessageReceived() geri çağırma işlevini çağırır.

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

Bir iletiye tanımlayıcı yerleştirmek, ileti bayt dizisini bir tanımlayıcı içerecek şekilde (örneğin, ilk birkaç bayt olarak) değiştirmek anlamına gelir.

Bağlantı oluştur

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

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

  1. Bir hizmeti yayınlamak (sunucuda) ve bir hizmete abone olmak (istemcide) için Wi-Fi Aware keşfini 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 bir Wi-Fi Aware ağı istemek için ConnectivityManager sınıfını kullanın. Bu işlem için WifiAwareNetworkSpecifier nesnesini kullanarak keşif oturumunu ve abonenin PeerHandle değerini belirtin. Bu değeri, abonenin ilettiği mesajdan elde edebilirsiniz:

    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ğ istediğinde aboneye mesaj göndermelidir.

  6. Abone, yayıncıdan mesajı aldıktan sonra yayıncıda kullanılan yöntemin aynısını kullanarak abonede bir Wi-Fi Aware ağı isteyin. NetworkSpecifier oluştururken bağlantı noktası belirtmeyin. Ağ bağlantısı kullanılabilir olduğunda, değiştiğinde veya kesildiğinde uygun geri çağırma yöntemleri çağrılır.

  7. Abone üzerinde onAvailable() yöntemi çağrıldıktan sonra, yayıncıdaki ServerSocket ile iletişim kurmak için Socket açabileceğiniz bir Network nesnesi kullanılabilir. Ancak ServerSocket'nin IPv6 adresini ve bağlantı noktasını bilmeniz gerekir. Bunları, onCapabilitiesChanged() geri çağırma işlevinde 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ıyla işiniz bittiğinde unregisterNetworkCallback() yöntemini çağırın.

Mesafe ölçümü yapan eşler ve konuma duyarlı keşif

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

Wi-Fi RTT API, MAC adresini veya PeerHandle'ını kullanarak bir Wi-Fi Aware eşine doğrudan erişim sağlar.

Wi-Fi Aware keşfi, yalnızca belirli bir coğrafi sınır içindeki hizmetleri keşfedecek şekilde kısıtlanabilir. Örneğin, 3 metreden (3.000 mm olarak belirtilir) daha yakın ve 10 metreden (10.000 mm olarak belirtilir) daha uzak olmayan bir "Aware_File_Share_Service_Name" hizmeti yayınlayan cihazın keşfedilmesine olanak tanıyan bir coğrafi sınır oluşturabilirsiniz.

Coğrafi sınır çizme özelliğini etkinleştirmek için hem yayıncının hem de abonenin harekete geçmesi gerekir:

  • Yayıncı, setRangingEnabled(true) kullanarak yayınlanan hizmette ölçümü etkinleştirmelidir.

    Yayıncı, menzil belirlemeyi etkinleştirmezse abone tarafından belirtilen tüm coğrafi sınır kısıtlamaları yok sayılır ve mesafe dikkate alınmadan normal keşif gerçekleştirilir.

  • Abone, setMinDistanceMm ve setMaxDistanceMm'nin bir kombinasyonunu kullanarak coğrafi sınır belirtmelidir.

    Her iki değer için de belirtilmeyen bir mesafe, sınır olmadığı anlamına gelir. Yalnızca maksimum mesafenin belirtilmesi, minimum mesafenin 0 olduğu anlamına gelir. Yalnızca minimum mesafenin belirtilmesi, maksimum mesafe olmadığı anlamına gelir.

Bir coğrafi sınır içinde eşler arası hizmet keşfedildiğinde onServiceDiscoveredWithinRange geri çağırma işlevi tetiklenir. Bu işlev, eşe olan ölçülen mesafeyi sağlar. Doğrudan Wi-Fi RTT API'si daha sonra mesafeyi ölçmek için gerektiğinde çağrılabilir.