Ringkasan Wi-Fi Aware

Kemampuan Wi-Fi Aware memungkinkan perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi untuk saling menemukan dan terhubung langsung tanpa ada jenis konektivitas lain di antara keduanya. Wi-Fi Aware juga dikenal sebagai Neighbor Awareness Jaringan (NAN).

Jaringan Wi-Fi Aware bekerja dengan membentuk kelompok dengan perangkat di dekatnya, atau dengan membuat cluster baru jika perangkat adalah yang pertama di suatu area. Ini perilaku pengelompokan berlaku di seluruh perangkat dan dikelola oleh jaringan Wi-Fi Layanan sistem Aware; aplikasi tidak memiliki kontrol atas perilaku pengelompokan. Aplikasi menggunakan Wi-Fi Aware API untuk berkomunikasi dengan layanan sistem Wi-Fi Aware, yang mengelola hardware Wi-Fi Aware di perangkat.

API Wi-Fi Aware memungkinkan aplikasi menjalankan operasi berikut:

  • Menemukan perangkat lain: API memiliki mekanisme untuk menemukan perangkat di sekitar. Proses dimulai saat satu perangkat memublikasikan perangkat atau layanan yang lebih dapat ditemukan. Kemudian, saat perangkat berlangganan ke satu atau beberapa layanan dan memasuki jangkauan Wi-Fi penayang, pelanggan tersebut akan menerima notifikasi bahwa penayang yang cocok telah ditemukan. Setelah pelanggan menemukan penerbit, pelanggan dapat mengirimkan mengirim pesan atau membuat koneksi jaringan dengan perangkat yang ditemukan. Perangkat dapat menjadi penayang dan pelanggan secara bersamaan.

  • Membuat koneksi jaringan: Setelah saling menemukan, kedua perangkat dapat membuat koneksi jaringan Wi-Fi Aware dua arah tanpa titik akses.

Koneksi jaringan Wi-Fi Aware mendukung kecepatan throughput yang lebih tinggi dengan jarak yang lebih jauh dibandingkan dengan koneksi Bluetooth. Jenis koneksi ini berguna untuk aplikasi yang berbagi koneksi jumlah data antarpengguna, seperti aplikasi berbagi foto.

Peningkatan Android 13 (API level 33)

Di perangkat yang menjalankan Android 13 (level API 33) dan yang lebih baru yang mendukung fitur instan mode komunikasi, aplikasi dapat menggunakan PublishConfig.Builder.setInstantCommunicationModeEnabled() dan Metode SubscribeConfig.Builder.setInstantCommunicationModeEnabled() untuk mengaktifkan atau menonaktifkan mode komunikasi instan untuk penerbit atau pelanggan sesi penemuan. Mode komunikasi instan mempercepat pertukaran pesan, penemuan layanan, dan jalur data apa pun yang disiapkan sebagai bagian dari sesi penemuan penerbit atau pelanggan. Untuk menentukan apakah perangkat mendukung komunikasi instan gunakan metode isInstantCommunicationModeSupported().

Peningkatan Android 12 (API level 31)

Android 12 (API level 31) menambahkan beberapa peningkatan pada Wi-Fi Aware:

  • Pada perangkat yang menjalankan Android 12 (API level 31) atau yang lebih baru, Anda dapat menggunakan callback onServiceLost() untuk mendapatkan notifikasi saat layanan yang telah ditemukan oleh aplikasi Anda hilang karena layanan tersebut berhenti atau keluar dari jangkauan.
  • Penyiapan jalur data Wi-Fi Aware telah sederhana. Versi sebelumnya menggunakan pesan L2 untuk memberikan alamat MAC inisiator, yang latensi yang diperkenalkan. Pada perangkat yang menjalankan Android 12 dan yang lebih baru, responden (server) dapat dikonfigurasi untuk menerima peer apa pun—yaitu, tidak perlu untuk mengetahui alamat MAC initator di awal. Hal ini mempercepat jalur data memunculkan dan memungkinkan beberapa tautan titik ke titik hanya dengan satu jaringan permintaan.
  • Aplikasi yang berjalan di Android 12 atau yang lebih tinggi dapat menggunakan WifiAwareManager.getAvailableAwareResources() untuk mendapatkan jumlah jalur data yang tersedia saat ini, sesi publikasi, dan berlangganan. Hal ini dapat membantu aplikasi menentukan apakah ada menyediakan cukup sumber daya untuk menjalankan fungsi yang diinginkan.

Penyiapan awal

Untuk menyiapkan aplikasi Anda menggunakan penemuan dan jaringan Wi-Fi Aware, lakukan langkah-langkah berikut:

  1. Minta izin berikut dalam manifes aplikasi Anda:

    <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. Periksa apakah perangkat mendukung Wi-Fi Aware dengan PackageManager API, seperti yang ditunjukkan di bawah ini:

    Kotlin

    context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)

    Java

    context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
  3. Periksa apakah Wi-Fi Aware saat ini tersedia. Wi-Fi Aware mungkin ada di perangkat, tetapi saat ini mungkin tidak tersedia karena pengguna telah menonaktifkan Wi-Fi atau Lokasi. Bergantung pada kemampuan hardware dan firmware mereka, beberapa perangkat mungkin tidak mendukung Wi-Fi Aware jika Wi-Fi Direct, SoftAP, atau tethering sedang digunakan. Untuk memeriksa apakah Wi-Fi Aware saat ini tersedia, panggil isAvailable().

    Ketersediaan Wi-Fi Aware dapat berubah setiap saat. Aplikasi Anda harus daftarkan BroadcastReceiver untuk menerima ACTION_WIFI_AWARE_STATE_CHANGED, yang dikirim setiap kali ketersediaan berubah. Saat aplikasi Anda menerima intent siaran, itu harus membuang semua sesi yang ada (asumsikan bahwa Layanan Wi-Fi Aware terganggu), lalu periksa kondisi ketersediaan saat ini dan menyesuaikan perilakunya. Contoh:

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

Untuk informasi selengkapnya, lihat Siaran.

Mendapatkan sesi

Untuk mulai menggunakan Wi-Fi Aware, aplikasi Anda harus mendapatkan WifiAwareSession dengan memanggil attach(). Metode ini melakukan hal berikut:

  • Mengaktifkan hardware Wi-Fi Aware.
  • Bergabung atau membentuk kumpulan Wi-Fi Aware.
  • Membuat sesi Wi-Fi Aware dengan namespace unik yang berfungsi sebagai penampung untuk semua sesi penemuan yang dibuat di dalamnya.

Jika aplikasi berhasil terpasang, sistem akan menjalankan Callback onAttached(). Callback ini menyediakan objek WifiAwareSession yang harus digunakan aplikasi Anda untuk semua operasi sesi selanjutnya. Aplikasi dapat menggunakan sesi tersebut untuk memublikasikan layanan atau berlangganan ke layanan.

Aplikasi Anda harus memanggil attach() hanya sekali. Jika aplikasi Anda memanggil attach() beberapa kali, aplikasi akan menerima sesi yang berbeda untuk setiap panggilan, masing-masing dengan namespace-nya sendiri. Hal ini dapat berguna dalam skenario yang kompleks, tetapi secara umum harus dihindari.

Memublikasikan layanan

Untuk membuat layanan dapat ditemukan, panggil metode publish(), yang menggunakan parameter berikut:

  • PublishConfig menentukan nama dan properti konfigurasi lainnya, seperti filter pencocokan.
  • DiscoverySessionCallback menentukan tindakan yang akan dijalankan saat peristiwa terjadi, seperti saat pelanggan menerima pesan.

Berikut contohnya:

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

Jika publikasi berhasil, maka onPublishStarted() metode callback akan dipanggil.

Setelah publikasi, saat perangkat yang menjalankan aplikasi pelanggan yang cocok memasuki jangkauan Wi-Fi perangkat penayang, pelanggan tersebut akan menemukan layanan. Kapan pelanggan menemukan penerbit, penerbit tidak menerima notifikasi; jika pelanggan mengirim pesan ke penayang, penerbit akan menerima notifikasi. Ketika hal itu terjadi, onMessageReceived() metode callback akan dipanggil. Anda dapat menggunakan Argumen PeerHandle dari metode ini ke kirim pesan kembali ke pelanggan atau membuat koneksi dengannya.

Untuk berhenti memublikasikan layanan, panggil DiscoverySession.close(). Sesi Discovery dikaitkan dengan induknya WifiAwareSession. Jika sesi induk ditutup, sesi penemuan terkaitnya juga akan ditutup. Saat dihapus tertutup juga, sistem tidak menjamin ketika berada di luar ruang lingkup sesi ini ditutup, jadi sebaiknya Anda secara eksplisit memanggil close() metode.

Berlangganan ke layanan

Untuk berlangganan layanan, panggil metode Metode subscribe(), yang menggunakan parameter berikut:

  • SubscribeConfig menentukan nama layanan yang akan dijadikan langganan dan properti konfigurasi lainnya, seperti filter pencocokan.
  • DiscoverySessionCallback menentukan tindakan yang akan dijalankan saat peristiwa terjadi, seperti saat penayang ditemukan.

Berikut contohnya:

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

Jika operasi subscribe berhasil, sistem akan memanggil callback onSubscribeStarted() di aplikasi Anda. Karena Anda dapat menggunakan argumen SubscribeDiscoverySession di callback untuk berkomunikasi dengan penayang setelah aplikasi Anda menemukannya, Anda harus menyimpan referensi ini. Anda dapat memperbarui sesi berlangganan kapan saja dengan menelepon updateSubscribe() di sesi penemuan.

Pada tahap ini, langganan Anda menunggu penayang yang cocok untuk masuk ke dalam jangkauan Wi-Fi. Saat hal ini terjadi, sistem akan menjalankan metode callback onServiceDiscovered(). Anda dapat menggunakan argumen PeerHandle dari callback ini untuk mengirim pesan atau membuat koneksi ke penayang tersebut.

Untuk berhenti berlangganan layanan, panggil DiscoverySession.close(). Sesi penemuan dikaitkan dengan WifiAwareSession induknya. Jika sesi induk ditutup, sesi penemuan terkaitnya juga akan ditutup. Meskipun objek yang dihapus juga ditutup, sistem tidak menjamin saat sesi di luar cakupan juga ditutup, sehingga sebaiknya Anda memanggil metode close() secara eksplisit.

Mengirim pesan

Untuk mengirim pesan ke perangkat lain, Anda memerlukan beberapa objek berikut:

Untuk mengirim pesan, panggil sendMessage(). Tujuan callback berikut mungkin akan terjadi:

  • Saat pesan berhasil diterima oleh peer, sistem akan memanggil callback onMessageSendSucceeded() di aplikasi yang mengirim.
  • Saat peer menerima pesan, sistem akan memanggil callback onMessageReceived() di aplikasi yang menerima.

Meskipun PeerHandle diperlukan untuk berkomunikasi dengan pembanding, Anda tidak boleh mengandalkannya sebagai ID permanen pembanding. ID dengan tingkat lebih tinggi dapat digunakan oleh aplikasi--disematkan dalam layanan penemuan itu sendiri atau di pesan berikutnya. Anda dapat menyematkan ID di layanan penemuan dengan metode setMatchFilter() atau setServiceSpecificInfo() PublishConfig atau SubscribeConfig. Metode setMatchFilter() memengaruhi penemuan, sedangkan metode setServiceSpecificInfo() tidak memengaruhi penemuan.

Menyematkan ID dalam pesan berarti memodifikasi array byte pesan untuk menyertakan ID (misalnya, sebagai beberapa byte pertama).

Membuat koneksi

Wi-Fi Aware mendukung jaringan klien-server antara dua perangkat Wi-Fi Aware.

Untuk menyiapkan koneksi klien-server:

  1. Menggunakan penemuan Wi-Fi Aware untuk memublikasikan layanan (di server) dan berlangganan ke layanan (di klien).

  2. Setelah pelanggan menemukan penayang, mengirim pesan dari pelanggan ke penayang.

  3. Mulai ServerSocket di perangkat penayang dan tetapkan atau dapatkan portnya:

    Kotlin

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

    Java

    ServerSocket ss = new ServerSocket(0);
    int port = ss.getLocalPort();
  4. Gunakan ConnectivityManager untuk meminta jaringan Wi-Fi Aware di penayang menggunakan WifiAwareNetworkSpecifier, yang menentukan sesi penemuan dan PeerHandle pelanggan, yang Anda dapatkan dari pesan yang dikirimkan oleh pelanggan:

    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. Setelah penayang meminta jaringan, penayang harus mengirim pesan ke pelanggan.

  6. Setelah pelanggan menerima pesan dari penayang, minta jaringan Wi-Fi Aware di pelanggan menggunakan metode yang sama seperti di penayang. Anjuran tidak menentukan porta saat membuat NetworkSpecifier Metode callback yang sesuai akan dipanggil saat koneksi jaringan tersedia, diubah, atau hilang.

  7. Setelah metode onAvailable() dipanggil pada pelanggan, Objek Network tersedia dengan yang dapat Anda buka Socket untuk berkomunikasi dengan ServerSocket pada penayang, tetapi Anda perlu mengetahui Alamat dan port IPv6 ServerSocket. Anda mendapatkannya dari objek NetworkCapabilities yang diberikan dalam callback 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. Setelah selesai dengan koneksi jaringan, panggil unregisterNetworkCallback()

Menentukan jarak peer dan penemuan kemampuan penentuan lokasi

Perangkat dengan lokasi Wi-Fi RTT kemampuan dapat langsung mengukur jarak ke peer dan menggunakan informasi ini untuk membatasi penemuan layanan Wi-Fi Aware.

Wi-Fi RTT API memungkinkan penentuan langsung jarak ke peer Wi-Fi Aware menggunakan alamat MAC atau PeerHandle-nya.

Penemuan Wi-Fi Aware dapat dibatasi hanya untuk menemukan layanan dalam pembatasan wilayah tertentu. Misalnya, Anda dapat menyiapkan pembatasan wilayah yang memungkinkan penemuan perangkat yang memublikasikan layanan "Aware_File_Share_Service_Name" yang tidak lebih dekat dari 3 meter (ditentukan sebagai 3.000 mm) dan tidak lebih dari 10 meter (ditetapkan sebagai 10.000 mm).

Untuk mengaktifkan pembatasan wilayah, baik penayang dan pelanggan harus melakukan tindakan:

  • Penayang harus mengaktifkan penentuan jarak pada layanan yang dipublikasikan menggunakan setRangingEnabled(true).

    Jika penayang tidak mengaktifkan penentuan jarak, maka batas pembatasan wilayah yang ditentukan oleh pelanggan akan diabaikan dan penemuan normal akan dilakukan, mengabaikan jarak.

  • Pelanggan harus menetapkan pembatasan wilayah menggunakan beberapa kombinasi setMinDistanceMm dan setMaxDistanceMm.

    Untuk kedua nilai tersebut, jarak yang tidak ditentukan menunjukkan bahwa tidak ada batas. Hanya menentukan jarak maksimum menunjukkan bahwa jarak minimum adalah 0. Hanya menentukan atribut jarak minimum menyiratkan tidak ada maksimum.

Saat layanan peer ditemukan di dalam pembatasan wilayah, callback onServiceDiscoveredWithinRange akan terpicu, yang memberikan jarak terukur ke peer. Tujuan Wi-Fi RTT API langsung dapat dipanggil seperlunya untuk mengukur jarak dengan di lain waktu.