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:
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" />
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);
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çinBroadcastReceiver
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:
DiscoverySession
. Bu nesne,sendMessage()
numaralı telefonu aramanıza olanak tanır. Uygulamanız, bir hizmet yayınlayarak veya bir hizmete abone olarakDiscoverySession
alır.İletiyi yönlendirmek için diğer cihazın
PeerHandle
. Uygulamanız, başka bir cihazınPeerHandle
bilgilerini iki şekilde alır:- Uygulamanız bir hizmet yayınlar ve bir abonenin mesajını alır.
Uygulamanız,
onMessageReceived()
geri çağırma işlevinden aboneninPeerHandle
değerini alır. - Uygulamanız bir hizmete abone oluyor. Ardından, eşleşen bir yayıncı bulunduğunda uygulamanız,
onServiceDiscovered()
geri çağırma işlevinden yayıncınınPeerHandle
değerini alır.
- Uygulamanız bir hizmet yayınlar ve bir abonenin mesajını alır.
Uygulamanız,
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:
Hizmet yayınlamak (sunucuda) ve hizmete abone olmak (istemcide) için Wi-Fi Aware keşfini kullanın.
Abone yayıncıyı keşfettikten sonra, aboneden yayıncıya mesaj gönderin.
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();
Abone tarafından iletilen mesajdan aldığınız, abonenin
PeerHandle
ve keşif oturumunu belirterekWifiAwareNetworkSpecifier
kullanarak yayıncıda Wi-Fi Aware ağı istemek içinConnectivityManager
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);
Yayıncı bir ağ istediğinde aboneye mesaj göndermelidir.
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.Abone üzerinde
onAvailable()
yöntemi çağrıldıktan sonra, yayıncıdakiServerSocket
ile iletişim kurmak içinSocket
açabileceğiniz birNetwork
nesnesi kullanılabilir. AncakServerSocket
'ün IPv6 adresini ve bağlantı noktasını bilmeniz gerekir. Bunları,onCapabilitiesChanged()
geri çağırmasında sağlananNetworkCapabilities
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);
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.