超寬頻通訊是一種無線電技術,專注於裝置之間的準確測距 (測量位置的精確度為 10 公分)。這項無線電技術可使用低能量密度進行短程測量,並在廣泛的無線電頻譜上執行高頻寬訊號。UWB 頻寬超過 500 MHz (或超過 20% 的部分頻寬)。
控管者/發起者與受控者/回應者
UWB 通訊會在兩部裝置之間進行,其中一部裝置為控制器,另一部裝置為受控裝置。Controller 會決定兩台裝置要共用的複雜管道 (UwbComplexChannel
),並扮演發起端的角色,而 Controlee 則是回應端。
Controller 可以處理多個 Controlee,但 Controlee 只能訂閱單一 Controller。支援控制器/啟動者和受控端/回應端設定。
測距參數
控制器和受控端需要相互識別,並傳送測距參數來開始測距。應用程式可使用所選的安全頻外 (OOB) 機制 (例如 藍牙低功耗 (BLE)) 實作此交換機制。
搜尋參數包括本機位址、複雜管道和工作階段金鑰等。請注意,這些參數可能會在測距工作階段結束後旋轉或變更,因此需要重新通訊才能重新啟動測距。
背景測距
如果裝置支援 UWB 測距功能,在背景執行的應用程式就能啟動 UWB 測距工作階段。如要檢查裝置功能,請參閱 RangingCapabilities
。
應用程式在背景執行時不會收到測距報告;應用程式移至前景時才會收到測距報告。
STS 設定
應用程式或服務會使用雜湊時間戳記序列 (STS) 為每個工作階段提供工作階段金鑰。已佈建的 STS 比靜態 STS 設定更安全。搭載 Android 14 以上版本的所有 UWB 裝置都支援預先提供的 STS。
威脅類別 | 靜態 STS | 已提供的 STS |
---|---|---|
Air:被動觀察 | 已緩解 | 已緩解 |
空氣:訊號放大 | 已緩解 | 已緩解 |
Air:重播/中繼攻擊 | 易受影響 | 已緩解 |
針對已佈建的 STS:
使用支援已佈建 STS 的
RangingParameters
中的uwbConfigType
。在
sessionKeyInfo
欄位中提供 16 個位元組的金鑰。
針對靜態 STS:
使用支援靜態 STS 的
RangingParameters
中的uwbConfigType
。在
sessionKeyInfo
欄位中提供 8 個位元組的金鑰。
操作步驟
如要使用 UWB API,請按照下列步驟操作:
- 請確認 Android 裝置搭載 Android 12 以上版本,且支援使用
PackageManager#hasSystemFeature("android.hardware.uwb")
的 UWB。 - 如果要對 IoT 裝置進行測距,請確認這些裝置符合 FiRa MAC 1.3 標準。
- 使用所選的 OOB 機制 (例如
BluetoothLeScanner
) 探索支援 UWB 的對等裝置。 - 使用您選擇的安全 OOB 機制 (例如
BluetoothGatt
) 交換測距參數。 - 如果使用者想停止工作階段,請取消工作階段的範圍。
使用限制
以下限制適用於 UWB API 的使用方式:
- 啟動新的 UWB 測距工作階段的應用程式必須是前景應用程式或服務,除非支援背景測距,如前文所述。
- 當應用程式移至背景 (工作階段持續進行時),應用程式可能就不會再收到回報。不過,UWB 工作階段會繼續在較低層級維護。當應用程式回到前景時,會恢復測距報告。
程式碼範例
範例應用程式
如需端對端範例,瞭解如何使用 UWB Jetpack 程式庫,請參閱 GitHub 上的範例應用程式。這個範例應用程式涵蓋驗證 Android 裝置的 UWB 相容性、使用 OOB 機制啟用偵測程序,以及設定兩部支援 UWB 的裝置之間的 UWB 測距。這個範例也涵蓋裝置控制和媒體分享用途。
UWB 測距
這個程式碼範例會啟動及終止受控端的 UWB 測距功能:
// The coroutineScope responsible for handling uwb ranging.
// This will be initialized when startRanging is called.
var job: Job?
// A code snippet that initiates uwb ranging for a Controlee.
suspend fun startRanging() {
// Get the ranging parameter of a partnering Controller using an OOB mechanism of choice.
val partnerAddress : Pair<UwbAddress, UwbComplexChannel> = listenForPartnersAddress()
// Create the ranging parameters.
val partnerParameters = RangingParameters(
uwbConfigType = UwbRangingParameters.UWB_CONFIG_ID_1,
// SessionKeyInfo is used to encrypt the ranging session.
sessionKeyInfo = null,
complexChannel = partnerAddress.second,
peerDevices = listOf(UwbDevice.createForAddress(partnerAddress.first)),
updateRateType = UwbRangingParameters.RANGING_UPDATE_RATE_AUTOMATIC
)
// Initiate a session that will be valid for a single ranging session.
val clientSession = uwbManager.clientSessionScope()
// Share the localAddress of the current session to the partner device.
broadcastMyParameters(clientSession.localAddress)
val sessionFlow = clientSession.prepareSession(partnerParameters)
// Start a coroutine scope that initiates ranging.
CoroutineScope(Dispatchers.Main.immediate).launch {
sessionFlow.collect {
when(it) {
is RangingResultPosition -> doSomethingWithPosition(it.position)
is RangingResultPeerDisconnected -> peerDisconnected(it)
}
}
}
}
// A code snippet that cancels uwb ranging.
fun cancelRanging() {
// Canceling the CoroutineScope will stop the ranging.
job?.let {
it.cancel()
}
}
RxJava3 支援
Rxjava3 支援功能現已推出,可協助實現與 Java 用戶端的互通性。這個程式庫提供一種方法,可將測量結果做為 Observable 或 Flowable 串流,並將 UwbClientSessionScope 擷取為 Single 物件。
private final UwbManager uwbManager;
// Retrieve uwbManager.clientSessionScope as a Single object
Single<UwbClientSessionScope> clientSessionScopeSingle =
UwbManagerRx.clientSessionScopeSingle(uwbManager);
UwbClientSessionScope uwbClientSessionScope = clientSessionScopeSingle.blockingGet();
// Retrieve uwbClientSessionScope.prepareSession Flow as an Observable object
Observable<RangingResult> rangingResultObservable =
UwbClientSessionScopeRx.rangingResultsObservable(clientSessionScope,
rangingParameters);
// Consume ranging results from Observable
rangingResultObservable.subscribe(
rangingResult -> doSomethingWithRangingResult(result), // onNext
(error) -> doSomethingWithError(error), // onError
() -> doSomethingOnResultEventsCompleted(), //onCompleted
);
// Unsubscribe
rangingResultObservable.unsubscribe();
// Retrieve uwbClientSessionScope.prepareSession Flow as a Flowable object
Flowable<RangingResult> rangingResultFlowable =
UwbClientSessionScopeRx.rangingResultsFlowable(clientSessionScope,
rangingParameters);
// Consume ranging results from Flowable using Disposable
Disposable disposable = rangingResultFlowable
.delay(1, TimeUnit.SECONDS)
.subscribeWith(new DisposableSubscriber<RangingResult> () {
@Override public void onStart() {
request(1);
}
@Override public void onNext(RangingResult rangingResult) {
doSomethingWithRangingResult(rangingResult);
request(1);
}
@Override public void onError(Throwable t) {
t.printStackTrace();
}
@Override public void onComplete() {
doSomethingOnEventsCompleted();
}
});
// Stop subscription
disposable.dispose();
生態系統支援
以下是支援的合作夥伴裝置和第三方 SDK。
支援 UWB 的行動裝置
自 2025 年 1 月起,下列裝置支援 Android UWB Jetpack 程式庫:
供應商 | 裝置型號 |
---|---|
Pixel Pro (6 Pro 以上機型)、Pixel Fold、Pixel Tablet | |
Motorola | Edge 50 Ultra |
Samsung | Galaxy Note 20、Galaxy Plus 和 Ultra (S21 以上機型)、Galaxy Z Fold (Fold2 以上機型) |
注意:所有裝置都支援背景 UWB 測距功能,但下列裝置除外:
- Pixel 6 Pro 和 Pixel 7 Pro。
- 搭載 Android 13 以下版本的 Samsung 手機。
- 搭載 Android 14 以下版本的中國版 Samsung 手機。
第三方 SDK
自 2023 年 4 月起,這些合作夥伴解決方案將與目前的 Jetpack 程式庫相容。
- Estimote UWB 開發套件。
- 行動知識:MK UWB Kit Mobile Edition 2.0。
已知問題:MAC 位址和靜態 STS 供應商 ID 欄位的位元組順序相反
在 Android 13 以下版本中,Android UWB 堆疊會錯誤地將下列欄位的位元組順序顛倒:
- 裝置的 MAC 位址
- 目的地 MAC 位址
- 靜態 STS 供應商 ID
位元組順序會顛倒,是因為 Android 堆疊會將這些欄位視為值,而非陣列。我們正在與 FiRa 合作更新 UCI 規格 (CR-1112),明確指出這些欄位應視為陣列。
這個問題將在 2320XXXX
版本中透過 GMS Core 更新修正。為了讓 IoT 供應商從此時起符合 Android 裝置的規範,他們必須修改實作方式,避免這些欄位的位元組順序倒轉。