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 birbirlerini keşfetmelerini ve aralarında başka bir bağlantı türü olmadan doğrudan bağlanmalarını sağlar. Wi-Fi Aware, Neighbor Awareness Networking (NAN) olarak da bilinir.

Wi-Fi Aware ağı, yakındaki 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 herhangi bir 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:

  • Diğer cihazları keşfetme: API, yakındaki diğer cihazları bulma mekanizmasına sahiptir. İşlem, bir cihaz bir veya daha fazla keşfedilebilir hizmet yayınladığında başlar. Ardından, bir cihaz bir veya daha fazla hizmete abone olup yayıncının kablosuz ağ aralığına girdiğinde aboneye eşleşen bir yayıncının keşfedildiğine dair bildirim gönderilir. Abone bir 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 işleme hızı oranlarını destekler. Bu bağlantı türleri, 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'teki (API düzeyi 33) geliştirmeler

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ı veya 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ı geliştirmeler ekler:

  • Android 12 (API düzeyi 31) veya sonraki sürümlerin yüklü olduğu cihazlarda, uygulamanızın hizmet durdurulduğu ya da kapsama alanı dışına çıktığı için keşfedilen bir hizmeti kaybettiğinde 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şma kullanılıyordu. Bu da gecikmeye neden oluyordu. Android 12 ve sonraki sürümlerin yüklü olduğu 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 yalnızca tek bir ağ isteğiyle birden fazla noktadan noktaya bağlantı sağlar.
  • Android 12 veya sonraki sürümlerde çalışan uygulamalar, şu anda kullanılabilen veri yollarının sayısını almak, oturumları yayınlamak ve oturumlara abone olmak için WifiAwareManager.getAvailableAwareResources() yöntemini kullanabilir. Bu, uygulamanın istediği işlevselliği yerine getirmek için yeterli kaynak olup olmadığını belirlemesine yardımcı olabilir.

İlk kurulum

Uygulamanızı Wi-Fi Aware keşif ve ağ oluşturma özelliğini 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. Aşağıda gösterildiği gibi PackageManager API'si ile cihazın 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'in şu anda kullanılıp kullanılamadığını kontrol edin. Cihazda Wi-Fi Aware özelliği bulunuyor olabilir ancak kullanıcı Wi-Fi'ı veya Konum'u devre dışı bıraktığı için şu anda kullanılamıyor olabilir. Bazı cihazlar, donanım ve ürün yazılımı özelliklerine bağlı olarak Wi-Fi Direct, SoftAP veya tethering kullanılıyorsa Wi-Fi Aware'i desteklemeyebilir. Wi-Fi Aware'in şu anda kullanılıp kullanılamadığını kontrol etmek için isAvailable() numaralı telefonu arayın.

    Wi-Fi Aware'in kullanılabilirliği herhangi bir zamanda değişebilir. Uygulamanız, kullanılabilirlik her değiştiğinde gönderilen ACTION_WIFI_AWARE_STATE_CHANGED almak için BroadcastReceiver kaydetmelidir. Uygulamanız yayın amaçlı iletiyi aldığında mevcut tüm oturumları silmeli (Wi-Fi Aware hizmetinin kesintiye uğradığını varsayarak) ve ardından 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 başlıklı makaleyi inceleyin.

Oturum alma

Wi-Fi Aware'i kullanmaya başlamak için uygulamanızın WifiAwareSession çağrısı yaparak attach() alması gerekir. Bu yöntem şunları yapar:

  • Wi-Fi Aware donanımını açar.
  • Bir 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ğırmasını yürütür. Bu geri çağırma, uygulamanızın sonraki tüm oturum işlemleri için kullanması gereken bir WifiAwareSession nesnesi sağlar. Bir uygulama, oturumu hizmet yayınlamak veya hizmete abone olmak için kullanabilir.

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

Hizmet yayınlama

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

Yayınlandıktan sonra, eşleşen abone uygulamalarının yüklü olduğu cihazlar yayıncı cihazın kablosuz ağ aralığına 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. Bu yöntemin PeerHandle bağımsız değişkenini kullanarak aboneye mesaj gönderebilir veya aboneyle bağlantı oluşturabilirsiniz.

Hizmetin yayınlanmasını durdurmak için DiscoverySession.close() numaralı telefonu arayın. Keşif oturumları, üst öğeleri WifiAwareSession ile ilişkilendirilir. Ü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 önerilir.

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, etkinlikler gerçekleştiğinde (ör. bir yayıncı keşfedildiğ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);

Abonelik işlemi başarılı olursa sistem, uygulamanızdaki onSubscribeStarted() geri çağırma işlevini çağırır. Uygulamanız bir yayıncıyı keşfettikten sonra yayıncıyla iletişim kurmak için geri çağırma işlevindeki SubscribeDiscoverySession bağımsız değişkenini kullanabileceğinizden bu referansı kaydetmeniz gerekir. Keşif oturumunda updateSubscribe() çağrısı yaparak abone olma oturumunu istediğiniz zaman güncelleyebilirsiniz.

Bu noktada aboneliğiniz, Wi-Fi menziline girecek eşleşen yayıncıları bekler. Bu durumda sistem, onServiceDiscovered() geri çağırma yöntemini yürütür. Bu geri çağırmadan gelen PeerHandle bağımsız değişkenini kullanarak yayıncıya mesaj gönderebilir veya yayıncıyla bağlantı oluşturabilirsiniz.

Bir hizmete abone olmayı durdurmak için DiscoverySession.close() numaralı telefonu arayın. Keşif oturumları, üst öğeleri WifiAwareSession ile ilişkilendirilir. Ü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 önerilir.

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() numaralı telefonu arayın. Ardından 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ğırmasını çağırır.
  • Diğer kullanıcı mesaj aldığında sistem, receiving uygulamasında onMessageReceived() geri çağırma işlevini çağırır.

Meslektaşlarla iletişim kurmak için PeerHandle gerekli olsa da meslektaşların kalıcı tanımlayıcısı olarak kullanmamalısınız. Daha üst düzey tanımlayıcılar, keşif hizmetinin kendisine veya sonraki iletilere yerleştirilmiş olarak uygulama tarafından kullanılabilir. setMatchFilter() veya setServiceSpecificInfo() PublishConfig ya da SubscribeConfig yöntemiyle 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şturma

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. Hizmet yayınlamak (sunucuda) ve 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 mesaj gönderin.

  3. Yayıncı cihazda ServerSocket başlatın ve bağlantı noktasını ayarlayın veya edinin:

    Kotlin

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

    Java

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
  4. Abone tarafından iletilen mesajdan aldığınız, abonenin PeerHandle ve keşif oturumunu belirterek WifiAwareNetworkSpecifier kullanarak yayıncıda Wi-Fi Aware ağı istemek için ConnectivityManager kullanın:

    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öntemle abone üzerinde 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 kaybolduğunda 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'ün 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ı işiniz bittiğinde aramayı sonlandırın unregisterNetworkCallback().

Ranging ve konuma duyarlı keşif

Wi-Fi RTT konum özelliklerine sahip bir cihaz, diğer cihazlara olan mesafeyi doğrudan ölçebilir ve bu bilgileri Wi-Fi Aware hizmeti 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 mesafe ölçümü yapılmasına olanak tanır.

Wi-Fi Aware keşfi, yalnızca belirli bir coğrafi sınırdaki 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 izin veren bir coğrafi çit oluşturabilirsiniz.

Coğrafi sınırlama özelliğini etkinleştirmek için hem yayıncının hem de abonenin işlem yapması gerekir:

  • Yayıncı, yayınlanan hizmette setRangingEnabled(true) yöntemini kullanarak mesafeyi etkinleştirmelidir.

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

  • Abone, setMinDistanceMm ve setMaxDistanceMm değerlerinin bir kombinasyonunu kullanarak bir coğrafi çit belirtmelidir.

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

Bir coğrafi sınırlı alan içinde eş hizmeti keşfedildiğinde, eşe olan ölçülen mesafeyi sağlayan onServiceDiscoveredWithinRange geri çağırma işlemi tetiklenir. Daha sonraki zamanlarda mesafeyi ölçmek için doğrudan kablosuz RTT API'si gerektiği şekilde çağrılabilir.