蓝牙客户端QBluetoothSocket的使用——Qt For Android

了解蓝牙

经典蓝牙和低功耗蓝牙差异

经典蓝牙(Bluetooth Classic):分为基本速率/增强数据速率(BR/EDR), 79个信道,在2.4GHz的(ISM)频段。支持点对点设备通信,主要用于实现无线音频流传输,已成为无线扬声器、耳机和车载娱乐系统背后的标准无线电协议。经典蓝牙还支持数据传输程序,包括移动打印。

低功耗蓝牙(Bluetooth Low Energy):为低功耗操作而设计的。工作在2.4GHz无授权ISM频段,共40个信道传输数据。蓝牙LE支持多种通信拓扑,点对点,广播,Mesh。使蓝牙能够支持创建可靠的、大规模的网络。LE也被广泛用于设备定位技术,满足高精度室内定位服务的需求。

经典蓝牙和低功耗蓝牙差异 - 知乎

蓝牙的配对和连接的建立过程

taodudu.cc/news/show-3161112.html?action=onClick

Qt蓝牙模块

支持的平台

 Qt 5.14 adds a native Win32 port supporting Classic Bluetooth on Windows 7 or newer, and Bluetooth LE on Windows 8 or newer. It must be enabled at build time by configuration option -native-win32-bluetooth. The UWP backend is used by default if this option is not set and the Win32 target platform supports the required UWP APIs (minimal requirement is Windows 10 version 1507, with slightly improved service discovery since Windows 10 version 1607).

使用

环境

版本:Qt15.15.2

语言:c++

平台:Android 11

蓝牙类型:经典蓝牙(Bluetooth Classic)

代码和说明

使用前在pro文件加载蓝牙模块

QT += bluetooth

大家都有使用蓝牙的经历,一般步骤是:检查蓝牙状态(是否打开)->查找附近的设备->配对->连接->数据的传输,下面就按照这个流程介绍代码。

  • 检查蓝牙状态(是否打开)

QBluetoothLocalDevice提供了获取和设置本地蓝牙设备状态的功能。 

可通过

QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const

来获取当前主机的模式,这里只判断是否是未打开,若未打开,可用powerOn() 打开蓝牙,不过调用后,立马再调用创建连接会失败,可能硬件还没准备好。

   QBluetoothLocalDevice* m_pLocalDev;
   m_pLocalDev = new QBluetoothLocalDevice(this);

   //检查蓝牙是否未打开
   if(m_pLocalDev->hostMode()==QBluetoothLocalDevice::HostPoweredOff)
    {
        m_pLocalDev->powerOn(); //打开蓝牙
        emit errorBTDevPowerOff();
        return false;
    }

  •  查找附近的蓝牙设备

 QBluetoothDeviceDiscoveryAgent 类可发现附近的蓝牙设备

void BluetoothDevice::BluetoothDevice()
{
    ...
   //初始化

    QBluetoothDeviceDiscoveryAgent* m_pDevDiscoveryAgent;
    m_pDevDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);


    connect(m_pDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,     this, &BluetoothDevice::onDeviceDiscovered);
    connect(m_pDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothDevice::onDiscoverFinished);
    connect(m_pDevDiscoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
            this, &BluetoothDevice::onDiscoverFinished);

   ...
}


void BluetoothDevice::refreshBTDevices()
{
    ...
    //开始查找附近蓝牙设备,根据需求这里限定为经典蓝牙
    m_pDevDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::ClassicMethod);

}

//查找到的蓝牙设备的信息
void BluetoothDevice::onDeviceDiscovered(const QBluetoothDeviceInfo &device)
{
    //MAC地址
    const QString& macAddr = device.address().toString();
    //设备名称
    const QString& name= device.name();

   //判读检测到设备是否与本地设备配对
    bool isPaired = false;
   if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == 
    QBluetoothLocalDevice::AuthorizedPaired )
       isPaired =true;
   
} 
//查找结束
void BluetoothDevice::onDiscoverFinished()
{
    emit discoveryFinished();
}

 上方确实获取一些附近的蓝牙设备,但是经常获取不全。情况是这样的:我的手机可查找到待开发设备(后续称设备)的蓝牙,但是设备没有查找到手机蓝牙,所以然后我用手机主动发起配对,是可以成功配对的,后续可以收发文件或者信息。在配对成功后,设备是可以看到我手机的名称和蓝牙MAC地址的,但是QBluetoothDeviceDiscoveryAgent 类仍无法查找到我的手机。

设备可查找到,Qt不行,所以尝试使用Java的方法,直接获取配对设备列表,这个方法是可以的:

package org.qtproject.example.testBluetooth;

import org.qtproject.qt5.android.bindings.QtActivity;

import android.bluetooth.*;
import java.util.Set;
import java.lang.String;
import java.util.ArrayList;


public class MainActivity extends QtActivity
{

    ... 
    public String[] getBondedDevices(boolean isBLE)
    {
        BluetoothAdapter BTAdapter = BluetoothAdapter.getDefaultAdapter();
        Set<BluetoothDevice> bondedDevice = BTAdapter.getBondedDevices();
        ArrayList<String> list = new ArrayList<String>();
        for (BluetoothDevice bt : bondedDevice)
        {
            int deviceType = bt.getType();
            if (!isBLE && (deviceType == BluetoothDevice.DEVICE_TYPE_CLASSIC || deviceType == BluetoothDevice.DEVICE_TYPE_DUAL))
                list.add(bt.getAddress() + " " + bt.getName());
            else if (isBLE && (deviceType == BluetoothDevice.DEVICE_TYPE_LE || deviceType == BluetoothDevice.DEVICE_TYPE_DUAL))
                list.add(bt.getAddress() + " " + bt.getName());
        }
        String[] result = (String[]) list.toArray(new String[list.size()]);
        return result;
    }


}

AndroidManifest.xml 修改

由于java中继承了QtActivity,所以xml中名字要进行更改

<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.example.testBluetooth.MainActivity" android:label="configSignal" android:screenOrientation="unspecified" android:launchMode="singleTop">

c++中调用

#ifdef Q_OS_ANDROID
void BluetoothDevice::getBondedTarget()
{
    QAndroidJniEnvironment env;
    QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION");
    if(r == QtAndroid::PermissionResult::Denied)
    {
        QtAndroid::requestPermissionsSync(QStringList() << "android.permission.ACCESS_FINE_LOCATION");
        r = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION");
        if(r == QtAndroid::PermissionResult::Denied)
        {
            qDebug() << "failed to request";
        }
    }
    qDebug() << "has permission";
    QAndroidJniObject array = QtAndroid::androidActivity().callObjectMethod("getBondedDevices", "(Z)[Ljava/lang/String;", false);
    int arraylen = env->GetArrayLength(array.object<jarray>());
    qDebug() << "arraylen:" << arraylen ;

    m_bondedDevices.clear();

    for(int i = 0; i < arraylen; i++)
    {
        QString info = QAndroidJniObject::fromLocalRef(env->GetObjectArrayElement(array.object<jobjectArray>(), i)).toString();
        BTDeviceInfo devInfo;
        devInfo.macAddr = info.left(info.indexOf(' '));
        devInfo.name = info.right(info.length() - info.indexOf(' ') - 1);
        devInfo.isPaired = true;

        m_bondedDevices.append(devInfo);
    }

}
#endif

  •  配对

上面我们已经获取附近蓝牙设备的配对状态了,配对的话可以手动配对,或者可以试试下面的方法,不过我测试时由于手机蓝牙搜不到,所以是手动配对的,没有尝试代码请求配对。

void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)

  • 创建连接

 Qt封装了蓝牙客户端(QBluetoothSocket)和蓝牙服务端(QBluetoothServer),跟Tcp的使用很像:Socket尝试连接服务器,Server监测连接,双方都可读写。

以客户端的身份QBluetoothSocket,请求连接服务器。服务器就是之前配对好的手机或者别的设备,注意手机端要打开蓝牙服务器QBluetoothServer,不然是不可能连接成功的。

  • 连接服务器

可以看到,需要传入服务器地址、uuid和打开模式。服务器地址 就是配对的蓝牙MAC地址;uuid有很多值,不同的功能uuid不同,可看一下枚举 enum QBluetoothUuid::ServiceClassUuid 了解一下;打开模式就不用说了。

void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode = ReadWrite)

代码示例

//初始化

QBluetoothSocket* m_pSocket;
QByteArray m_buf;
QString m_strServerUUID;
QString m_strMACAddr;

m_pSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol,this);
m_strServerUUID = QBluetoothUuid(QBluetoothUuid::SerialPort).toString();

connect(m_pSocket,&QBluetoothSocket::connected,this,&BluetoothConnection::onConnected);    connect(m_pSocket,&QBluetoothSocket::disconnected,this,&BluetoothConnection::onDisconnect);
connect(m_pSocket,&QBluetoothSocket::readyRead,this,&BluetoothConnection::onReadyRead);
connect(m_pSocket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
            this, &BluetoothConnection::onErrorOccurred);


//连接服务器 (uuid 可传入,可默认)
void BluetoothConnection::connectToSerive(QString strAddr, QString strUuid)
{
    if(m_pSocket->state() == QBluetoothSocket::ConnectedState)
    {
        if(strAddr == m_strMACAddr && strUuid == m_strServerUUID)
        {
            return;
        }
        else
            disconnect();
    }


    if(strUuid != "")
        m_strServerUUID = strUuid;
    m_strMACAddr = strAddr;

    m_pSocket->connectToService(QBluetoothAddress(strAddr), QBluetoothUuid(m_strServerUUID),QIODevice::ReadWrite);
}
  •  数据传输处理

数据传输处理这部分,代码就不展示了,需求不同,代码不同。

结束语

安卓的蓝牙客户端大概就是这样了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ceph:关于Ceph 集群管理的一些笔记

写在前面 准备考试&#xff0c;整理ceph 相关笔记博文内容涉及&#xff0c;Ceph 管理工具 cephadm&#xff0c;ceph 编排器&#xff0c;Ceph CLI 和 Dashboard GUI 介绍理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守…

大数据分析平台释疑专用帖第二弹

不管是想要快速了解BI大数据分析平台&#xff0c;还是想要了解BI和自己的需求匹配度&#xff0c;都可关注我们的释疑专用贴。 1、可以分析直播数据吗&#xff1f; 严格来说&#xff0c;只要能够提供数据&#xff0c;就可以做数据可视化分析&#xff0c;直播数据也同理。 如果…

solr快速上手:整合SolrJ实现客户端操作(九)

0. 引言 我们前面学习了solr的服务端基础操作&#xff0c;实际项目中我们还需要在客户端调用solr&#xff0c;就像调用数据库一样&#xff0c;我们可以基于solrJ来实现对solr的客户端操作 1. SolrJ简介 SolrJ 是 Solr官方提供的 Java 客户端库&#xff0c;主要用于与 Solr 服…

Python 请求分页

文章目录 什么是 Python 中的分页带有下一个按钮的 Python 分页没有下一个按钮的 Python 分页无限滚动的 Python 分页带有加载更多按钮的分页 在本文中&#xff0c;我们将了解分页以及如何克服 Python 中与分页相关的问题。 读完本文后&#xff0c;我们将能够了解 Python 分页以…

经典目标检测YOLO系列(1)YOLO-V1算法及其在VOC2007数据集上的应用

经典目标检测YOLO系列(1)YOLO-V1算法及其在VOC2007数据集上的应用 1 YOLO-V1的简述 1.1 目标检测概述 ​ 目标检测有非常广泛的应用&#xff0c; 例如&#xff1a;在安防监控、手机支付中的人脸检测&#xff1b;在智慧交通&#xff0c;自动驾驶中的车辆检测&#xff1b;在智…

Parallel Desktop中按照的centos在切换root用户时,密码正确,但一直切换不成功,显示su: Authentication failure

目录 一、出现问题二、分析问题三、解决问题四、参考资料 一、出现问题 我的密码明明是输入正确的&#xff0c;但又一直给我报下面的错误 二、分析问题 我怀疑是我密码记错了&#xff0c;所以我点击Log Out&#xff0c;重新去输入了一下密码&#xff0c;发现是正确的我确认…

Build your own unconditional confidence

不要活在既定的社会价值体系中 人类的偏好大多数时候都是愚昧的 I play whatever gods give me 情绪价值稳定 解决问题的能力 Dont label yourself 真正的强者不会吝啬对他人的赞美 敬畏自然&#xff0c;敬畏未知事物 核心是你对这个事情是否感兴趣&#xff0c;觉得有价…

PHP 使用html创建PDF并设置水印

使用TCPDF库给PDF文件加水印&#xff0c;需要注意无法直接使用文本&#xff0c;需要创建水印图片后&#xff0c;通过图片来设置水印效果。 目录 创建PDF 创建合同模板 创建pdf文件 简单创建 设置文档信息 去掉默认页头脚 设置间距 设置字体支持中文 设置图片比例因子 …

代理ip数据采集的优缺点

随着互联网时代的到来&#xff0c;数据已经成为企业发展和决策的关键。但是&#xff0c;不同的网站它对于数据访问的限制和反爬虫措施却是给企业的数据采集带来了挑战。针对这一问题&#xff0c;代理IP数据采集技术应运而生。但是使用代理ip来进行数据采集也有优缺点。 一、代理…

【微信小程序】wxml、wxss、js、json文件介绍

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;微信小程序的入门介绍 【前言】书接上回&#xff0c;我们知道了一个小程序的构成结构&#xff0c;接下来我们来进一步学习小程序的目录结构中的.wxml、.wxss、.js、.json。 目录 ⭐ 一…

List容器(Java)

文章目录 1.容器介绍1.1 容器接口结构1.2 简单解析 2. List容器创建(Member functions)3. 访问操作(Element access)3.1 get()3.2 Iterator遍历3.3 增强for循环 4. 修改操作(Modifiers)4.1 add()4.2 addAll()4.3 remove()4.4 set() 5. 容量操作(Member functions)5.1 clear() …

傻白入门芯片设计,形式化验证方法学——AveMC工具学习(二十)

目录 一、形式验证方法学 &#xff08;一&#xff09;什么是形式化验证&#xff1f; &#xff08;二&#xff09;与传统验证的区别&#xff1f; 二、AveMC工具学习 &#xff08;一&#xff09;什么是AveMC&#xff1f; &#xff08;二&#xff09;AveMC的工作逻辑&#x…

Redis整合jedis 学习

前言 redis简单来讲是内存数据库&#xff0c;因为是将数据存放到内存&#xff0c;因此读写速率高快(传统数据库&#xff0c;不是先从内存转到硬存&#xff0c;慢) 1.jedis连接Redis redis是java操作redis的客户端&#xff0c;通过他我们能通过java语句操控redis。 jedis对于…

全国大数据与计算智能挑战赛:面向低资源的命名实体识别基线方案,排名13/64,组织单位:国防科技大学系统工程学院(大数据与决策实验室)

NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…

一起学SF框架系列6.1-模块core-Resource

Java虽然提供了java.net.URL类和各种URL前缀处理程序来负责处理对各种资源的访问&#xff0c;但对于低级别资源的访问来说还是不够充分。例如&#xff0c;没有标准化的实现可用于访问需要从类路径中获取或者相对于一个ServletContext的资源&#xff1b;也没有检查所指向的资源是…

Linux 正则表达式

正则表达式有什么用&#xff1f;最基本的爬虫会用到&#xff0c;正则表达式简单来说就是匹配字符串的 比如&#xff1a;你匹配所有图片的链接地址 <img src"------(图片链接地址)"> 比如、abc/def URL:在WWW上&#xff0c;每一信息资源都有统一的且在网上…

(opencv)图像几何变换——缩放

图像缩放是指将图像的尺寸变小或变大的过程&#xff0c;也就是减少或增加源图像数据的像素个数。图像缩放一定程度上会造成信息的丢失&#xff0c;因此需要考虑适宜的方法进行操作。 下面介绍两种常用的图像缩放方法的原理及实现 1.基于等间隔提取图像缩放 等间隔提取图像缩…

机器视觉初步5-1:图像平滑专题

在计算机视觉领域&#xff0c;图像平滑处理是一个重要的任务&#xff0c;用于降低噪声&#xff0c;提高图像质量。常见的图像平滑算法有均值滤波、中值滤波、高斯滤波等。本文将介绍这些算法的原理&#xff0c;并分别给出使用Python与Halcon实现的代码。&#xff08;当前版本&a…

什么是微软的 Application Framework?

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来看一下什么是微软的 Application Framework&#xff1f; 到底什么是 Application Framework&#xff1f; 我当年学习这个的时候也困惑了好久&#xff0c;于是一直在搜索这个概念有没有好的解释&#…

ChatGPT时代:ChatGPT全能应用一本通

引言 随着人工智能技术的不断发展和进步&#xff0c;我们进入了ChatGPT时代。ChatGPT是基于GPT架构的大型语言模型&#xff0c;它具备强大的自然语言处理和生成能力&#xff0c;使得我们能够进行更加自由、流畅的对话。作为ChatGPT的全能应用&#xff0c;它可以被视为一本通&a…