Fix Windows crash on start or stop scan (#143)

* Fix Windows crash on start or stop scan

* Fix crash on stop scan and cleanup

* Update Changelog

* Cleanups
This commit is contained in:
Rohit Sangwan
2025-02-25 18:13:51 +05:30
committed by GitHub
parent bc19a653dd
commit f0c38f7273
3 changed files with 82 additions and 19 deletions
+1
View File
@@ -1,5 +1,6 @@
## 0.17.0
* Fix Windows crash when calling pair APIs with an unknown deviceId
* Fix Windows crash when calling startScan again after some time
* Fix Windows warning `Unable to establish connection on channel` when hot restart
## 0.16.0
+59 -19
View File
@@ -130,20 +130,29 @@ namespace universal_ble
std::optional<FlutterError> UniversalBlePlugin::StartScan(const UniversalScanFilter *filter)
{
if (bluetoothRadio && bluetoothRadio.State() == RadioState::On)
if (!bluetoothRadio || bluetoothRadio.State() != RadioState::On)
{
return FlutterError("Bluetooth is not available");
}
try
{
setupDeviceWatcher();
scanResults.clear();
DeviceWatcherStatus status = deviceWatcher.Status();
if (status != DeviceWatcherStatus::Started)
DeviceWatcherStatus deviceWatcherStatus = deviceWatcher.Status();
// std::cout << "DeviceWatcherState: " << DeviceWatcherStatusToString(deviceWatcherStatus) << std::endl;
// DeviceWatcher can only start if its in Created, Stopped, or Aborted state
if (deviceWatcherStatus == DeviceWatcherStatus::Created || deviceWatcherStatus == DeviceWatcherStatus::Stopped || deviceWatcherStatus == DeviceWatcherStatus::Aborted)
{
deviceWatcher.Start();
}
else
else if (deviceWatcherStatus == DeviceWatcherStatus::Stopping)
{
return FlutterError("Already scanning");
return FlutterError("StoppingScan in progress");
}
// Setup LeWatcher and apply filters
if (!bluetoothLEWatcher)
{
bluetoothLEWatcher = BluetoothLEAdvertisementWatcher();
@@ -176,29 +185,41 @@ namespace universal_ble
bluetoothLEWatcherReceivedToken = bluetoothLEWatcher.Received({this, &UniversalBlePlugin::BluetoothLEWatcher_Received});
}
bluetoothLEWatcher.Start();
return std::nullopt;
}
else
catch (...)
{
return FlutterError("Bluetooth is not available");
std::cout << "Unknown error StartScan" << std::endl;
return FlutterError("Unknown error");
}
};
std::optional<FlutterError> UniversalBlePlugin::StopScan()
{
if (bluetoothRadio && bluetoothRadio.State() == RadioState::On)
{
if (bluetoothLEWatcher)
try
{
bluetoothLEWatcher.Stop();
bluetoothLEWatcher.Received(bluetoothLEWatcherReceivedToken);
if (bluetoothLEWatcher)
{
bluetoothLEWatcher.Received(bluetoothLEWatcherReceivedToken);
bluetoothLEWatcher.Stop();
}
bluetoothLEWatcher = nullptr;
disposeDeviceWatcher();
scanResults.clear();
return std::nullopt;
}
catch (const winrt::hresult_error &err)
{
int errorCode = err.code();
std::cout << "StopScanLog: " << winrt::to_string(err.message()) << " ErrorCode: " << std::to_string(errorCode) << std::endl;
return FlutterError(std::to_string(errorCode), winrt::to_string(err.message()));
}
catch (...)
{
return FlutterError("Failed to Stop");
}
bluetoothLEWatcher = nullptr;
disposeDeviceWatcher();
scanResults.clear();
return std::nullopt;
}
else
{
@@ -751,19 +772,38 @@ namespace universal_ble
deviceWatcherDevices.erase(deviceId);
// On Device Removed
});
deviceWatcherEnumerationCompletedToken = deviceWatcher.EnumerationCompleted([this](DeviceWatcher sender, IInspectable args)
{
std::cout << "DeviceWatcherEvent: EnumerationCompleted" << std::endl;
disposeDeviceWatcher();
// EnumerationCompleted
});
deviceWatcherStoppedToken = deviceWatcher.Stopped([this](DeviceWatcher sender, IInspectable args)
{
// std::cout << "DeviceWatcherEvent: Stopped" << std::endl;
// disposeDeviceWatcher();
// DeviceWatcher Stopped
});
}
void UniversalBlePlugin::disposeDeviceWatcher()
{
if (deviceWatcher != nullptr)
{
if (deviceWatcher.Status() == DeviceWatcherStatus::Started)
deviceWatcher.Stop();
deviceWatcher.Added(deviceWatcherAddedToken);
deviceWatcher.Updated(deviceWatcherUpdatedToken);
deviceWatcher.Removed(deviceWatcherRemovedToken);
deviceWatcher.EnumerationCompleted(deviceWatcherEnumerationCompletedToken);
deviceWatcher.Stopped(deviceWatcherStoppedToken);
auto status = deviceWatcher.Status();
// std::cout << "DisposingDeviceWatcher, CurrentState: " << DeviceWatcherStatusToString(status) << std::endl;
if (status == DeviceWatcherStatus::Started)
{
deviceWatcher.Stop();
}
deviceWatcher = nullptr;
// Dispose tokens
deviceWatcherDevices.clear();
}
}
+22
View File
@@ -99,6 +99,8 @@ namespace universal_ble
winrt::event_token deviceWatcherAddedToken;
winrt::event_token deviceWatcherUpdatedToken;
winrt::event_token deviceWatcherRemovedToken;
winrt::event_token deviceWatcherEnumerationCompletedToken;
winrt::event_token deviceWatcherStoppedToken;
winrt::fire_and_forget InitializeAsync();
void Radio_StateChanged(Radio sender, IInspectable args);
@@ -176,6 +178,26 @@ namespace universal_ble
void GetSystemDevices(
const flutter::EncodableList &with_services,
std::function<void(ErrorOr<flutter::EncodableList> reply)> result);
std::string DeviceWatcherStatusToString(DeviceWatcherStatus result)
{
switch (result)
{
case DeviceWatcherStatus::Created:
return "Created";
case DeviceWatcherStatus::Aborted:
return "Aborted";
case DeviceWatcherStatus::EnumerationCompleted:
return "EnumerationCompleted";
case DeviceWatcherStatus::Started:
return "Started";
case DeviceWatcherStatus::Stopped:
return "Stopped";
case DeviceWatcherStatus::Stopping:
return "Stopping";
}
return "";
}
};
} // namespace universal_ble