diff --git a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor index 6189781f746..035104b5ffe 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor @@ -46,9 +46,9 @@ private IBluetoothService? BluetoothService { get; set; } private IBluetoothService? BluetoothService { get; set; }
2. 列出蓝牙设备
-调用 BluetoothService 实例方法 RequestDevice 即可,通过 IsSupport 进行浏览器是否支持蓝牙
调用 BluetoothService 实例方法 RequestDevice 即可,通过 IsSupport 进行浏览器是否支持蓝牙。可以通过 BluetoothRequestOptions 过滤参数过滤蓝牙设备
_serialPort = await BluetoothService.RequestDevice(["battery_service"]);
+_serialPort = await BluetoothService.RequestDevice();
if (BluetoothService.IsSupport == false)
{
await ToastService.Error(Localizer["NotSupportBluetoothTitle"], Localizer["NotSupportBluetoothContent"]);
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
index 447ac818d14..beaf34bd93f 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/Bluetooth.razor.cs
@@ -25,7 +25,7 @@ public partial class Bluetooth
private async Task RequestDevice()
{
- _blueDevice = await BluetoothService.RequestDevice(["battery_service"]);
+ _blueDevice = await BluetoothService.RequestDevice();
if (BluetoothService.IsSupport == false)
{
await ToastService.Error(Localizer["NotSupportBluetoothTitle"], Localizer["NotSupportBluetoothContent"]);
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 53074d70cd1..a10da1e8964 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
- 8.10.4-beta03
+ 8.10.4
diff --git a/src/BootstrapBlazor/Services/Bluetooth/BluetoothFilter.cs b/src/BootstrapBlazor/Services/Bluetooth/BluetoothFilter.cs
new file mode 100644
index 00000000000..7c46c59c14e
--- /dev/null
+++ b/src/BootstrapBlazor/Services/Bluetooth/BluetoothFilter.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.Json.Serialization;
+
+namespace BootstrapBlazor.Components;
+
+///
+/// BluetoothFilter 类
+///
+public class BluetoothFilter
+{
+ ///
+ /// An array of values indicating the Bluetooth GATT (Generic Attribute Profile) services that a Bluetooth device must support. Each value can be a valid name from the GATT assigned services list, such as 'battery_service' or 'blood_pressure'. You can also pass a full service UUID such as '0000180F-0000-1000-8000-00805f9b34fb' or the short 16-bit (0x180F) or 32-bit alias. Note that these are the same values that can be passed to BluetoothUUID.getService().
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? Services { get; set; }
+
+ ///
+ /// A string containing the precise name of the device to match against.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Name { get; set; }
+
+ ///
+ /// A string containing the name prefix to match against. All devices that have a name starting with this string will be matched.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? NamePrefix { get; set; }
+
+ ///
+ /// An array of objects matching against manufacturer data in the Bluetooth Low Energy (BLE) advertising packets.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? ManufacturerData { get; set; }
+
+ ///
+ /// An array of objects matching against service data in the Bluetooth Low Energy (BLE) advertising packets.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? ServiceData { get; set; }
+}
diff --git a/src/BootstrapBlazor/Services/Bluetooth/BluetoothManufacturerDataFilter.cs b/src/BootstrapBlazor/Services/Bluetooth/BluetoothManufacturerDataFilter.cs
new file mode 100644
index 00000000000..39f0eb5d4a9
--- /dev/null
+++ b/src/BootstrapBlazor/Services/Bluetooth/BluetoothManufacturerDataFilter.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.Json.Serialization;
+
+namespace BootstrapBlazor.Components;
+
+///
+/// BluetoothManufacturerDataFilter 配置类
+///
+public class BluetoothManufacturerDataFilter
+{
+ ///
+ /// A mandatory number identifying the manufacturer of the device. Company identifiers are listed in the Bluetooth specification Assigned numbers, Section 7. For example, to match against devices manufactured by "Digianswer A/S", with assigned hex number 0x000C, you would specify 12.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public int? CompanyIdentifier { get; set; }
+
+ ///
+ /// The data prefix. A buffer containing values to match against the values at the start of the advertising manufacturer data.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? DataPrefix { get; set; }
+
+ ///
+ /// This allows you to match against bytes within the manufacturer data, by masking some bytes of the service data dataPrefix.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Mask { get; set; }
+}
diff --git a/src/BootstrapBlazor/Services/Bluetooth/BluetoothRequestOptions.cs b/src/BootstrapBlazor/Services/Bluetooth/BluetoothRequestOptions.cs
new file mode 100644
index 00000000000..015d90e77ee
--- /dev/null
+++ b/src/BootstrapBlazor/Services/Bluetooth/BluetoothRequestOptions.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.Json.Serialization;
+
+namespace BootstrapBlazor.Components;
+
+///
+/// BluetoothRequestOptions 参数类
+///
+public class BluetoothRequestOptions
+{
+ ///
+ /// An array of filter objects indicating the properties of devices that will be matched. To match a filter object, a device must match all the values of the filter: all its specified services, name, namePrefix, and so on
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? Filters { get; set; }
+
+ ///
+ /// An array of filter objects indicating the characteristics of devices that will be excluded from matching. The properties of the array elements are the same as for .
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? ExclusionFilters { get; set; }
+
+ ///
+ /// An array of optional service identifiers.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? OptionalServices { get; set; }
+
+ ///
+ /// An optional array of integer manufacturer codes. This takes the same values as companyIdentifier.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? OptionalManufacturerData { get; set; }
+
+ ///
+ /// A boolean value indicating that the requesting script can accept all Bluetooth devices. The default is false.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public bool AcceptAllDevices { get; set; }
+}
diff --git a/src/BootstrapBlazor/Services/Bluetooth/BluetoothServiceDataFilter.cs b/src/BootstrapBlazor/Services/Bluetooth/BluetoothServiceDataFilter.cs
new file mode 100644
index 00000000000..4179124e55e
--- /dev/null
+++ b/src/BootstrapBlazor/Services/Bluetooth/BluetoothServiceDataFilter.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using System.Text.Json.Serialization;
+
+namespace BootstrapBlazor.Components;
+
+///
+/// BluetoothServiceDataFilter 配置类
+///
+public class BluetoothServiceDataFilter
+{
+ ///
+ /// The GATT service name, the service UUID, or the UUID 16-bit or 32-bit form. This takes the same values as the elements of the services array.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Service { get; set; }
+
+ ///
+ /// The data prefix. A buffer containing values to match against the values at the start of the advertising service data.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? DataPrefix { get; set; }
+
+ ///
+ /// This allows you to match against bytes within the manufacturer data, by masking some bytes of the service data dataPrefix.
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Mask { get; set; }
+}
diff --git a/src/BootstrapBlazor/Services/Bluetooth/DefaultBluetoothService.cs b/src/BootstrapBlazor/Services/Bluetooth/DefaultBluetoothService.cs
index abe3fb8b6eb..7ae91f8bccb 100644
--- a/src/BootstrapBlazor/Services/Bluetooth/DefaultBluetoothService.cs
+++ b/src/BootstrapBlazor/Services/Bluetooth/DefaultBluetoothService.cs
@@ -70,7 +70,7 @@ public async Task GetAvailability(CancellationToken token = default)
///
///
///
- public async Task RequestDevice(string[] optionalServices, CancellationToken token = default)
+ public async Task RequestDevice(BluetoothRequestOptions? options = null, CancellationToken token = default)
{
_module ??= await LoadModule();
@@ -78,7 +78,7 @@ public async Task GetAvailability(CancellationToken token = default)
if (IsSupport)
{
ErrorMessage = null;
- var parameters = await _module.InvokeAsync("requestDevice", token, _deviceId, optionalServices, _interop, nameof(OnError));
+ var parameters = await _module.InvokeAsync("requestDevice", token, _deviceId, options, _interop, nameof(OnError));
if (parameters != null)
{
device = new BluetoothDevice(_module, _deviceId, parameters);
diff --git a/src/BootstrapBlazor/Services/Bluetooth/IBluetoothService.cs b/src/BootstrapBlazor/Services/Bluetooth/IBluetoothService.cs
index f7ceadd248f..ed4c8a76773 100644
--- a/src/BootstrapBlazor/Services/Bluetooth/IBluetoothService.cs
+++ b/src/BootstrapBlazor/Services/Bluetooth/IBluetoothService.cs
@@ -33,8 +33,8 @@ public interface IBluetoothService
///
/// 请求蓝牙配对方法
///
- /// 请求服务列表 请参考 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt
+ /// 实例
///
///
- Task RequestDevice(string[] optionalServices, CancellationToken token = default);
+ Task RequestDevice(BluetoothRequestOptions? options = null, CancellationToken token = default);
}
diff --git a/src/BootstrapBlazor/wwwroot/modules/bt.js b/src/BootstrapBlazor/wwwroot/modules/bt.js
index aed1d74a616..394be95b8ed 100644
--- a/src/BootstrapBlazor/wwwroot/modules/bt.js
+++ b/src/BootstrapBlazor/wwwroot/modules/bt.js
@@ -12,7 +12,7 @@ export async function getAvailability() {
return ret;
}
-export async function requestDevice(id, optionalServices, invoke, method) {
+export async function requestDevice(id, options, invoke, method) {
let ret = await getAvailability();
if (ret === false) {
return null;
@@ -22,9 +22,8 @@ export async function requestDevice(id, optionalServices, invoke, method) {
const bt = { device: null };
Data.set(id, bt);
try {
- const ret = await navigator.bluetooth.requestDevice({
- acceptAllDevices: true,
- optionalServices: optionalServices
+ const ret = await navigator.bluetooth.requestDevice(options ?? {
+ acceptAllDevices: true
});
bt.device = ret;
device = [ret.name, ret.id];
diff --git a/test/UnitTest/Services/BluetoothServiceTest.cs b/test/UnitTest/Services/BluetoothServiceTest.cs
index a44551dc1d0..cdf811988cb 100644
--- a/test/UnitTest/Services/BluetoothServiceTest.cs
+++ b/test/UnitTest/Services/BluetoothServiceTest.cs
@@ -17,7 +17,7 @@ public async Task RequestDevice_Ok()
Context.JSInterop.Setup("disconnect", matcher => matcher.Arguments.Count == 3 && (matcher.Arguments[0]?.ToString()?.StartsWith("bb_bt_") ?? false)).SetResult(true);
var bluetoothService = Context.Services.GetRequiredService();
- var device = await bluetoothService.RequestDevice(["battery_service"]);
+ var device = await bluetoothService.RequestDevice();
Assert.NotNull(device);
Assert.Equal("test", device.Name);
Assert.Equal("id_1234", device.Id);
@@ -50,7 +50,7 @@ public async Task ReadValue_null()
Context.JSInterop.Setup("requestDevice", matcher => matcher.Arguments.Count == 4 && (matcher.Arguments[0]?.ToString()?.StartsWith("bb_bt_") ?? false)).SetResult(["test", "id_1234"]);
Context.JSInterop.Setup("readValue", matcher => matcher.Arguments.Count == 5 && (matcher.Arguments[0]?.ToString()?.StartsWith("bb_bt_") ?? false)).SetResult(null);
var bluetoothService = Context.Services.GetRequiredService();
- var device = await bluetoothService.RequestDevice(["battery_service"]);
+ var device = await bluetoothService.RequestDevice();
Assert.NotNull(device);
var v = await device.GetBatteryValue();
Assert.Equal(0x0, v);
@@ -73,4 +73,65 @@ public async Task GetAvailability_Ok()
mi.Invoke(bluetoothService, ["test"]);
Assert.Equal("test", bluetoothService.ErrorMessage);
}
+
+ [Fact]
+ public void Filter_Ok()
+ {
+ var filter = new BluetoothRequestOptions()
+ {
+ Filters =
+ [
+ new() {
+ ManufacturerData =
+ [
+ new()
+ {
+ CompanyIdentifier = 0x004C,
+ DataPrefix = "Apple",
+ Mask = "test"
+ }
+ ],
+ Name = "test-Name",
+ NamePrefix = "test-NamePrefix",
+ Services = ["test-service"],
+ ServiceData = [new BluetoothServiceDataFilter()
+ {
+ DataPrefix = "test-data-prefix",
+ Service = "test-data-service",
+ Mask = "test-data-mask"
+ }]
+ }
+ ],
+ AcceptAllDevices = false,
+ ExclusionFilters = [],
+ OptionalManufacturerData = ["test-manufacturer-data"],
+ OptionalServices = ["test-optional-service"]
+ };
+
+ Assert.NotNull(filter.Filters);
+
+ var data = filter.Filters[0].ManufacturerData;
+ Assert.NotNull(data);
+ Assert.Equal(0x004C, data[0].CompanyIdentifier);
+ Assert.Equal("Apple", data[0].DataPrefix);
+ Assert.Equal("test", data[0].Mask);
+
+ Assert.Equal("test-Name", filter.Filters[0].Name);
+ Assert.Equal("test-NamePrefix", filter.Filters[0].NamePrefix);
+
+ var services = filter.Filters[0].Services;
+ Assert.NotNull(services);
+ Assert.Equal("test-service", services[0]);
+
+ var serviceData = filter.Filters[0].ServiceData;
+ Assert.NotNull(serviceData);
+ Assert.Equal("test-data-prefix", serviceData[0].DataPrefix);
+ Assert.Equal("test-data-service", serviceData[0].Service);
+ Assert.Equal("test-data-mask", serviceData[0].Mask);
+
+ Assert.False(filter.AcceptAllDevices);
+ Assert.Empty(filter.ExclusionFilters);
+ Assert.Equal(["test-manufacturer-data"], filter.OptionalManufacturerData);
+ Assert.Equal(["test-optional-service"], filter.OptionalServices);
+ }
}