Bạn có thể sử dụng chức năng vị trí Wi-Fi do API RTT Wi-Fi (Round-Trip-Time) cung cấp để đo khoảng cách tới các điểm truy cập Wi-Fi hỗ trợ RTT ở gần và các thiết bị Nhận biết Wi-Fi ngang hàng.
Nếu đo khoảng cách đến 3 điểm truy cập trở lên, bạn có thể sử dụng thuật toán đa phương để ước tính vị trí thiết bị phù hợp nhất với các phép đo đó. Kết quả thường chính xác trong vòng 1-2 mét.
Với độ chính xác này, bạn có thể phát triển các dịch vụ dựa trên vị trí chi tiết, chẳng hạn như chỉ đường trong nhà, điều khiển bằng giọng nói riêng biệt (ví dụ: "Bật đèn này") và thông tin dựa trên vị trí (ví dụ: "Sản phẩm này có ưu đãi đặc biệt không?").
Thiết bị yêu cầu không cần kết nối với các điểm truy cập để đo khoảng cách bằng tính năng Tin nhắn theo thời gian thực (RTT) của Wi-Fi. Để duy trì quyền riêng tư, chỉ thiết bị yêu cầu mới có thể xác định khoảng cách đến điểm truy cập; các điểm truy cập không có thông tin này. Không giới hạn hoạt động của Tin nhắn theo thời gian thực (RTT) của Wi-Fi đối với các ứng dụng trên nền trước nhưng bị điều tiết đối với các ứng dụng nền.
RTT của Wi-Fi và các chức năng Fine-Time-Measurement (FTM) liên quan được chỉ định theo tiêu chuẩn IEEE 802.11-2016. RTT Wi-Fi yêu cầu phép đo thời gian chính xác do FTM cung cấp vì tính năng này tính khoảng cách giữa 2 thiết bị bằng cách đo thời gian một gói cần để đi một vòng giữa các thiết bị rồi nhân thời gian đó với tốc độ ánh sáng.
Sự khác biệt về cách triển khai dựa trên phiên bản Android
Tin nhắn theo thời gian thực (RTT) của Wi-Fi đã được ra mắt trong Android 9 (API cấp 28). Khi dùng giao thức này để xác định vị trí của một thiết bị bằng tính năng đa phương với các thiết bị chạy Android 9, bạn cần có quyền truy cập vào dữ liệu vị trí điểm truy cập (AP) được xác định trước trong ứng dụng của mình. Bạn là người quyết định cách lưu trữ và truy xuất dữ liệu này.
Trên các thiết bị chạy Android 10 (API cấp 29) trở lên, dữ liệu vị trí AP có thể được biểu thị dưới dạng các đối tượng ResponderLocation
, bao gồm vĩ độ, kinh độ và độ cao. Đối với các AP RTT Wi-Fi hỗ trợ Thông tin cấu hình vị trí/Báo cáo hành chính vị trí (dữ liệu LCI/LCR), giao thức sẽ trả về một đối tượng ResponderLocation
trong quá trình phân bổ.
Tính năng này cho phép các ứng dụng truy vấn AP để trực tiếp hỏi vị trí của chúng thay vì cần lưu trữ trước thông tin này. Vì vậy, ứng dụng của bạn có thể tìm các AP và xác định vị trí của các AP đó ngay cả khi trước đây các AP đó chưa từng được biết đến, chẳng hạn như khi người dùng bước vào một toà nhà mới.
Yêu cầu
- Phần cứng của thiết bị đưa ra yêu cầu phạm vi phải triển khai tiêu chuẩn FTM 802.11-2016.
- Thiết bị đưa ra yêu cầu về khoảng không phải chạy Android 9 (API cấp 28) trở lên.
- Thiết bị đưa ra yêu cầu khoảng cách phải bật dịch vụ vị trí và bật tính năng quét tìm Wi-Fi (trong phần Cài đặt > Vị trí).
- Nếu ứng dụng đang thực hiện yêu cầu phạm vi nhắm đến Android 13 (API cấp 33) trở lên, thì ứng dụng đó phải có quyền
NEARBY_WIFI_DEVICES
. Nếu một ứng dụng như vậy nhắm đến một phiên bản Android cũ hơn, thì ứng dụng đó phải có quyềnACCESS_FINE_LOCATION
. - Ứng dụng phải truy vấn phạm vi điểm truy cập trong khi đang hiển thị hoặc trong một dịch vụ trên nền trước. Ứng dụng không thể truy cập vào thông tin vị trí ở chế độ nền.
- Điểm truy cập phải triển khai theo tiêu chuẩn FTM IEEE 802.11-2016.
Thiết lập
Để thiết lập ứng dụng dùng tính năng Tin nhắn theo thời gian thực (RTT) của Wi-Fi, hãy thực hiện các bước sau.
1. Yêu cầu cấp quyền
Yêu cầu các quyền sau đây trong tệp kê khai của ứng dụng:
<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" />
Các quyền NEARBY_WIFI_DEVICES
và ACCESS_FINE_LOCATION
là các quyền nguy hiểm, vì vậy, bạn cần yêu cầu các quyền này trong thời gian chạy mỗi khi người dùng muốn thực hiện thao tác quét tin nhắn theo thời gian thực (RTT). Ứng dụng của bạn sẽ cần yêu cầu người dùng cấp quyền nếu quyền đó chưa được cấp. Để biết thêm thông tin về quyền khi bắt đầu chạy, hãy xem bài viết Yêu cầu quyền cho ứng dụng.
2. Kiểm tra xem thiết bị có hỗ trợ tin nhắn theo thời gian thực (RTT) của Wi-Fi hay không
Để kiểm tra xem thiết bị có hỗ trợ Tin nhắn theo thời gian thực (RTT) qua Wi-Fi hay không, hãy sử dụng API PackageManager:
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. Kiểm tra xem có dùng được RTT Wi-Fi hay không
Tin nhắn theo thời gian thực (RTT) của Wi-Fi có thể tồn tại trên thiết bị, nhưng hiện có thể không hoạt động vì người dùng đã tắt Wi-Fi. Tuỳ thuộc vào tính năng phần cứng và chương trình cơ sở, một số thiết bị có thể không hỗ trợ Tin nhắn theo thời gian thực (RTT) của Wi-Fi nếu SoftAP hoặc tính năng chia sẻ Internet đang được sử dụng. Để kiểm tra xem thời gian dùng tính năng Tin nhắn theo thời gian thực (RTT) của Wi-Fi có đang hoạt động hay không, hãy gọi isAvailable().
Khả năng sử dụng Tin nhắn theo thời gian thực (RTT) qua Wi-Fi có thể thay đổi bất cứ lúc nào. Ứng dụng của bạn nên đăng ký một broadcastReceiver để nhận ACTION_Wifi_RTT_STATE_CHANGED, được gửi khi tình trạng hoạt động thay đổi. Khi nhận được ý định truyền tin, ứng dụng sẽ kiểm tra trạng thái sẵn có hiện tại và điều chỉnh hành vi của ứng dụng cho phù hợp.
Ví dụ:
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);
Để biết thêm thông tin, hãy xem phần Chương trình phát sóng.
Tạo yêu cầu phạm vi
Yêu cầu phạm vi (RangingRequest) được tạo bằng cách chỉ định một danh sách các điểm truy cập ngang hàng (AP) hoặc Wi-Fi Aware (Nhận biết Wi-Fi) mà phạm vi được yêu cầu. Bạn có thể chỉ định nhiều điểm truy cập hoặc thiết bị ngang hàng trong tính năng Nhận biết Wi-Fi trong một yêu cầu trong một phạm vi; đo lường và trả về khoảng cách đến tất cả các thiết bị.
Ví dụ: yêu cầu có thể dùng phương thức addAccessPoint() để chỉ định một điểm truy cập cần đo khoảng cách:
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();
Điểm truy cập được xác định bằng đối tượng QuétResult. Bạn có thể thu được điểm truy cập này bằng cách gọi WifiManager.getScanRenderer().
Bạn có thể sử dụng
addAccessPoints(List
Tương tự, một yêu cầu trong phạm vi có thể thêm một ứng dụng ngang hàng nhận biết Wi-Fi bằng địa chỉ MAC hoặc PeerHandle của yêu cầu đó, sử dụng phương thức addWifiAwarePeer(MacAddress ngang hàng) và addWifiAwarePeer(PeerHandle) tương ứng. Để biết thêm thông tin về cách khám phá các thiết bị ngang hàng hỗ trợ tính năng Nhận biết Wi-Fi, hãy xem tài liệu về tính năng Nhận biết Wi-Fi.
Yêu cầu phạm vi
Một ứng dụng đưa ra yêu cầu theo khoảng bằng cách sử dụng phương thức WifiRttManager.startRanging() và cung cấp các thông tin sau: RangingRequest để chỉ định thao tác, Trình thực thi để chỉ định ngữ cảnh gọi lại và RangingResultCallback để nhận kết quả.
Ví dụ:
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) { … } });
Thao tác sắp xếp được thực hiện không đồng bộ và các kết quả khác nhau được trả về bằng một trong các lệnh gọi lại của RangingResultCallback:
- Nếu không thể thực hiện toàn bộ thao tác trong phạm vi, thì lệnh gọi lại onRangingFailure sẽ được kích hoạt bằng mã trạng thái được mô tả trong RangingResultCallback. Lỗi như vậy có thể xảy ra nếu dịch vụ không thể thực thi một hoạt động trong phạm vi tại một thời điểm – ví dụ: do Wi-Fi bị tắt, vì ứng dụng đã yêu cầu quá nhiều thao tác trong phạm vi và bị điều tiết hoặc do vấn đề về quyền.
- Khi thao tác phạm vi hoàn tất, lệnh gọi lại onRanging Results sẽ được kích hoạt với một danh sách kết quả khớp với danh sách yêu cầu--một kết quả cho mỗi yêu cầu. Thứ tự của kết quả không nhất thiết phải khớp với thứ tự của yêu cầu. Xin lưu ý rằng thao tác trong khoảng có thể hoàn tất nhưng mỗi kết quả vẫn có thể cho biết lỗi của phép đo cụ thể đó.
Diễn giải phạm vi kết quả
Mỗi kết quả mà lệnh gọi lại onRanging Results trả về đều được chỉ định bằng đối tượng RangingResult. Đối với mỗi yêu cầu, hãy làm như sau.
1. Xác định yêu cầu
Xác định yêu cầu dựa trên thông tin được cung cấp khi tạo RangingRequest: thường là một địa chỉ MAC được cung cấp trong ScanResult
để xác định một điểm truy cập. Địa chỉ MAC có thể lấy từ kết quả phạm vi bằng phương thức getMacAddress().
Danh sách kết quả trong dải có thể khác thứ tự các kết quả ngang hàng (điểm truy cập) được chỉ định trong yêu cầu giới hạn. Vì vậy, bạn nên sử dụng địa chỉ MAC để xác định ứng dụng ngang hàng, chứ không phải thứ tự kết quả.
2. Xác định xem mỗi phép đo có thành công hay không
Để xác định xem một phép đo có thành công hay không, hãy sử dụng phương thức
getStatus(). Bất kỳ giá trị nào khác không phải STATUS_STATUS sẽ cho biết không thành công. Nếu không thành công, tất cả các trường khác của kết quả này (ngoại trừ thông tin nhận dạng yêu cầu ở trên) đều không hợp lệ và phương thức get*
tương ứng sẽ không thành công với ngoại lệ IllegalStateException .
3. Nhận kết quả cho mỗi lần đo lường thành công
Đối với mỗi lần đo lường thành công, bạn có thể truy xuất các giá trị kết quả bằng các phương thức get
tương ứng:
Khoảng cách, tính bằng mm và độ lệch chuẩn của phép đo:
RSSI của các gói dùng để đo lường:
Thời gian tính bằng mili giây khi thực hiện phép đo (biểu thị thời gian kể từ khi khởi động):
Số lần đo đã thử và số lần đo đã thực hiện thành công (và dựa trên dữ liệu đo khoảng cách):
Các thiết bị Android hỗ trợ Wi-Fi-RTT
Bảng dưới đây liệt kê một số điện thoại, điểm truy cập và thiết bị bán lẻ, kho hàng và trung tâm phân phối có hỗ trợ Wi-Fi-RTT. Các chỉ số này chưa hoàn chỉnh. Bạn nên liên hệ với chúng tôi để liệt kê các sản phẩm có hỗ trợ tính năng RTT tại đây.
Điểm truy cập
Nhà sản xuất và kiểu máy | Ngày hỗ trợ |
---|---|
Nest Wifi Pro (Wi-Fi 6E) | Có thể làm |
Compulab WILD AP | Có thể làm |
Wi-Fi của Google | Có thể làm |
Bộ định tuyến Wi-Fi của Google Nest | Có thể làm |
Điểm phát Wi-Fi Google Nest | Có thể làm |
Aruba AP-635 | Có thể làm |
Cisco 9130 | Có thể làm |
Cisco 9136 | Có thể làm |
Cisco 9166 | Có thể làm |
Cisco 9164 | Có thể làm |
Aruba AP-505 | Có thể làm |
Aruba AP-515 | Có thể làm |
Aruba AP-575 | Có thể làm |
Aruba AP-518 | Có thể làm |
Aruba AP-505H | Có thể làm |
Aruba AP-565 | Có thể làm |
Aruba AP-535 | Có thể làm |
Điện thoại
Nhà sản xuất và kiểu máy | Phiên bản Android |
---|---|
Pixel 6 | 9 trở lên |
Pixel 6 Pro | 9 trở lên |
Pixel 5 | 9 trở lên |
Pixel 5a | 9 trở lên |
Pixel 5a (5G) | 9 trở lên |
Xiaomi Mi 10 Pro | 9 trở lên |
Xiaomi Mi 10 | 9 trở lên |
Xiaomi Redmi Mi 9T Pro | 9 trở lên |
Xiaomi Mi 9T | 9 trở lên |
Xiaomi Mi 9 | 9 trở lên |
Xiaomi Mi Note 10 | 9 trở lên |
Xiaomi Mi Note 10 Lite | 9 trở lên |
Xiaomi Redmi Note 9S | 9 trở lên |
Xiaomi Redmi Note 9 Pro | 9 trở lên |
Xiaomi Redmi Note 8T | 9 trở lên |
Xiaomi Redmi Note 8 | 9 trở lên |
Xiaomi Redmi K30 Pro | 9 trở lên |
Xiaomi Redmi K20 Pro | 9 trở lên |
Xiaomi Redmi K20 | 9 trở lên |
Xiaomi Redmi Note 5 Pro | 9 trở lên |
Xiaomi Mi CC9 Pro | 9 trở lên |
LG G8X ThinQ | 9 trở lên |
LG V50S ThinQ | 9 trở lên |
LG V60 ThinQ | 9 trở lên |
LG V30 | 9 trở lên |
Samsung Galaxy Note 10+ 5G | 9 trở lên |
Samsung Galaxy S20+ 5G | 9 trở lên |
Samsung Galaxy S20 trở lên | 9 trở lên |
Samsung Galaxy S20 5G | 9 trở lên |
Samsung Galaxy S20 Ultra 5G | 9 trở lên |
Samsung Galaxy S20 | 9 trở lên |
Samsung Galaxy Note 10 trở lên | 9 trở lên |
Samsung Galaxy Note 10 5G | 9 trở lên |
Samsung Galaxy Note 10 | 9 trở lên |
Samsung A9 Pro | 9 trở lên |
Google Pixel 4 XL | 9 trở lên |
Google Pixel 4 | 9 trở lên |
Google Pixel 4a | 9 trở lên |
Google Pixel 3 XL | 9 trở lên |
Google Pixel 3 | 9 trở lên |
Google Pixel 3a XL | 9 trở lên |
Google Pixel 3a | 9 trở lên |
Google Pixel 2 XL | 9 trở lên |
Google Pixel 2 | 9 trở lên |
Google Pixel 1 XL | 9 trở lên |
Google Pixel 1 | 9 trở lên |
Poco X2 | 9 trở lên |
Sharp Aquos R3 SH-04L | 9 trở lên |
Thiết bị cho trung tâm bán lẻ, kho hàng và phân phối
Nhà sản xuất và kiểu máy | Phiên bản Android |
---|---|
Ngựa vằn PS20 | 10.0 trở lên |
Ngựa vằn TC52/TC52HC | 10.0 trở lên |
Ngựa vằn TC57 | 10.0 trở lên |
Ngựa vằn TC72 | 10.0 trở lên |
Ngựa vằn TC77 | 10.0 trở lên |
Ngựa vằn MC93 | 10.0 trở lên |
Ngựa vằn TC8300 | 10.0 trở lên |
Ngựa vằn VC8300 | 10.0 trở lên |
Ngựa vằn EC30 | 10.0 trở lên |
Ngựa vằn ET51 | 10.0 trở lên |
Ngựa vằn ET56 | 10.0 trở lên |
Ngựa vằn L10 | 10.0 trở lên |
Ngựa vằn CC600/CC6000 | 10.0 trở lên |
Ngựa vằn MC3300x | 10.0 trở lên |
Ngựa vằn MC330x | 10.0 trở lên |
Ngựa vằn TC52x | 10.0 trở lên |
Ngựa vằn TC57x | 10.0 trở lên |
Zebra EC50 (LAN và HC) | 10.0 trở lên |
Ngựa vằn EC55 (WAN) | 10.0 trở lên |
Ngựa vằn WT6300 | 10.0 trở lên |
Skorpio X5 | 10.0 trở lên |