סקירה כללית של חיפוש נקודות Wi-Fi

אפשר להשתמש ביכולות הסריקה של Wi-Fi שמסופקות על ידי WifiManager API כדי לקבל רשימה של נקודות גישה ל-Wi-Fi שגלויות מהמכשיר.

תהליך הסריקה של Wi-Fi

תהליך הסריקה כולל שלושה שלבים:

  1. רישום מעבד אירוע של שידור עבור SCAN_RESULTS_AVAILABLE_ACTION, שמופעל כשבקשות הסריקה מסתיימות, ומספק את סטטוס ההצלחה או הכישלון שלהן. במכשירים שמותקנת בהם גרסת Android 10 (API ברמה 29) ומעלה, השידור הזה יישלח לכל סריקת Wi-Fi מלאה שמבוצעת במכשיר על ידי הפלטפורמה או אפליקציות אחרות. אפליקציות יכולות להאזין באופן פסיבי לכל סיום הסריקה במכשיר באמצעות השידור, בלי לבצע סריקה משלהן.

  2. מבקשים סריקה באמצעות WifiManager.startScan(). חשוב לבדוק את סטטוס ההחזרה של השיטה, כי יכול להיות שהקריאה תיכשל בגלל אחת מהסיבות הבאות:

    • יכול להיות שהבקשות לסריקה יוגבלו בגלל יותר מדי סריקות בפרק זמן קצר.
    • המכשיר לא פעיל והסריקה מושבתת.
    • החומרה של ה-Wi-Fi מדווחת על כשל בסריקה.
  3. קבלת תוצאות סריקה באמצעות WifiManager.getScanResults(). תוצאות הסריקה שיוחזרו הן התוצאות העדכניות ביותר, ויכול להיות שהן יהיו מסריקה קודמת אם הסריקה הנוכחית לא הושלמה או לא הצליחה. המשמעות היא שאם תפעילו את השיטה הזו לפני שתקבלו שידור SCAN_RESULTS_AVAILABLE_ACTION מוצלח, יכול להיות שתקבלו תוצאות סריקה ישנות יותר.

בדוגמה הבאה אפשר לראות איך מטמיעים את השלבים האלה:

Kotlin

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()
    } else {
      scanFailure()
    }
  }
}

val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  // scan failure handling
  scanFailure()
}

....

private fun scanSuccess() {
  val results = wifiManager.scanResults
  ... use new scan results ...
}

private fun scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  val results = wifiManager.scanResults
  ... potentially use older scan results ...
}

Java

WifiManager wifiManager = (WifiManager)
                   context.getSystemService(Context.WIFI_SERVICE);

BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context c, Intent intent) {
    boolean success = intent.getBooleanExtra(
                       WifiManager.EXTRA_RESULTS_UPDATED, false);
    if (success) {
      scanSuccess();
    } else {
      // scan failure handling
      scanFailure();
    }
  }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(wifiScanReceiver, intentFilter);

boolean success = wifiManager.startScan();
if (!success) {
  // scan failure handling
  scanFailure();
}

....

private void scanSuccess() {
  List<ScanResult> results = wifiManager.getScanResults();
  ... use new scan results ...
}

private void scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  List<ScanResult> results = wifiManager.getScanResults();
  ... potentially use older scan results ...
}

הגבלות

ב-Android 8.0 (רמת API‏ 26) הוצגו הגבלות לגבי הרשאות והתדירות המותרת של סריקות Wi-Fi.

כדי לשפר את ביצועי הרשת, האבטחה וחיי הסוללה, ב-Android 9 (רמת API‏ 28) הוחמרו דרישות ההרשאה והוגבלה עוד יותר התדירות של סריקות Wi-Fi.

הרשאות

Android 8.0 ו-Android 8.1:

כדי לבצע קריאה מוצלחת אל WifiManager.getScanResults() נדרשת אחת מההרשאות הבאות:

אם לאפליקציה שקוראת ל-API אין אף אחת מההרשאות האלה, הקריאה תיכשל עם SecurityException.

לחלופין, במכשירים שמותקנת בהם גרסת Android 8.0‏ (API ברמה 26) ומעלה, אפשר להשתמש ב-CompanionDeviceManager כדי לבצע סריקה של מכשירים נלווים בקרבת מקום בשם האפליקציה, בלי לדרוש את הרשאת המיקום. מידע נוסף על האפשרות הזו זמין במאמר בנושא צימוד של מכשיר משני.

Android 9:

כדי שהקריאה אל WifiManager.startScan() תצליח, צריכים להתקיים כל התנאים הבאים:

Android 10 (רמת API‏ 29) ואילך:

כדי שהקריאה אל WifiManager.startScan() תצליח, צריכים להתקיים כל התנאים הבאים:

  • אם האפליקציה שלך מטרגטת SDK של Android 10 (רמת API‏ 29) ומעלה, לאפליקציה יש הרשאה ACCESS_FINE_LOCATION.
  • אם האפליקציה שלך מטרגטת SDK בגרסה נמוכה מ-Android 10 (רמת API 29), לאפליקציה שלך יש הרשאה ACCESS_COARSE_LOCATION או ACCESS_FINE_LOCATION.
  • לאפליקציה שלך יש הרשאה CHANGE_WIFI_STATE
  • שירותי המיקום מופעלים במכשיר (בקטע הגדרות > מיקום).

כדי להתקשר אל WifiManager.getScanResults() בהצלחה, צריך לוודא שכל התנאים הבאים מתקיימים:

  • אם האפליקציה מטרגטת ל-SDK של Android 10 (רמת API‏ 29) ומעלה, לאפליקציה יש הרשאה מסוג ACCESS_FINE_LOCATION.
  • אם האפליקציה מטרגטת SDK בגרסה נמוכה מ-Android 10 (רמת API‏ 29), לאפליקציה יש הרשאה ACCESS_COARSE_LOCATION או ACCESS_FINE_LOCATION.
  • לאפליקציה שלך יש הרשאה ACCESS_WIFI_STATE.
  • שירותי המיקום מופעלים במכשיר (בקטע הגדרות > מיקום).

אם אפליקציית השיחות לא עומדת בכל הדרישות האלה, השיחה תיכשל עם SecurityException.

ויסות נתונים (throttle)

ההגבלות הבאות חלות על התדירות של הסריקות באמצעות WifiManager.startScan().

Android 8.0 ו-Android 8.1:

כל אפליקציה שפועלת ברקע יכולה לסרוק פעם אחת בפרק זמן של 30 דקות.

Android 9:

כל אפליקציה בחזית יכולה לסרוק ארבע פעמים בפרק זמן של 2 דקות. כך אפשר לבצע מספר רב של סריקות בזמן קצר.

כל האפליקציות ברקע יכולות לסרוק פעם אחת בפרק זמן של 30 דקות.

Android מגרסה 10 ואילך:

חלות אותן מגבלות של הגבלת קצב העברת נתונים מ-Android 9. נוספה אפשרות חדשה למפתחים להשבית את הוויסות לצורך בדיקות מקומיות (בקטע אפשרויות למפתחים > רשת > ויסות סריקה לנקודות Wi-Fi).