אפשר להשתמש בפונקציות של מיקום Wi-Fi שמספק Wi-Fi RTT (Round-Trip-Time) API כדי למדוד את המרחק מנקודות גישה בקרבת מקום עם תמיכה ב-RTT וממכשירים אחרים עם תמיכה ב-Wi-Fi Aware.
אם מודדים את המרחק לשלוש נקודות גישה או יותר, אפשר להשתמש אלגוריתם רב-שלבי להערכת מיקום המכשיר המתאים ביותר מדידות. בדרך כלל התוצאה מדויקת בטווח של 1-2 מטר.
בעזרת הדיוק הזה אפשר לפתח שירותים מבוססי-מיקום ברמת פירוט גבוהה, כמו ניווט בתוך מבנים, שליטה קולית ללא צורך בהבהרה (לדוגמה, "הפעלת הנורה הזו") ומידע מבוסס-מיקום (לדוגמה, "האם יש מבצעים מיוחדים על המוצר הזה?").
המכשיר ששלח את הבקשה לא צריך להתחבר לנקודות הגישה כדי לבצע מדידה מרחק באמצעות Wi-Fi RTT. כדי לשמור על הפרטיות, רק המכשיר ששלח את הבקשה יכול כדי לקבוע את המרחק לנקודת הגישה, נקודות הגישה מידע זה. אין הגבלה על פעולות RTT ב-Wi-Fi באפליקציות שפועלות בחזית, אבל מוגבלת לאפליקציות ברקע.
התכונות של Fine-Time-Measurement (FTM) ו-Wi-Fi RTT שצוין בתקן IEEE 802.11-2016. נדרש זמן מדויק לשימוש ב-RTT ב-Wi-Fi מדידה שמסופקת על ידי FTM כי היא מחשבת את המרחק בין מכשירים על ידי מדידת הזמן שלוקח לחבילה לבצע טיסה הלוך ושוב בין ולהכפיל את הזמן הזה במהירות האור.
ב-Android 15 (רמת API 35) נוספה תמיכה ב-IEEE 802.11az שאינו מבוסס-טריגרים (NTB).
הבדלים בהטמעה בהתאם לגרסת Android
התחלנו להשתמש ב-RTT ב-Wi-Fi ב-Android 9 (רמת API 28). כשמשתמשים בפרוטוקול הזה כדי לקבוע את מיקום המכשיר באמצעות ריבוי שורות עם מכשירים פועלים ב-Android 9, נדרשת גישה למיקומים של נקודות גישה שהוגדרו מראש (AP) בתוך האפליקציה. אתם מחליטים איך לאחסן ולאחזר את הנתונים האלה.
במכשירים עם Android מגרסה 10 ואילך (רמת API 29 ואילך), נתוני המיקום של נקודת הגישה יכולים להיות מיוצגים כאובייקטים מסוג ResponderLocation
, שכוללים קו רוחב, קו אורך וגובה. בנקודות Wi-Fi RTT שתומכות בנתוני LCI/LCR (מידע על הגדרת המיקום/דוח על מיקום ציבורי), הפרוטוקול יחזיר אובייקט ResponderLocation
במהלך תהליך הטווח.
התכונה הזו מאפשרת לאפליקציות לשלוח שאילתות לנקודות הגישה כדי לבקש מהן את המיקום שלהן ישירות, במקום לאחסן את המידע הזה מראש. כך האפליקציה יכולה למצוא נקודות גישה ולקבוע את המיקומים שלהן גם אם הן לא היו ידועות קודם, למשל כשמשתמש נכנס לבניין חדש.
תמיכה בטווח IEEE 802.11az NTB זמינה במכשירים עם מערכת Android 15
(רמת API 35) ומעלה. המשמעות היא שאם המכשיר תומך ב-IEEE 802.11az
מצב הפעלה NTB (מצוין על ידי
WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR
),
האפליקציה שלך יכולה למצוא הן נקודות גישה בתקן IEEE 802.11mc ו-IEEE 802.11az באמצעות
בקשת טווח. הרחבנו את ממשק ה-API של RangingResult
כדי לספק מידע על הערך המינימלי והמקסימלי שאפשר להשתמש בו במרווח בין מדידות הטווח, כך שהמרווח המדויק יהיה בשליטת האפליקציה.
הדרישות
- החומרה של המכשיר שמבצע את בקשת הטווח חייבת להטמיע את תקן FTM 802.11-2016 או תקן 802.11az (טווח שמבוסס על לא-טריגר).
- במכשיר שמגיש את בקשת הטווח צריכה לפעול מערכת Android מגרסה 9 (רמת API 28) ואילך. טווח מבוסס IEEE 802.11az לא מבוסס על טריגרים מופעל במכשירים מערכת Android בגרסה 15 (רמת API 35) ואילך.
- במכשיר שמגיש את בקשת המדידה צריכים להיות מופעלים שירותי המיקום וחיפוש רשתות Wi-Fi (בקטע הגדרות > מיקום).
- אם האפליקציה שמבצעת את הטווחים של הבקשות לטירגוט
מערכת Android 13 (רמת API 33) ואילך, חייבת להיות בה גרסת
NEARBY_WIFI_DEVICES
הרשאה. אם אפליקציה כזו מיועדת לגרסה קודמת של Android, היא צריכה להיות בעלת ההרשאהACCESS_FINE_LOCATION
במקום זאת. - האפליקציה צריכה לשלוח שאילתה על טווח נקודות הגישה בזמן שהיא גלויה או נמצאת בתוך האפליקציה שירות שפועל בחזית. האפליקציה לא יכולה לגשת לפרטי המיקום דרך רקע.
- נקודת הגישה חייבת ליישם את תקן IEEE 802.11-2016 FTM או את תקן IEEE 802.11az (מדידה לטווח ללא טריגר).
הגדרה
כדי להגדיר באפליקציה שימוש ב-RTT ב-Wi-Fi, מבצעים את השלבים הבאים.
1. בקשת הרשאות
צריך לבקש את ההרשאות הבאות במניפסט של האפליקציה:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 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" />
ההרשאות NEARBY_WIFI_DEVICES
ו-ACCESS_FINE_LOCATION
מסוכנות
עליך לבקש אותן בזמן הריצה בכל פעם שהמשתמש רוצה
ביצוע פעולת סריקת RTT. האפליקציה שלך תצטרך לבקש מהמשתמש
אם ההרשאה עדיין לא ניתנה. מידע נוסף על הרשאות בסביבת זמן הריצה זמין במאמר בקשה להרשאות לאפליקציה.
2. בדיקה אם המכשיר תומך ב-Wi-Fi RTT
כדי לבדוק אם המכשיר תומך ב-RTT ב-Wi-Fi, משתמשים ב-API PackageManager
:
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. איך בודקים אם התכונה RTT ב-Wi-Fi זמינה
יכול להיות שיש במכשיר RTT Wi-Fi, אבל הוא לא יהיה זמין כי המשתמש
השבית את ה-Wi-Fi. בהתאם ליכולות החומרה והקושחה שלהם, יכול להיות שחלק מהמכשירים לא יתמכו ב-Wi-Fi RTT אם נעשה בהם שימוש ב-SoftAP או בקישור. כדי לבדוק אם אפשר להשתמש ב-RTT ב-Wi-Fi, צריך להתקשר למספר isAvailable()
.
הזמינות של Wi-Fi RTT עשויה להשתנות בכל שלב. האפליקציה שלך צריכה לרשום
BroadcastReceiver
לקבל
ACTION_WIFI_RTT_STATE_CHANGED
,
שנשלח כשהזמינות משתנה. כשהאפליקציה מקבלת את כוונה השידור, היא צריכה לבדוק את סטטוס הזמינות הנוכחי ולשנות את ההתנהגות שלה בהתאם.
לדוגמה:
Kotlin
val filter = IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED) val myReceiver = object: BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (wifiRttManager.isAvailable) { … } else { … } } } context.registerReceiver(myReceiver, filter)
Java
IntentFilter filter = new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED); BroadcastReceiver myReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (wifiRttManager.isAvailable()) { … } else { … } } }; context.registerReceiver(myReceiver, filter);
למידע נוסף, ראו שידורים.
יצירת בקשת טווח
בקשה בטווח
(RangingRequest
) נוצר
באמצעות ציון רשימה של נקודות AP או נקודות להשוואה עם Wi-Fi Aware שאליהן
נדרש. אפשר לציין כמה נקודות גישה או רשתות Wi-Fi Aware במסגרת
בקשה בטווח יחיד; המערכת מודדת ומחזירה את המרחקים בין כל המכשירים.
לדוגמה, בקשה יכולה להשתמש
addAccessPoint()
כדי לציין נקודת גישה שאליה מודדים את המרחק:
Kotlin
val req: RangingRequest = RangingRequest.Builder().run { addAccessPoint(ap1ScanResult) addAccessPoint(ap2ScanResult) build() }
Java
RangingRequest.Builder builder = new RangingRequest.Builder(); builder.addAccessPoint(ap1ScanResult); builder.addAccessPoint(ap2ScanResult); RangingRequest req = builder.build();
נקודת הגישה מזוהה באמצעות האובייקט ScanResult
, שאפשר לקבל על ידי קריאה ל-WifiManager.getScanResults()
.
אפשר להשתמש ב-addAccessPoints(List<ScanResult>)
כדי להוסיף כמה נקודות גישה בבת אחת.
אובייקטים מסוג ScanResult
יכולים להכיל נקודות AP נתמכות עם תמיכה ב-IEEE 802.11mc (is80211mcResponder()
) וב-IEEE 802.11az לטווח מבוסס-טריגר (is80211azNtbResponder()
). מכשירים שתומכים בטווח IEEE 802.11az NTB מבצעים או 802.11mc
802.11az בהתאם ליכולת של ה-AP, וברירת המחדל היא 802.11az כאשר
סוכנות AP תומכת בשתיהן. במכשירים שלא תומכים ב-IEEE 802.11az, כל פעולות הטווח מתבצעות באמצעות הפרוטוקול IEEE 802.11mc.
באופן דומה, בקשת מדידת מרחק יכולה להוסיף עמית Wi-Fi Aware באמצעות כתובת ה-MAC שלו או באמצעות PeerHandle
, באמצעות השיטות addWifiAwarePeer(MacAddress peer)
ו-addWifiAwarePeer(PeerHandle peer)
, בהתאמה. מידע נוסף על זיהוי עמיתים ב-Wi-Fi Aware זמין במסמכי העזרה של Wi-Fi Aware.
טווח בקשות
אפליקציה מנפיקה בקשה טווח באמצעות
WifiRttManager.startRanging()
ולציין את הפרטים הבאים:
RangingRequest
כדי לציין
פעולה, Executor
כדי לציין
את ההקשר של הקריאה החוזרת
RangingResultCallback
כדי לקבל את התוצאות.
לדוגמה:
Kotlin
val mgr = context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE) as WifiRttManager val request: RangingRequest = myRequest mgr.startRanging(request, executor, object : RangingResultCallback() { override fun onRangingResults(results: List<RangingResult>) { … } override fun onRangingFailure(code: Int) { … } })
Java
WifiRttManager mgr = (WifiRttManager) Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE); RangingRequest request ...; mgr.startRanging(request, executor, new RangingResultCallback() { @Override public void onRangingFailure(int code) { … } @Override public void onRangingResults(List<RangingResult> results) { … } });
פעולת הטווח מתבצעת באופן אסינכרוני, ותוצאות הטווח
שהוחזרה באחד מהקריאות החוזרות של
RangingResultCallback
- אם כל פעולת הטווח נכשלת, הפרמטר
onRangingFailure
הקריאה החוזרת מופעלת באמצעות קוד סטטוס שמתואר בשדהRangingResultCallback
כשל כזה עשוי להתרחש אם השירות לא יכול לבצע פעולת טווח באותו זמן - לדוגמה, בגלל שה-Wi-Fi מושבת, כי האפליקציה ביקש יותר מדי פעולות טווח וחסומות, או בגלל בעיית הרשאה. - כשפעולת הטווח מסתיימת, מתבצעת הפעלה חוזרת של
onRangingResults
עם רשימת תוצאות שתואמת לרשימת הבקשות – תוצאה אחת לכל בקשה. סדר התוצאות לא תואם בהכרח לסדר הבקשות. חשוב לשים לב שפעולת טווח עשויה הושלם, אך כל תוצאה עדיין עשויה להעיד על כשל מדידה.
פירוש תוצאות הטווח
כל אחת מהתוצאות שמוחזרות על ידי הפונקציה הלא סטטית onRangingResults
מוגדרת באמצעות אובייקט RangingResult
. בכל בקשה, מבצעים את הפעולות הבאות.
1. זיהוי הבקשה
לזהות את הבקשה על סמך המידע שסופק כשיצרתם את
RangingRequest
בדרך כלל כתובת MAC שצוינה בScanResult
שמזוהה גישה
לנקודה. אפשר לקבל את כתובת ה-MAC מתוצאת הטווח באמצעות השיטה getMacAddress()
.
רשימת התוצאות עשויה להיות בסדר שונה מזה של האפליקציות להשוואה (גישה נקודות) שצוינו בבקשת הטווח, לכן עליך להשתמש בכתובת MAC כדי אנחנו מזהים את האפליקציה להשוואה, לא את סדר התוצאות.
2. בודקים אם כל מדידה הצליחה
כדי לבדוק אם המדידה בוצעה בהצלחה, משתמשים בשיטה getStatus()
. כל ערך מלבד
STATUS_SUCCESS
מציין כישלון. כשל פירושו שכל שאר השדות בתוצאה הזו (למעט מזהה הבקשה שלמעלה) לא תקינים, וששיטה get*
המתאימה תיכשל עם חריגה מסוג IllegalStateException
.
3. קבלת תוצאות לכל מדידה מוצלחת
לכל מדידה מוצלחת (RangingResult
), אפשר לאחזר תוצאה
ערכים עם ה-methods get
המתאימות:
מרחק, מ"מ וסטיית תקן של המדידה:
RSSI של המנות שמשמשות למדידות:
הזמן באלפיות השנייה שבו בוצעה המדידה (מציין זמן מאז האתחול):
מספר המדידות שניסו לבצע ומספר המדידות שהצליחו (ועליהם מבוססות מדידות המרחק):
משך הזמן המינימלי והמקסימלי שצריך להמתין במכשיר הלקוח בין מדידות של 11az NTB:
הפונקציות
getMinTimeBetweenNtbMeasurementsMicros()
ו-getMaxTimeBetweenNtbMeasurementsMicros()
מחזירות את הזמן המינימלי והמקסימלי. אם מדידת הטווח הבאה היא לפני שיחלוף הזמן המינימלי, ה-API מחזיר את תוצאה של טווח שנשמר במטמון. אם תתקבל בקשה למדידת הטווח הבא אחרי הזמן המקסימלי שחלף, אז ה-API מסיים את הלא-טריגר טווח של סשן חדש ומנהל משא ומתן על סשן חדש בטווח עם התגובה . מומלץ להימנע מבקשה לסשן מדידה חדש, כי היא מוסיפה זמן יתר לזמן המדידה. כדי לנצל את מלוא היתרונות של יעילות הטווח של 802.11az ללא טריגר, צריך להפעיל את בקשת הטווח הבאה בין זמן המדידה המינימלי למקסימלי שצוין במדידה הקודמת שלRangingResult
.חזרות בשדה אימון ארוך (LTF) שתחנות של מגיבים או יוזמים משמש בקידומת של תוצאת IEEE 802.11az NTB:
מספר השידורים והקבלים של שידורי זמן מרחביים (STS) שהיוזם תחנת עבודה שמשמשת עבור תוצאת IEEE 802.11az NTB:
מכשירי Android שתומכים ב-WiFi-RTT
בטבלאות הבאות מפורטים חלק מהטלפונים, נקודות הגישה ומכשירים לקמעונאות, למחסנים ולמרכזי הפצה שתומכים ב-WiFi-RTT. הנתונים האלה רחוקים מלהיות מקיפים. אנחנו ממליצים לפנות אלינו כדי לרשום כאן את המוצרים שלכם שתומכים ב-RTT.
נקודות גישה
יצרן ודגם | תאריך התמיכה |
---|---|
Nest Wifi Pro (Wi-Fi 6E) | נתמך |
Compulab WILD AP | נתמך |
Google Wi-Fi | נתמך |
נתב Wi-Fi של Google Nest | נתמך |
נקודת Wi-Fi של Google Nest | נתמך |
Aruba AP-635 | נתמך |
Cisco 9130 | נתמך |
Cisco 9136 | נתמך |
Cisco 9166 | נתמך |
Cisco 9164 | נתמך |
ארובה AP-505 | נתמך |
Aruba AP-515 | נתמך |
ארובה AP-575 | נתמך |
ארובה AP-518 | נתמך |
ארובה AP-505H | נתמך |
ארובה AP-565 | נתמך |
Aruba AP-535 | נתמך |
טלפונים
יצרן ודגם | גרסת Android |
---|---|
6 Pixel | 9.0 ומעלה |
Pixel 6 Pro | 9.0 ומעלה |
Pixel 5 | 9.0 ואילך |
Pixel 5a | 9.0 ואילך |
Pixel 5a (5G) | 9.0 ואילך |
Xiaomi Mi 10 Pro | 9.0 ואילך |
Xiaomi Mi 10 | 9.0 ואילך |
Xiaomi Redmi Mi 9T Pro | 9.0 ומעלה |
Xiaomi Mi 9T | 9.0 ואילך |
Xiaomi Mi 9 | 9.0 ואילך |
Xiaomi Mi Note 10 | 9.0 ומעלה |
Xiaomi Mi Note 10 Lite | 9.0 ומעלה |
Xiaomi Redmi Note 9S | 9.0 ואילך |
Xiaomi Redmi Note 9 Pro | 9.0 ומעלה |
Xiaomi Redmi Note 8T | 9.0 ואילך |
Xiaomi Redmi Note 8 | 9.0 ומעלה |
Xiaomi Redmi K30 Pro | 9.0 ומעלה |
Xiaomi Redmi K20 Pro | 9.0 ומעלה |
Xiaomi Redmi K20 | 9.0 ומעלה |
Xiaomi Redmi Note 5 Pro | 9.0 ואילך |
Xiaomi Mi CC9 Pro | 9.0 ומעלה |
LG G8X ThinQ | 9.0 ואילך |
LG V50S ThinQ | 9.0 ואילך |
LG V60 ThinQ | 9.0 ואילך |
LG V30 | 9.0 ומעלה |
Samsung Galaxy Note 10+ 5G | 9.0 ומעלה |
Samsung Galaxy S20+ 5G | 9.0 ומעלה |
טלפונים מדגם Samsung Galaxy S20 ואילך | 9.0 ומעלה |
Samsung Galaxy S20 5G | 9.0 ומעלה |
Samsung Galaxy S20 Ultra 5G | 9.0 ומעלה |
Samsung Galaxy S20 | 9.0 ומעלה |
Samsung Galaxy Note 10+ | 9.0 ואילך |
Samsung Galaxy Note 10 5G | 9.0 ואילך |
Samsung Galaxy Note 10 | 9.0 ומעלה |
Samsung A9 Pro | 9.0 ומעלה |
Google Pixel 4 XL | 9.0 ואילך |
Google Pixel 4 | 9.0 ומעלה |
Google Pixel 4a | 9.0 ומעלה |
Google Pixel 3 XL | 9.0 ומעלה |
Google Pixel 3 | 9.0 ואילך |
Google Pixel 3a XL | 9.0 ומעלה |
Google Pixel 3a | 9.0 ואילך |
Google Pixel 2 XL | 9.0 ואילך |
Google Pixel 2 | 9.0 ומעלה |
Google Pixel 1 XL | 9.0 ומעלה |
Google Pixel 1 | 9.0 ואילך |
Poco X2 | 9.0 ואילך |
Sharp Aquos R3 SH-04L | 9.0 ואילך |
מכשירים של מרכז הקמעונאות, האחסון וההפצה
יצרן ודגם | גרסת Android |
---|---|
Zebra PS20 | 10.0 ומעלה |
Zebra TC52/TC52HC | 10.0 ומעלה |
Zebra TC57 | 10.0 ומעלה |
Zebra TC72 | 10.0 ומעלה |
זברה TC77 | 10.0 ומעלה |
זברה MC93 | 10.0 ומעלה |
זברה TC8300 | 10.0 ומעלה |
Zebra VC8300 | 10.0 ומעלה |
Zebra EC30 | 10.0 ומעלה |
זברה ET51 | 10.0 ומעלה |
זברה ET56 | 10.0 ומעלה |
זברה L10 | 10.0 ומעלה |
Zebra CC600/CC6000 | 10.0 ומעלה |
Zebra MC3300x | 10.0 ומעלה |
זברה MC330x | 10.0 ומעלה |
זברה TC52x | 10.0 ומעלה |
Zebra TC57x | 10.0 ומעלה |
זברה EC50 (LAN ו-HC) | 10.0 ומעלה |
Zebra EC55 (WAN) | 10.0 ומעלה |
זברה WT6300 | 10.0 ומעלה |
Skorpio X5 | 10.0 ומעלה |