【Android】Bluetooth(蓝牙)连接与数据传输(一)

简介

蓝牙技术是一种无线数据和语音通信开放的全球规范,它是基于低成本的近距离无线连接,为固定和移动设备建立通信环境的一种特殊的近距离无线技术(使用2.4~2.485GHz的ISM波段的UHF无线电波)连接。

蓝牙类型描述
经典蓝牙(Classic Bluetooth)功耗高,传输数据量大,传输距离短(10米)
低功耗蓝牙(Bluetooth Low Energy)功耗低,传输数据量小,传输距离较经典蓝牙远
蓝牙模块描述
单模蓝牙有一种蓝牙版本,运行一种蓝牙协议栈的模块,常用在低功耗蓝牙(Bluetooth Low Energy),如手环。
双模蓝牙内置两个蓝牙版本,运行两套协议栈的蓝牙模块,支持经典蓝牙与低功耗蓝牙,如手机。

权限声明

Android 11(API 30)及以下的Android版本,只需声明android.permission.BLUETOOTHandroid.permission.ACCESS_FINE_LOCATION,如果是Android 9(API 28)及以下的Android版本,则需要将android.permission.ACCESS_FINE_LOCATION更换为android.permission.ACCESS_COARSE_LOCATION。以下权限则是Android 12(API 31)及以上你可能会使用到的权限。

<!--  允许应用程序连接到配对的蓝牙设备  -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--  需要能够发现和配对附近的蓝牙设备  -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<!--  允许应用程序发现和配对蓝牙设备  -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--  需要能够连接到配对的蓝牙设备  -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<!--  允许应用程序在没有用户交互的情况下配对蓝牙设备,并允许或禁止电话簿访问或消息访问  -->
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
    tools:ignore="ProtectedPermissions" />
<!--  需要能够向附近的蓝牙设备做广告 Android 12 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>

<uses-permission android:name="com.google.android.things.permission.MANAGE_BLUETOOTH" />
<!--  获得定位  -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

这里展示了七个与蓝牙相关的权限,其中的android.permission.BLUETOOTH_SCANandroid.permission.BLUETOOTH_CONNECTandroid.permission.BLUETOOTH_ADVERTISEandroid.permission.ACCESS_FINE_LOCATION权限属于危险权限,需要另外写代码去动态申请。

蓝牙扫描

开始扫描

蓝牙扫描接收扫描结果使用BroadcastReceiver进行接收,而BroadcastReceiver需要写代码去触发,执行startDiscovery()扫描蓝牙前应加上registerReceiver(BroadcastReceiver receiver,IntentFilter filter)注册一个广播接收者,同时加上IntentFilter过滤掉那些用不到的intent,只取我们用得到的Intent

val filter = IntentFilter()
// 找到设备
filter.addAction(BluetoothDevice.ACTION_FOUND)
// 远程设备的绑定状态发生变化
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
// 第一次检索远程设备的友好名称,或自上次检索后更改
filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED)
// 远程设备的蓝牙类已更改
filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED)
// 用于在获取远程设备后将其UUID 作为ParcelUuid远程设备的包装进行广播
filter.addAction(BluetoothDevice.ACTION_UUID)
// 操作配对请求
filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST)
// 蓝牙状态改变
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
// 开始搜索蓝牙
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
// 蓝牙搜索完成
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
// 本地Adapter的蓝牙扫描模式发生了变化
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)
// 本地蓝牙适配器更改蓝牙名称
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)
// 请求本地蓝牙可被其它蓝牙扫描到
filter.addAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)
// 显示请求可发现模式的系统活动
filter.addAction(BluetoothAdapter.ACTION_REQUEST_ENABLE)
// 连接状态改变
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)

继承了BroadcastReceiver的类,实现其onReceive(Context context, Intent intent)方法,就可以在onReceive(Context context, Intent intent)里加上if语句去判断当前BroadcastReceiver是否接收到了上述的Action,当接收到IntentAction与上述IntentFilter.addAction(String action)相符,意味着是时候该执行与对应Action相关的操作了。

当识别到设备需要将其返回到Activity时,则可使用EventBus来进行传输。

执行上述操作后,当前手机开启了蓝牙,其它的蓝牙设备却扫描不到当前手机蓝牙时,也许是因为没有启用允许其它蓝牙发现当前手机蓝牙的功能(Android系统默认情况下无法扫描到当前手机蓝牙),关于这一点,应在扫描蓝牙前就加上允许其它蓝牙发现当前手机蓝牙的代码,如下:

val enabler = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)
startActivity(enabler)

执行代码,弹出申请是否允许其它设备发现本设备功能弹框,点击允许后,在接下来的120秒内(上限为300秒),其它的蓝牙可在规定时间内扫描到当前手机蓝牙。
在这里插入图片描述

取消扫描

取消蓝牙扫描时应先判断是否为null、是否正在扫描蓝牙后再取消扫描,同时注销掉广播。

if (bluetoothAdapter != null && bluetoothAdapter!!.isDiscovering) {
    bluetoothAdapter!!.cancelDiscovery()
    context.unregisterReceiver(bluetoothReceiver)
}

获取蓝牙信息

找到蓝牙设备后可得到一个任意类型T,将其转换为BluetoothDevice,就可以通过这一个类来获取蓝牙的相关信息,下图中使用到的方法如下:

MethodsDescribe
getName()获取蓝牙名称
getType()获取蓝牙类型
getBondState()获取蓝牙的绑定状态
getAddress()获取蓝牙设备的硬件地址
getUuids()返回远程设备支持的功能 (UUID)

其效果如下:
在这里插入图片描述

其它获取蓝牙相关信息方法见:BluetoothDevice

蓝牙配对

配对

蓝牙的配对使用BluetoothDevice.createBond()进行配对,createBond()有一个返回值,但千万不要以为他返回true意味着蓝牙配对成功,返回true只是意味着它开始申请配对,届时双方的蓝牙都会弹出如下对话框提示是否配对,此刻点击取消才是真正的取消配对,即配对失败。

在这里插入图片描述
部分蓝牙,如蓝牙耳机、部分手机蓝牙,配对成功后就直接连接上了,不需要再执行连接的操作。关于连接、数据传输的操作会在下一章进行讲解,博主暂时还缺乏能够进行数据传输的蓝牙设备,还请见谅。

取消配对

蓝牙配对与取消配对的方法createBond()removeBond()都在BluetoothDevice里面,但调用方式却有着天壤之别。

createBond()可通过BluetoothDevice类的实例直接进行调用,removeBond()通过BluetoothDevice实例来进行调用是行不通的,这一切的始作俑者,都是因为removeBond()@SystemApi注解导致的。

在这里插入图片描述
但这并不意味无法调用removeBond()方法,针对这种情况,可以使用反射来强制调用removeBond()方法,如下所示:

try {
     val method = BluetoothDevice::class.java.getMethod("removeBond")
     val b = method.invoke(device) as Boolean
 } catch (e: Exception) {
     e.printStackTrace()
 }

获取已配对蓝牙

获取已经配对的蓝牙设备,得拿到BluetoothAdapter类的实例,调用getBondedDevices()即可获得一个Set<BluetoothDevice>类型的已配对蓝牙数据。

val bondedDevices: Set<BluetoothDevice> get() = getBluetoothAdapter()!!.bondedDevices

在这里插入图片描述

最终效果

由于


注意事项:
1、低功耗蓝牙不能兼容(连接)经典蓝牙,只能兼容双模蓝牙、低功耗蓝牙。
2、BluetoothAdapter.getDefaultAdapter()方法在API 31 中已废弃,可使用BluetoothManager.getAdapter()代替。
3、本项目目前只做到蓝牙扫描与配对,数据的传输因缺少对应的蓝牙设备而暂时停滞,后期有相关设备后将会补上数据传输相关的文章。

点击前往下载源码

参考文档:
1、Android Bluetooth 连接
2、Android Developers —— Bluetooth overview(蓝牙概述)
3、Android Developers —— Bluetooth permissions(蓝牙权限)
4、Android Developers —— Manifest.permission(蓝牙清单权限)
5、Android Developers —— Find Bluetooth devices(查找蓝牙设备)
6、Android Developers —— Connect Bluetooth devices(连接蓝牙设备)

  • 19
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Android实现蓝牙连接和传输数据是一个常见的需求。下面是一些基本的步骤: 1. 确保你的设备支持蓝牙功能,并且已经开启蓝牙。 2. 在 AndroidManifest.xml 文件中添加蓝牙权限: ``` <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> ``` 3. 创建一个 BluetoothAdapter 对象,通过调用 getDefaultAdapter() 方法获取系统默认的蓝牙适配器: ``` BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); ``` 4. 检查蓝牙是否可用: ``` if (bluetoothAdapter == null) { // 设备不支持蓝牙 return; } if (!bluetoothAdapter.isEnabled()) { // 蓝牙未开启,可以通过调用 Intent 请求用户开启蓝牙 Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH); } ``` 5. 开始搜索设备并建立连接: ``` bluetoothAdapter.startDiscovery(); ``` 6. 注册 BroadcastReceiver 监听搜索到的设备: ``` BroadcastReceiver discoveryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 搜索到设备 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 连接设备 connectToDevice(device); } } }; IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(discoveryReceiver, filter); ``` 7. 连接到设备: ``` private void connectToDevice(BluetoothDevice device) { BluetoothSocket socket = null; try { // 创建蓝牙Socket socket = device.createRfcommSocketToServiceRecord(MY_UUID); // 连接 socket.connect(); // 开始传输数据 sendData(socket); } catch (IOException e) { e.printStackTrace(); } } ``` 8. 传输数据: ``` private void sendData(BluetoothSocket socket) throws IOException { // 获取输出流 OutputStream outputStream = socket.getOutputStream(); // 发送数据 String message = "Hello, Bluetooth!"; outputStream.write(message.getBytes()); } ``` 以上是一个简单的示例,涵盖了蓝牙连接和传输数据的基本步骤。你可以根据自己的需求进行扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宾有为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值