Wi-Fi และตัวย่ออื่น ๆ อีกมากมาย วิธีรับข้อมูลเกี่ยวกับโหนด Wi-Fi ในแอปพลิเคชัน Android โดยไม่บวม

วันหนึ่งฉันต้องสแกนเครือข่าย Wi-Fi จากแอปพลิเคชัน Android และรับข้อมูลโดยละเอียดเกี่ยวกับจุดเข้าใช้งาน

ที่นี่เราต้องเผชิญกับความยากลำบากหลายประการ: เอกสาร off.Android คลาสที่อธิบายไว้หลายคลาสเลิกใช้แล้ว (ระดับ API > 26) ซึ่งไม่ได้สะท้อนให้เห็นในนั้น คำอธิบายของบางสิ่งในเอกสารประกอบมีเพียงเล็กน้อย (เช่น ฟิลด์ความสามารถของคลาส ผลการสแกน ในขณะที่เขียนแทบจะไม่มีอะไรอธิบายเลยแม้ว่าจะมีข้อมูลสำคัญมากมายก็ตาม) ปัญหาที่สามอาจอยู่ที่ว่าเมื่อคุณเข้าใกล้ Wi-Fi เป็นครั้งแรก นอกเหนือจากการอ่านทฤษฎีและการตั้งค่าเราเตอร์ผ่าน localhost คุณจะต้องจัดการกับตัวย่อจำนวนหนึ่งที่ดูเหมือนเข้าใจได้ทีละตัว แต่อาจไม่ชัดเจนว่าจะเชื่อมโยงและจัดโครงสร้างอย่างไร (การตัดสินเป็นเรื่องส่วนตัวและขึ้นอยู่กับประสบการณ์ก่อนหน้านี้)

บทความนี้อธิบายวิธีรับข้อมูลที่ครอบคลุมเกี่ยวกับสภาพแวดล้อม Wi-Fi จากโค้ด Android ที่ไม่มี NDK, การแฮ็ก แต่ใช้เฉพาะ Android API และทำความเข้าใจวิธีตีความ

อย่ารอช้าและเริ่มเขียนโค้ดได้เลย

1. สร้างโครงการ

หมายเหตุนี้มีไว้สำหรับผู้ที่สร้างโครงการ Android มากกว่าหนึ่งครั้ง ดังนั้นเราจึงละเว้นรายละเอียดของรายการนี้ โค้ดด้านล่างจะแสดงเป็น Kotlin, minSdkVersion=23

2. สิทธิ์การเข้าถึง

หากต้องการทำงานกับ Wi-Fi จากแอปพลิเคชัน คุณจะต้องได้รับอนุญาตหลายประการจากผู้ใช้ ตาม เอกสารเพื่อสแกนเครือข่ายบนอุปกรณ์ที่มีระบบปฏิบัติการเวอร์ชันหลัง 8.0 นอกเหนือจากการเข้าถึงเพื่อดูสถานะของสภาพแวดล้อมเครือข่ายแล้ว คุณต้องเข้าถึงเพื่อเปลี่ยนสถานะของโมดูล Wi-Fi ของอุปกรณ์ หรือเข้าถึงพิกัด (โดยประมาณ หรือแน่นอน) ตั้งแต่เวอร์ชัน 9.0 เป็นต้นไป คุณต้องแจ้งให้ผู้ใช้ทำทั้งสองอย่าง และขอให้ผู้ใช้เปิดบริการระบุตำแหน่งอย่างชัดเจนด้วย อย่าลืมอธิบายให้ผู้ใช้ฟังอย่างกล้าหาญว่านี่คือความตั้งใจของ Google และไม่ใช่ความปรารถนาของเราที่จะสอดแนมเขา :)

ดังนั้นใน AndroidManifest.xml เราจะเพิ่ม:

    <uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>

และในโค้ดที่มีลิงก์ไปยังกิจกรรมปัจจุบัน:

import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat

....

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
            makeEnableLocationServices(activity.applicationContext)
        } else {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
        }

    /* включает экран включения службы по определению местоположения */
    fun makeEnableLocationServices(context: Context) {
        // TODO: перед вызовом этой функции надо рассказать пользователю, зачем Вам доступ к местоположению
        val lm: LocationManager =
            context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!gpsEnabled && !networkEnabled) {
            context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }

3. สร้าง BroadcastReceiver และสมัครรับกิจกรรมการอัปเดตข้อมูลเกี่ยวกับการสแกนสภาพแวดล้อมเครือข่าย Wi-Fi

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } 
  }
}

val intentFilter = IntentFilter()
/* подписываемся на сообщения о получении новых результатов сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  /* что-то не получилось при запуске сканирования, проверьте выданые разрешения */
}

....

private fun scanSuccess() {
 /* вот они, результаты сканирования */
  val results: List<ScanResult> = wifiManager.scanResults
}

เมธอด WiFiManager.startScan ในเอกสารประกอบถูกทำเครื่องหมายว่าเลิกใช้แล้วตั้งแต่ API เวอร์ชัน 28 แต่ปิดอยู่ ให้คำแนะนำ แนะนำให้ใช้มัน

โดยรวมแล้วเราได้รับรายการวัตถุ ผลการสแกน.

4. ดูที่ ScanResult และทำความเข้าใจข้อกำหนด

ลองดูที่บางฟิลด์ของคลาสนี้และอธิบายว่าฟิลด์เหล่านี้หมายถึงอะไร:

SSID — Service Set Identifier คือชื่อของเครือข่าย

BSSID – ตัวระบุชุดบริการพื้นฐาน – ที่อยู่ MAC ของอะแดปเตอร์เครือข่าย (จุด Wi-Fi)

ระดับ — ตัวบ่งชี้ความแรงของสัญญาณที่ได้รับ [dBm (dBm รัสเซีย) — เดซิเบล, กำลังอ้างอิง 1 mW.] — ตัวบ่งชี้ความแรงของสัญญาณที่ได้รับ รับค่าตั้งแต่ 0 ถึง -100 ยิ่งห่างจาก 0 มากเท่าใด สัญญาณจะสูญเสียไปมากตามเส้นทางจากจุด Wi-Fi ไปยังอุปกรณ์ของคุณ สามารถดูรายละเอียดเพิ่มเติมได้ที่ เช่น ที่ วิกิพีเดีย. ที่นี่ฉันจะบอกคุณว่าการใช้คลาส Android WifiManager คุณสามารถปรับระดับสัญญาณในระดับตั้งแต่ดีเยี่ยมไปจนถึงแย่มากได้ในขั้นตอนที่คุณเลือก:

        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val numberOfLevels = 5
        val level = WifiManager.calculateSignalLevel(level, numberOfLevels)

ความถี่ — ความถี่การทำงานของจุด Wi-Fi [Hz] นอกจากความถี่แล้ว คุณอาจสนใจช่องที่เรียกว่า แต่ละจุดมีความบริสุทธิ์ในการทำงานของตัวเอง ในขณะที่เขียน ช่วง Wi-Fi ที่ได้รับความนิยมมากที่สุดคือ 2.4 GHz แต่เพื่อให้แม่นยำยิ่งขึ้น จุดนั้นจะส่งข้อมูลไปยังโทรศัพท์ของคุณด้วยความถี่ตัวเลขที่ใกล้เคียงกับความถี่ที่มีชื่อ จำนวนช่องและความถี่ที่สอดคล้องกัน ได้มาตรฐาน. ทำเช่นนี้เพื่อให้จุดใกล้เคียงทำงานที่ความถี่ต่างกัน จึงไม่รบกวนซึ่งกันและกัน และไม่ลดความเร็วและคุณภาพของการส่งสัญญาณร่วมกัน ในกรณีนี้ จุดต่างๆ ไม่ได้ทำงานที่ความถี่เดียว แต่ผ่านช่วงความถี่ (พารามิเตอร์ ความกว้างของช่อง) เรียกว่าความกว้างของช่อง นั่นคือจุดที่ทำงานในช่องที่อยู่ติดกัน (และไม่เพียงแต่ติดกันเท่านั้น แต่ยังรวมถึง 3 ช่องจากตัวมันเองด้วย) จะรบกวนซึ่งกันและกัน คุณอาจพบว่าโค้ดง่ายๆ นี้มีประโยชน์ ซึ่งช่วยให้คุณคำนวณหมายเลขช่องสัญญาณจากค่าความถี่สำหรับจุดที่มีความถี่ 2.4 และ 5 Ghz:


    /* по частоте определяем номер канала */
    val channel: Int
        get() {
            return if (frequency in 2412..2484) {
                (frequency - 2412) / 5 + 1
            } else if (frequency in 5170..5825) {
                (frequency - 5170) / 5 + 34
            } else {
                -1
            }
        }

ความสามารถในการ - สาขาการวิเคราะห์ที่น่าสนใจที่สุด ซึ่งต้องใช้เวลามาก ที่นี่ "ความสามารถ" ของจุดเขียนอยู่ในบรรทัด ในกรณีนี้ คุณไม่จำเป็นต้องค้นหารายละเอียดของการตีความสตริงในเอกสารประกอบ นี่คือตัวอย่างบางส่วนของสิ่งที่อาจอยู่ในบรรทัดนี้:

[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]

5. ทำความเข้าใจคำย่อและความสามารถในการแยกวิเคราะห์

เป็นที่น่าสังเกตว่าคลาสของแพ็คเกจ android.net.wifi.* นั้นถูกใช้ภายใต้ประทุนโดยยูทิลิตี้ Linux wpa_supplicant และผลลัพธ์ที่ได้ในฟิลด์ความสามารถจะเป็นสำเนาของฟิลด์แฟล็กเมื่อทำการสแกน

เราจะดำเนินการอย่างสม่ำเสมอ ขั้นแรกให้พิจารณาผลลัพธ์ของรูปแบบที่องค์ประกอบภายในวงเล็บคั่นด้วยเครื่องหมาย “-“:

[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]

ความหมายแรกอธิบายสิ่งที่เรียกว่า วิธีการรับรองความถูกต้อง. นั่นคือลำดับการดำเนินการที่อุปกรณ์และจุดเชื่อมต่อต้องดำเนินการเพื่อให้จุดเชื่อมต่ออนุญาตให้ใช้ตัวเองได้ และวิธีการเข้ารหัสเพย์โหลด ในขณะที่เขียนบทความนี้ ตัวเลือกที่พบบ่อยที่สุดคือ WPA และ WPA2 ซึ่งแต่ละอุปกรณ์เชื่อมต่อโดยตรงหรือผ่านสิ่งที่เรียกว่า เซิร์ฟเวอร์ RADIUS (WPA-Enterprice) มอบรหัสผ่านผ่านช่องทางที่เข้ารหัส เป็นไปได้มากว่าจุดเข้าใช้งานในบ้านของคุณจะมีการเชื่อมต่อตามรูปแบบนี้ ความแตกต่างระหว่างเวอร์ชันที่สองและเวอร์ชันแรกคือมีการเข้ารหัสที่แข็งแกร่งกว่า: AES เทียบกับ TKIP ที่ไม่ปลอดภัย WPA3 ซึ่งมีความซับซ้อนและล้ำหน้ากว่า ก็กำลังทยอยเปิดตัวเช่นกัน ตามทฤษฎีแล้ว อาจมีตัวเลือกสำหรับโซลูชันราคาป้อน CCKM (การจัดการคีย์แบบรวมศูนย์ของ Cisco) แต่ฉันไม่เคยเจอมันเลย

จุดเชื่อมต่ออาจถูกกำหนดค่าให้ตรวจสอบสิทธิ์ด้วยที่อยู่ MAC หรือหากจุดเข้าใช้งานให้ข้อมูลโดยใช้อัลกอริธึม WEP ที่ล้าสมัย ก็แสดงว่าไม่มีการตรวจสอบสิทธิ์จริง ๆ (คีย์ลับในที่นี้คือคีย์เข้ารหัส) เราจัดประเภทตัวเลือกเช่น OTHER
นอกจากนี้ยังมีวิธีการที่ได้รับความนิยมใน Wi-Fi สาธารณะพร้อม Captive Portal Detection ที่ซ่อนอยู่ - คำขอตรวจสอบสิทธิ์ผ่านเบราว์เซอร์ จุดเชื่อมต่อดังกล่าวปรากฏต่อเครื่องสแกนว่าเปิดอยู่ (ซึ่งมาจากมุมมองของการเชื่อมต่อทางกายภาพ) ดังนั้นเราจึงจัดประเภทเป็น OPEN

ค่าที่สองสามารถแสดงเป็น อัลกอริธึมการจัดการคีย์. นี่เป็นพารามิเตอร์ของวิธีการตรวจสอบสิทธิ์ที่อธิบายไว้ข้างต้น พูดถึงวิธีการแลกเปลี่ยนคีย์เข้ารหัสอย่างชัดเจน พิจารณาตัวเลือกที่เป็นไปได้ EAP - ใช้ใน WPA-Enterprice ที่กล่าวถึง ใช้ฐานข้อมูลเพื่อตรวจสอบข้อมูลการตรวจสอบสิทธิ์ที่ป้อน SAE - ใช้ใน WPA3 ขั้นสูง ทนทานต่อแรงดุร้ายได้ดีกว่า PSK - ตัวเลือกที่พบบ่อยที่สุดเกี่ยวข้องกับการป้อนรหัสผ่านและส่งในรูปแบบที่เข้ารหัส IEEE8021X - ตามมาตรฐานสากล (แตกต่างจากที่รองรับโดยตระกูล WPA) OWE (การเข้ารหัสไร้สายแบบฉวยโอกาส) เป็นส่วนขยายของมาตรฐาน IEEE 802.11 สำหรับจุดที่เราจัดประเภทเป็นเปิด OWE รับประกันความปลอดภัยของข้อมูลที่ส่งผ่านเครือข่ายที่ไม่ปลอดภัยด้วยการเข้ารหัส ตัวเลือกยังเป็นไปได้เมื่อไม่มีคีย์การเข้าถึง ให้เรียกตัวเลือกนี้ว่า NONE

พารามิเตอร์ที่สามคือสิ่งที่เรียกว่า แผนการเข้ารหัส — วิธีการใช้รหัสเพื่อปกป้องข้อมูลที่ส่ง มาแสดงรายการตัวเลือกกัน WEP - ใช้รหัสสตรีม RC4 คีย์ลับคือคีย์เข้ารหัสซึ่งถือว่าไม่เป็นที่ยอมรับในโลกของการเข้ารหัสสมัยใหม่ TKIP - ใช้ใน WPA, CKIP - ใน WPA2 TKIP+CKIP - สามารถระบุได้ในจุดที่สามารถใช้ WPA และ WPA2 เพื่อความเข้ากันได้แบบย้อนหลัง

แทนที่จะเป็นองค์ประกอบสามประการ คุณจะพบเครื่องหมาย WEP โดดเดี่ยว:

[WEP]

ดังที่เราได้กล่าวไว้ข้างต้น นี่ก็เพียงพอแล้วที่จะไม่ระบุอัลกอริทึมสำหรับการใช้คีย์ที่ไม่มีอยู่ และวิธีการเข้ารหัสซึ่งเป็นค่าเริ่มต้นเดียวกัน

พิจารณาวงเล็บนี้:

[ESS]

มัน โหมดการทำงานของ Wi-Fi หรือ โทโพโลยีเครือข่าย Wi-Fi. คุณอาจพบโหมด BSS (ชุดบริการพื้นฐาน) - เมื่อมีจุดเข้าใช้งานหนึ่งจุดซึ่งอุปกรณ์ที่เชื่อมต่อสื่อสารกัน สามารถพบได้บนเครือข่ายท้องถิ่น ตามกฎแล้ว จุดเข้าใช้งานจำเป็นในการเชื่อมต่ออุปกรณ์จากเครือข่ายท้องถิ่นที่แตกต่างกัน ดังนั้นจึงเป็นส่วนหนึ่งของชุดบริการเพิ่มเติม - ESS ประเภท IBSS (ชุดบริการพื้นฐานอิสระ) ระบุว่าอุปกรณ์เป็นส่วนหนึ่งของเครือข่าย Peer-to-Peer

คุณอาจเห็นธง WPS:

[WPS]

WPS (การตั้งค่าการป้องกัน Wi-Fi) เป็นโปรโตคอลสำหรับการเริ่มต้นเครือข่าย Wi-Fi แบบกึ่งอัตโนมัติ ในการเริ่มต้น ผู้ใช้จะต้องป้อนรหัสผ่าน 8 ตัวอักษรหรือกดปุ่มบนเราเตอร์ หากจุดเข้าใช้งานของคุณเป็นประเภทแรกและช่องทำเครื่องหมายนี้ปรากฏถัดจากชื่อจุดเข้าใช้งานของคุณ ขอแนะนำอย่างยิ่งให้ไปที่แผงผู้ดูแลระบบและปิดใช้งานการเข้าถึง WPS ความจริงก็คือบ่อยครั้งที่ PIN 8 หลักสามารถค้นหาได้จากที่อยู่ MAC หรือสามารถแยกออกได้ในเวลาอันใกล้ซึ่งใครบางคนสามารถใช้ประโยชน์ได้อย่างไม่สุจริต

6. สร้างแบบจำลองและฟังก์ชันการแยกวิเคราะห์

จากสิ่งที่เราพบข้างต้น เราจะอธิบายสิ่งที่เกิดขึ้นโดยใช้คลาสข้อมูล:

/* схема аутентификации */
enum class AuthMethod {
    WPA3,
    WPA2,
    WPA, // Wi-Fi Protected Access
    OTHER, // включает в себя Shared Key Authentication и др. использующие mac-address-based и WEP
    CCKM, // Cisco
    OPEN // Open Authentication. Может быть со скрытым Captive Portal Detection - запрос аутентификации через браузер
}

/* алгоритм ввода ключей */
enum class KeyManagementAlgorithm {
    IEEE8021X, // по стандарту
    EAP, // Extensible Authentication Protocol, расширяемый протокол аутентификации
    PSK, // Pre-Shared Key — каждый узел вводит пароль для доступа к сети
    WEP, // в WEP пароль является ключом шифрования (No auth key)
    SAE, // Simultaneous Authentication of Equals - может быть в WPA3
    OWE, // Opportunistic Wireless Encryption - в роутерах новых поколений, публичных сетях типа OPEN
    NONE // может быть без шифрования в OPEN, OTHER
}

/* метод шифрования */
enum class CipherMethod {
    WEP, // Wired Equivalent Privacy, Аналог шифрования трафика в проводных сетях
    TKIP, // Temporal Key Integrity Protocol
    CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
    // протокол блочного шифрования с кодом аутентичности сообщения и режимом сцепления блоков и счетчика
    // на основе AES
    NONE // может быть без шифрования в OPEN, OTHER
}

/* набор методов шифрования и протоколов, по которым может работать точка */
data class Capability(
    var authScheme: AuthMethod? = null,
    var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
    var cipherMethod: CipherMethod? = null
)

/* Режим работы WiFi (или топология сетей WiFi) */
enum class TopologyMode {
    IBSS, // Эпизодическая сеть (Ad-Hoc или IBSS – Independent Basic Service Set).
    BSS, // Основная зона обслуживания Basic Service Set (BSS) или Infrastructure Mode.
    ESS // Расширенная зона обслуживания ESS – Extended Service Set.
}

ตอนนี้เรามาเขียนฟังก์ชันที่จะแยกวิเคราะห์ฟิลด์ความสามารถ:


private fun parseCapabilities(capabilitiesString: String): List < Capability > {
    val capabilities: List < Capability > = capabilitiesString
        .splitByBrackets()
        .filter {
            !it.isTopology() && !it.isWps()
        }
        .flatMap {
            parseCapability(it)
        }
    return
        if (!capabilities.isEmpty()) {
            capabilities
        } else {
            listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
        }
}

private fun parseCapability(part: String): List < Capability > {
    if (part.contains("WEP")) {
        return listOf(Capability(
            AuthMethod.OTHER,
            KeyManagementAlgorithm.WEP,
            CipherMethod.WEP
        ))
    }

    val authScheme = when {
        part.contains("WPA3") - > AuthMethod.WPA3
        part.contains("WPA2") - > AuthMethod.WPA2
        part.contains("WPA") - > AuthMethod.WPA
        else - > null
    }

    val keyManagementAlgorithm = when {
        part.contains("OWE") - > KeyManagementAlgorithm.OWE
        part.contains("SAE") - > KeyManagementAlgorithm.SAE
        part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
        part.contains("EAP") - > KeyManagementAlgorithm.EAP
        part.contains("PSK") - > KeyManagementAlgorithm.PSK
        else - > null
    }

    val capabilities = ArrayList < Capability > ()
    if (part.contains("TKIP") || part.contains("CCMP")) {
        if (part.contains("TKIP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.TKIP
            ))
        }
        if (part.contains("CCMP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.CCMP
            ))
        }
    } else if (authScheme != null || keyManagementAlgorithm != null) {
        capabilities.add(Capability(
            authScheme ? : AuthMethod.OPEN,
            keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
            CipherMethod.NONE
        ))
    }

    return capabilities
}

private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
    return capabilitiesString
        .splitByBrackets()
        .mapNotNull {
            when {
                it.contains("ESS") - > TopologyMode.ESS
                it.contains("BSS") - > TopologyMode.BSS
                it.contains("IBSS") - > TopologyMode.IBSS
                else - > null
            }
        }
        .firstOrNull()
}

private fun parseWPSAvailable(capabilitiesString: String): Boolean {
    return capabilitiesString
        .splitByBrackets()
        .any {
            it.isWps()
        }
}

private fun String.splitByBrackets(): List < String > {
    val m = Pattern.compile("[(.*?)]").matcher(this)
    val parts = ArrayList < String > ()
    while (m.find()) {
        parts.add(m.group().replace("[", "").replace("]", ""))
    }
    return parts
}

private fun String.isTopology(): Boolean {
    return TopologyMode.values().any {
        this == it.name
    }
}

private fun String.isWps(): Boolean {
    return this == "WPS"
}

8. ดูผลลัพธ์

ฉันจะสแกนเครือข่ายและแสดงสิ่งที่ฉันพบ แสดงให้เห็นว่าเป็นผลลัพธ์ของเอาต์พุตอย่างง่ายผ่าน Log.d:

Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true

ปัญหาการเชื่อมต่อกับเครือข่ายจากรหัสแอปพลิเคชันยังคงไม่ได้รับการตรวจสอบ ฉันจะบอกว่าเพื่อที่จะอ่านรหัสผ่านที่บันทึกไว้จากระบบปฏิบัติการของอุปกรณ์มือถือคุณต้องมีสิทธิ์รูทและความเต็มใจที่จะค้นหาผ่านระบบไฟล์เพื่ออ่าน wpa_supplicant.conf หากตรรกะของแอปพลิเคชันจำเป็นต้องป้อนรหัสผ่านจากภายนอก การเชื่อมต่อสามารถทำได้ผ่านคลาส android.net.wifi.WifiManager.

ขอบคุณ เอกอร์ โปโนมาเรฟ เพื่อการเพิ่มเติมอันทรงคุณค่า

หากคุณคิดว่าจำเป็นต้องเพิ่มหรือแก้ไขบางสิ่ง โปรดเขียนความคิดเห็นไว้ :)

ที่มา: will.com

เพิ่มความคิดเห็น