My Qt Android Bluetooth code is not working for an Android-13 device when using Qt5.12.3
-
Hi,
I have a Qt Android-based code that scan BLE devices and display them on a widget. My code works well when it runs on a Android-8 device (API-level 26) using Qt5.12.3, jdk1.8.0_211, NDK 19.2.5345600 and SDK target=26.
When compiling the code for an Android-13 device (API-level 33), the application is not able to find and display BLE devices. I am also using Qt5.12.3, NDK 19.2.5345600 and SDK target=28 which is the highest SDK supported in my Qt. I also included all required permissions in the manifest.xml file:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BLUETOOTH_CONNECT
android.permission.BLUETOOTH_SCANHere is the output when using the Android-13 device but without correctly finding and displaying BLE devices:
I faced same issue when testing heartrate-game example from Qt: Android-8 device successfully detects nearby BLE devices while Android-13 device could not.
Therefore, is this issue related to the used Qt version and/or the target SDK ? i.e., should I use more recent Qt version (like Qt5.15) and higher target SDK (level 33) ? I prefer to work with Qt5 since it supports .pro files which I am currently using.
Here are the main parts of my code:
#include <QtAndroid>
#include <QAndroidJniObject>void MainWindow::deviceDiscovered(const QBluetoothDeviceInfo &device)
{
qDebug() << "[BLE] Raw: " << device.name() << device.address().toString();if(device.coreConfigurations()&QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { qDebug() << "Discovered:" << device.name() << device.address().toString(); if(BLE_liste->findItems(device.name()+"\n"+device.address().toString(),Qt::MatchExactly).count()==0) { BLE_liste->addItem(device.name()+"\n"+device.address().toString()); *dev_info=device; QBluetoothDeviceInfo* temp_info=new QBluetoothDeviceInfo; *temp_info=device; dev_info_list.append(temp_info); } }
}
void MainWindow::searchCharacteristic()
{
if(BLE_service){
foreach (QLowEnergyCharacteristic c, BLE_service->characteristics()) {
if(c.isValid()){
if (c.properties() & QLowEnergyCharacteristic::WriteNoResponse ||
c.properties() & QLowEnergyCharacteristic::Write) {
m_writeCharacteristic = c;
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
m_writeMode = QLowEnergyService::WriteWithoutResponse;
else
m_writeMode = QLowEnergyService::WriteWithResponse;
}
if (c.properties() & QLowEnergyCharacteristic::Read)
m_readCharacteristic = c;if(c.properties() & QLowEnergyCharacteristic::Notify) { m_notificationDesc = c.descriptor( QBluetoothUuid::ClientCharacteristicConfiguration); if (m_notificationDesc.isValid()) { BLE_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100")); } } } } }
}
void MainWindow::on_listWidget_itemClicked(QListWidgetItem *item)
{
string = item->text();string = string.split("\n").at(0); //get the 1st word in string *dev_info=*(dev_info_list.at(BLE_liste->row(item))); BLE_controlleur=new QLowEnergyController(*dev_info,this);
connect(BLE_controlleur, SIGNAL(connected()),this,SLOT(device_connected()));
connect(BLE_controlleur, SIGNAL(discoveryFinished()),this,SLOT(service_discovered()));
BLE_controlleur->connectToDevice();}
void MainWindow::device_connected()
{
BLE_controlleur->discoverServices();
}void MainWindow::service_discovered()
{
services_discovered=1;
m_servicesUuid = BLE_controlleur->services();int maxl=m_servicesUuid.length(); for(int i=0;i<maxl;i++) { if(m_servicesUuid.at(i).toString()=="{6e400001-b5a3-f393-e0a9-e50e24dcca9e}") { BLE_service= BLE_controlleur->createServiceObject(m_servicesUuid.at(i), this); connect(BLE_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(onServiceStateChanged(QLowEnergyService::ServiceState))); connect(BLE_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)), this, SLOT(update_com_state_(QLowEnergyCharacteristic,QByteArray))); connect(BLE_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(error_slot(QLowEnergyService::ServiceError))); connect(Comm_timer, SIGNAL(timeout()),this, SLOT(update_com_state())); if(BLE_service->state() == QLowEnergyService::DiscoveryRequired) { BLE_service->discoverDetails(); } else searchCharacteristic(); BLE_liste->setStyleSheet("QListWidget{background-color: rgba(0,0,0,0);color:rgb(202,233,250);font-weight:bold;font-family:Myriad Pro Regular;font-size:64px;border:4px solid rgb(249,159,65);border-radius:12px;} QListWidget::item:selected{background:rgb(249,159,65);color:rgb(0,0,0);}"); } }
}
void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s)
{
if (s == QLowEnergyService::ServiceDiscovered)
{
searchCharacteristic();
}
}void MainWindow::BLE_search_slot()
{
if(agent!=nullptr)
{
delete agent;
}if(ble_widget->isHidden()==false) { if(localDevice.hostMode()==QBluetoothLocalDevice::HostPoweredOff) {localDevice.powerOn(); QTimer::singleShot(2000, this, SLOT(BLE_search_slot())); } BLE_liste->clear(); dev_info_list.clear(); QtAndroid::requestPermissionsSync({ "android.permission.ACCESS_FINE_LOCATION", "android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT" }); agent = new QBluetoothDeviceDiscoveryAgent(); // create an object in ctors connect(agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this, SLOT(deviceDiscovered(QBluetoothDeviceInfo))); agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); }
}
-
Hi,
I have a Qt Android-based code that scan BLE devices and display them on a widget. My code works well when it runs on a Android-8 device (API-level 26) using Qt5.12.3, jdk1.8.0_211, NDK 19.2.5345600 and SDK target=26.
When compiling the code for an Android-13 device (API-level 33), the application is not able to find and display BLE devices. I am also using Qt5.12.3, NDK 19.2.5345600 and SDK target=28 which is the highest SDK supported in my Qt. I also included all required permissions in the manifest.xml file:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BLUETOOTH_CONNECT
android.permission.BLUETOOTH_SCANHere is the output when using the Android-13 device but without correctly finding and displaying BLE devices:
I faced same issue when testing heartrate-game example from Qt: Android-8 device successfully detects nearby BLE devices while Android-13 device could not.
Therefore, is this issue related to the used Qt version and/or the target SDK ? i.e., should I use more recent Qt version (like Qt5.15) and higher target SDK (level 33) ? I prefer to work with Qt5 since it supports .pro files which I am currently using.
Here are the main parts of my code:
#include <QtAndroid>
#include <QAndroidJniObject>void MainWindow::deviceDiscovered(const QBluetoothDeviceInfo &device)
{
qDebug() << "[BLE] Raw: " << device.name() << device.address().toString();if(device.coreConfigurations()&QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { qDebug() << "Discovered:" << device.name() << device.address().toString(); if(BLE_liste->findItems(device.name()+"\n"+device.address().toString(),Qt::MatchExactly).count()==0) { BLE_liste->addItem(device.name()+"\n"+device.address().toString()); *dev_info=device; QBluetoothDeviceInfo* temp_info=new QBluetoothDeviceInfo; *temp_info=device; dev_info_list.append(temp_info); } }
}
void MainWindow::searchCharacteristic()
{
if(BLE_service){
foreach (QLowEnergyCharacteristic c, BLE_service->characteristics()) {
if(c.isValid()){
if (c.properties() & QLowEnergyCharacteristic::WriteNoResponse ||
c.properties() & QLowEnergyCharacteristic::Write) {
m_writeCharacteristic = c;
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
m_writeMode = QLowEnergyService::WriteWithoutResponse;
else
m_writeMode = QLowEnergyService::WriteWithResponse;
}
if (c.properties() & QLowEnergyCharacteristic::Read)
m_readCharacteristic = c;if(c.properties() & QLowEnergyCharacteristic::Notify) { m_notificationDesc = c.descriptor( QBluetoothUuid::ClientCharacteristicConfiguration); if (m_notificationDesc.isValid()) { BLE_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100")); } } } } }
}
void MainWindow::on_listWidget_itemClicked(QListWidgetItem *item)
{
string = item->text();string = string.split("\n").at(0); //get the 1st word in string *dev_info=*(dev_info_list.at(BLE_liste->row(item))); BLE_controlleur=new QLowEnergyController(*dev_info,this);
connect(BLE_controlleur, SIGNAL(connected()),this,SLOT(device_connected()));
connect(BLE_controlleur, SIGNAL(discoveryFinished()),this,SLOT(service_discovered()));
BLE_controlleur->connectToDevice();}
void MainWindow::device_connected()
{
BLE_controlleur->discoverServices();
}void MainWindow::service_discovered()
{
services_discovered=1;
m_servicesUuid = BLE_controlleur->services();int maxl=m_servicesUuid.length(); for(int i=0;i<maxl;i++) { if(m_servicesUuid.at(i).toString()=="{6e400001-b5a3-f393-e0a9-e50e24dcca9e}") { BLE_service= BLE_controlleur->createServiceObject(m_servicesUuid.at(i), this); connect(BLE_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(onServiceStateChanged(QLowEnergyService::ServiceState))); connect(BLE_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)), this, SLOT(update_com_state_(QLowEnergyCharacteristic,QByteArray))); connect(BLE_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(error_slot(QLowEnergyService::ServiceError))); connect(Comm_timer, SIGNAL(timeout()),this, SLOT(update_com_state())); if(BLE_service->state() == QLowEnergyService::DiscoveryRequired) { BLE_service->discoverDetails(); } else searchCharacteristic(); BLE_liste->setStyleSheet("QListWidget{background-color: rgba(0,0,0,0);color:rgb(202,233,250);font-weight:bold;font-family:Myriad Pro Regular;font-size:64px;border:4px solid rgb(249,159,65);border-radius:12px;} QListWidget::item:selected{background:rgb(249,159,65);color:rgb(0,0,0);}"); } }
}
void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s)
{
if (s == QLowEnergyService::ServiceDiscovered)
{
searchCharacteristic();
}
}void MainWindow::BLE_search_slot()
{
if(agent!=nullptr)
{
delete agent;
}if(ble_widget->isHidden()==false) { if(localDevice.hostMode()==QBluetoothLocalDevice::HostPoweredOff) {localDevice.powerOn(); QTimer::singleShot(2000, this, SLOT(BLE_search_slot())); } BLE_liste->clear(); dev_info_list.clear(); QtAndroid::requestPermissionsSync({ "android.permission.ACCESS_FINE_LOCATION", "android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT" }); agent = new QBluetoothDeviceDiscoveryAgent(); // create an object in ctors connect(agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this, SLOT(deviceDiscovered(QBluetoothDeviceInfo))); agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); }
}
@ZINE Please format your code properly.
For newer Android devices you should also use newer Qt version, 5.12.3 is quite old already and I doubt it officially supports Android 13 (see https://doc.qt.io/archives/qt-5.12/android.html). -
@jsulm Thanks for the feedback. I think that at least Qt5.15 is required to supports Android 13 (see https://medium.com/@shmilysyg/set-android-target-sdk-level-33-in-qt-38bb9049924c). I prefer using Qt5.15.2 since I am using .pro files. Also, I suppose that I need higher JDK and NDK versions.
While I do not think that the issue is related to the code (I tested Qt example and did not work), here is my formatted code:
void MainWindow::deviceDiscovered(const QBluetoothDeviceInfo &device) { qDebug() << "[BLE] Raw: " << device.name() << device.address().toString(); if(device.coreConfigurations()&QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { qDebug() << "Discovered:" << device.name() << device.address().toString(); if(BLE_liste->findItems(device.name()+"\n"+device.address().toString(),Qt::MatchExactly).count()==0) { BLE_liste->addItem(device.name()+"\n"+device.address().toString()); *dev_info=device; QBluetoothDeviceInfo* temp_info=new QBluetoothDeviceInfo; *temp_info=device; dev_info_list.append(temp_info); } } } void MainWindow::searchCharacteristic() { if(BLE_service){ foreach (QLowEnergyCharacteristic c, BLE_service->characteristics()) { if(c.isValid()){ if (c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write) { m_writeCharacteristic = c; if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse) m_writeMode = QLowEnergyService::WriteWithoutResponse; else m_writeMode = QLowEnergyService::WriteWithResponse; } if (c.properties() & QLowEnergyCharacteristic::Read) m_readCharacteristic = c; if(c.properties() & QLowEnergyCharacteristic::Notify) { m_notificationDesc = c.descriptor( QBluetoothUuid::ClientCharacteristicConfiguration); if (m_notificationDesc.isValid()) { BLE_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100")); } } } } } } void MainWindow::on_listWidget_itemClicked(QListWidgetItem *item) { string = item->text(); string = string.split("\n").at(0); //get the 1st word in string *dev_info=*(dev_info_list.at(BLE_liste->row(item))); BLE_controlleur=new QLowEnergyController(*dev_info,this); connect(BLE_controlleur, SIGNAL(connected()),this,SLOT(device_connected())); connect(BLE_controlleur, SIGNAL(discoveryFinished()),this,SLOT(service_discovered())); BLE_controlleur->connectToDevice(); } void MainWindow::device_connected() { BLE_controlleur->discoverServices(); } void MainWindow::service_discovered() { services_discovered=1; m_servicesUuid = BLE_controlleur->services(); int maxl=m_servicesUuid.length(); for(int i=0;i<maxl;i++) { if(m_servicesUuid.at(i).toString()=="{6e400001-b5a3-f393-e0a9-e50e24dcca9e}") { BLE_service= BLE_controlleur->createServiceObject(m_servicesUuid.at(i), this); connect(BLE_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(onServiceStateChanged(QLowEnergyService::ServiceState))); connect(BLE_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)), this, SLOT(update_com_state_(QLowEnergyCharacteristic,QByteArray))); connect(BLE_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(error_slot(QLowEnergyService::ServiceError))); connect(Comm_timer, SIGNAL(timeout()),this, SLOT(update_com_state())); if(BLE_service->state() == QLowEnergyService::DiscoveryRequired) { BLE_service->discoverDetails(); } else searchCharacteristic(); BLE_liste->setStyleSheet("QListWidget{background-color: rgba(0,0,0,0);color:rgb(202,233,250);font-weight:bold;font-family:Myriad Pro Regular;font-size:64px;border:4px solid rgb(249,159,65);border-radius:12px;} QListWidget::item:selected{background:rgb(249,159,65);color:rgb(0,0,0);}"); } } } void MainWindow::onServiceStateChanged(QLowEnergyService::ServiceState s) { if (s == QLowEnergyService::ServiceDiscovered) { searchCharacteristic(); } } void MainWindow::BLE_search_slot() { if(agent!=nullptr) { delete agent; } if(ble_widget->isHidden()==false) { if(localDevice.hostMode()==QBluetoothLocalDevice::HostPoweredOff) {localDevice.powerOn(); QTimer::singleShot(2000, this, SLOT(BLE_search_slot())); } BLE_liste->clear(); dev_info_list.clear(); QtAndroid::requestPermissionsSync({ "android.permission.ACCESS_FINE_LOCATION", "android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT" }); agent = new QBluetoothDeviceDiscoveryAgent(); // create an object in ctors connect(agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this, SLOT(deviceDiscovered(QBluetoothDeviceInfo))); agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); } }