סקירה כללית של חיפוש נקודות 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(). תוצאות הסריקה שמוחזרות הן התוצאות המעודכנות ביותר, שיכולות להיות מסריקה קודמת אם הסריקה הנוכחית לא הושלמה או לא הצליחה. כלומר, יכול להיות שיתקבלו תוצאות סריקה ישנות יותר אם מפעילים את ה-method הזו לפני שמקבלים שידור 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 (רמת API‏ 26) ו-Android 8.1 (רמת API‏ 27):

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

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

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

‫Android 9 (רמת API‏ 28):

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

  • לאפליקציה יש את ההרשאה ACCESS_FINE_LOCATION או ACCESS_COARSE_LOCATION.
  • לאפליקציה שלך יש את ההרשאה CHANGE_WIFI_STATE.
  • שירותי המיקום מופעלים במכשיר (בקטע הגדרות > מיקום).

‫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:

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

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

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

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