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

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

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

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

  1. רישום של מעבד אירועים להעברה (broadcast) עבור 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() נדרשת אחת מההרשאות הבאות:

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

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

Android 9:

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

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

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

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

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

  • אם האפליקציה שלכם מטרגטת ל-Android 10 (רמת API 29) SDK ואילך, היא תקבל את ההרשאה 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. יש אפשרות חדשה למפתחים להשבית את הגבלת הקצב לצורך בדיקה מקומית (בקטע אפשרויות למפתחים > Networking (רשתות) > Wi-Fi scan throttling (ויסות סריקה לנקודות Wi-Fi)).