FromBluetoothAddressAsync抛出';System.IO.FileNotFoundException';在mscorlib.ni.dll中

FromBluetoothAddressAsync抛出';System.IO.FileNotFoundException';在mscorlib.ni.dll中,bluetooth,windows-10,uwp,background-task,Bluetooth,Windows 10,Uwp,Background Task,我正在开发一个连接BLE信标的应用程序,为此我使用BluetoothLEAdvertisementWatcher API。当我收到广告时,我想连接到设备以阅读GATT特征 所以我开了一个观察者 BluetoothLEAdvertisementWatcher watcher; watcher.Received += OnAdvertisementReceived; watcher.Stopped += OnAdvertisementWatcherStopped; w

我正在开发一个连接BLE信标的应用程序,为此我使用BluetoothLEAdvertisementWatcher API。当我收到广告时,我想连接到设备以阅读GATT特征

所以我开了一个观察者

    BluetoothLEAdvertisementWatcher watcher;
    watcher.Received += OnAdvertisementReceived;
    watcher.Stopped += OnAdvertisementWatcherStopped;
    watcher.Start();
然后我尝试访问该设备

private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
    var address = eventArgs.BluetoothAddress;

    BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
    Debug.WriteLine(device.Name + " - " + device.DeviceId);
    ....
此操作失败(在FromBluetoothAddressAsync行)

在中发生“System.IO.FileNotFoundException”类型的异常 mscorlib.ni.dll,但未在用户代码中处理

其他信息:系统找不到指定的文件。(HRESULT的异常:0x80070002)

有趣的是:如果我打开系统的bluetooth devices(蓝牙设备)窗口,它可以正常工作

因此,当我打开bluetooth devices(蓝牙设备)窗口并运行应用程序时,不会抛出错误,当我关闭bluetooth devices(蓝牙设备)窗口时,会抛出错误

请注意,它总是在后台任务中抛出此错误

显然,它在构建10.0.10586.218时确实有效。 我在网上从一个有同样问题的人那里找到了这个:

LUMIA 950、Windows 10、1511、10.0.14332.1001

FromIdAsync()上引发异常:“System.IO.FileNotFoundException” 在mscorlib.ni.dll中

LUMIA 730、Windows 10、1511、10.0.10586.218

FindAllAsync()上引发异常:“System.ArgumentException”

LUMIA 920、Windows 10、1511、10.0.10586.218

没有错误

截图:


BLE Windows API是否可爱,以及它们为您提供的良好(未)记录的异常情况

我想,如果你想和一个设备配对,就不应该使用AdvertisementWatcher。相反,对于包含配对和非配对设备的可移动设备,请使用具有特定选择器的DeviceInformation watcher。这将提供一个可与之配对的即用设备信息对象


示例代码可以在第8个场景中看到。

BLE Windows API不是很可爱吗?它们给您提供了很好的(未记录的)异常

我想,如果你想和一个设备配对,就不应该使用AdvertisementWatcher。相反,对于包含配对和非配对设备的可移动设备,请使用具有特定选择器的DeviceInformation watcher。这将提供一个可与之配对的即用设备信息对象


示例代码可在场景8中看到。

问题

此错误是由在非UI线程中调用
FromBluetoothAddressAsync
引起的。当应用程序尝试访问蓝牙外围设备时,Windows 10需要用户同意。调用
FromBluetoothAddressAsync
时,Windows会尝试创建同意对话。由于这不是UI线程,因此无法显示同意对话框并引发异常

解决方案

首先,您应该使BluetoothLEAdvertisementWatcher更具体地针对您正在搜索的外围设备。如果你不这样做,那么你的应用程序将看到每一个蓝牙LE设备,并在每一个设备上提示用户同意-一个糟糕的用户体验

有多种方法可以过滤广告。您可以使用
eventArgs
中的属性,在您的
onadvertisimentreceived
方法中手动执行此操作,也可以在
BluetoothLEAdvertisementWatcher
本身中设置过滤器。例如,要查找具有心率监视器的蓝牙LE设备,请执行以下操作:

watcher.AdvertisementFilter.Advertisement.ServiceUuids.Add(GattServiceUuids.HeartRate);
要在UI线程上进行调用,需要使用调度程序。您可以使用以下代码设置dispatcher:

// Variable in your class
CoreDispatcher dispatcher;

// Init for your class
public MainPage() {
    ...
    // Init the dispatcher, this must be done on the main thread
    this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
    ...
}
然后,当您收到广告时,您可以进行自己的过滤,然后告诉调度程序连接到主线程上的蓝牙LE设备

private async void ConnectToBTDevice(BluetoothLEAdvertisementReceivedEventArgs eventArgs) {
    // This will cause a consent prompt if the user hasn't already consented
    var btDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
}

private bool Filter(BluetoothLEAdvertisementReceivedEventArgs eventArgs) {
    // Return true if the advertisement has the name we're looking for
    return eventArgs.Advertisement.LocalName != null && eventArgs.Advertisement.LocalName.Equals("Peripheral Name");
}

private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) {

    // Do our own filtering (for example)
    if(!this.Filter(eventArgs)) return;

    // Connect to the Bluetooth device in the UI (main) thread
    this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.ConnectToBTDevice(eventArgs));
}

问题

此错误是由在非UI线程中调用
FromBluetoothAddressAsync
引起的。当应用程序尝试访问蓝牙外围设备时,Windows 10需要用户同意。调用
FromBluetoothAddressAsync
时,Windows会尝试创建同意对话。由于这不是UI线程,因此无法显示同意对话框并引发异常

解决方案

首先,您应该使BluetoothLEAdvertisementWatcher更具体地针对您正在搜索的外围设备。如果你不这样做,那么你的应用程序将看到每一个蓝牙LE设备,并在每一个设备上提示用户同意-一个糟糕的用户体验

有多种方法可以过滤广告。您可以使用
eventArgs
中的属性,在您的
onadvertisimentreceived
方法中手动执行此操作,也可以在
BluetoothLEAdvertisementWatcher
本身中设置过滤器。例如,要查找具有心率监视器的蓝牙LE设备,请执行以下操作:

watcher.AdvertisementFilter.Advertisement.ServiceUuids.Add(GattServiceUuids.HeartRate);
要在UI线程上进行调用,需要使用调度程序。您可以使用以下代码设置dispatcher:

// Variable in your class
CoreDispatcher dispatcher;

// Init for your class
public MainPage() {
    ...
    // Init the dispatcher, this must be done on the main thread
    this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
    ...
}
然后,当您收到广告时,您可以进行自己的过滤,然后告诉调度程序连接到主线程上的蓝牙LE设备

private async void ConnectToBTDevice(BluetoothLEAdvertisementReceivedEventArgs eventArgs) {
    // This will cause a consent prompt if the user hasn't already consented
    var btDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
}

private bool Filter(BluetoothLEAdvertisementReceivedEventArgs eventArgs) {
    // Return true if the advertisement has the name we're looking for
    return eventArgs.Advertisement.LocalName != null && eventArgs.Advertisement.LocalName.Equals("Peripheral Name");
}

private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) {

    // Do our own filtering (for example)
    if(!this.Filter(eventArgs)) return;

    // Connect to the Bluetooth device in the UI (main) thread
    this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.ConnectToBTDevice(eventArgs));
}

连接问题通过我标记为答案的注释解决,首先配对,然后使用FromIdAsync。不过,我也使用了其中的一部分来修复它,谢谢。连接问题通过我标记为答案的评论解决了,首先配对,然后使用FromIdAsync。不过,我也使用了其中的一部分来修复它,非常感谢。