Android 使用经典蓝牙
Android 使用经典蓝牙
本文内容基本是按照安卓官方文档来进行经典蓝牙的学习,大体都从官方文档粘贴而来,英文部分做了写粗略的翻译,作为自己学习安卓经典蓝牙的一个记录。官方文档可参考https://developer.android.com/guide/topics/connectivity/bluetooth.html
基础知识
Android Bluetooth基础类、API,包含在android.bluetooth包下
- BluetoothAdaper 表示本地蓝牙适配器,是所有蓝牙交互的入口点,
BluetoothAdapter
是所有蓝牙交互的入口点。 利用它可以发现其他蓝牙设备,查询绑定(配对)设备的列表,使用已知的 MAC 地址实例化BluetoothDevice
,以及创建BluetoothServerSocket
以侦听来自其他设备的通信。 - BluetoothDevice 表示远程蓝牙设备。利用它可以通过
BluetoothSocket
请求与某个远程设备建立连接,或查询有关该设备的信息,例如设备的名称、地址、类和绑定状态等。 - BluetoothSocket 表示蓝牙套接字接口(与 TCP
Socket
相似)。这是允许应用通过 InputStream 和 OutputStream 与其他蓝牙设备交换数据的连接点。 - BluetoothServerSocket 表示用于侦听传入请求的开放服务器套接字(类似于 TCP
ServerSocket
)。 要连接两台 Android 设备,其中一台设备必须使用此类开放一个服务器套接字。 当一台远程蓝牙设备向此设备发出连接请求时,BluetoothServerSocket
将会在接受连接后返回已连接的BluetoothSocket
。 - BluetoothClass 描述蓝牙设备的一般特征和功能。 这是一组只读属性,用于定义设备的主要和次要设备类及其服务。 不过,它不能可靠地描述设备支持的所有蓝牙配置文件和服务,而是适合作为设备类型提示
- BluetoothProfile 表示蓝牙配置文件的接口。 蓝牙配置文件是适用于设备间蓝牙通信的无线接口规范。 免提配置文件便是一个示例。 如需了解有关配置文件的详细讨论,请参阅使用配置文件
使用蓝牙
获取蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
设置蓝牙
获取BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) {// 若为Null,则说明不支持蓝牙,在这里做出相应处理 }
启用蓝牙
if (!mBluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
若蓝牙为启用,则将显示对话框,请求用户允许启用蓝牙
查找蓝牙
查询配对的设备:在执行设备发现之前,有必要查询已配对的设备及,故使用getBondedDevices()方法,其返回一组已配对的BluetoothDevice
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // 如果有配对的设备 if (pairedDevices.size() > 0) {// 遍历匹配设备组for (BluetoothDevice device : pairedDevices) {// 将已配对设备的名称及地址存储在一个ArrayAdapter中mArrayAdapter.add(device.getName() + "\n" + device.getAddress());} }
发现设备:要开始发现设备,只需调用
startDiscovery()
。该进程为异步进程,并且该方法会立即返回一个布尔值,指示是否已成功启动发现操作。 发现进程通常包含约 12 秒钟的查询扫描,之后对每台发现的设备进行页面扫描,以检索其蓝牙名称。您的应用必须针对ACTION_FOUND
Intent 注册一个 BroadcastReceiver,以便接收每台发现的设备的相关信息。 针对每台设备,系统将会广播ACTION_FOUND
Intent。此 Intent 将携带额外字段EXTRA_DEVICE
和EXTRA_CLASS
,二者分别包含BluetoothDevice
和BluetoothClass
。 例如,下面说明了在发现设备时如何注册以处理广播。// 为 ACTION_FOUND 创建一个广播接收器 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();//当发现一个蓝牙设备时if (BluetoothDevice.ACTION_FOUND.equals(action)) {//利用EXTRA_DEVICE字段, 从intent中获取该设备实例BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 使用getName和getAddress方法获取蓝牙设备名和地址mArrayAdapter.add(device.getName() + "\n" + device.getAddress());}} }; //注册该广播 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); //搜索完成 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter); // 要在onDestry方法中取消注册该广播
//取消注册该广播 @Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(mBtFoundReceiver);}
启用本地可检测性(可选)
如果您希望将本地设备设为可被其他设备检测到,请使用
ACTION_REQUEST_DISCOVERABLE
操作 Intent 调用startActivityForResult(Intent, int)
。 这将通过系统设置发出启用可检测到模式的请求(无需停止您的应用)。 默认情况下,设备将变为可检测到并持续 120 秒钟。 您可以通过添加EXTRA_DISCOVERABLE_DURATION
Intent Extra 来定义不同的持续时间。 应用可以设置的最大持续时间为 3600 秒,值为 0 则表示设备始终可检测到。 任何小于 0 或大于 3600 的值都会自动设为 120 秒。//设置持续时间为300秒 Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent);
上述操作将显示对话框,请求用户允许设备设为可检测到,若同意,则您的 Activity 将会收到对
onActivityResult())
回调的调用,其结果代码等于设备可检测到的持续时间。 如果用户响应“No”或出现错误,结果代码将为RESULT_CANCELED
。如果设备尚未启用蓝牙,则在启用设备可检测性将会自动启用蓝牙。仅当您希望您的应用托管将用于接受传入连接的服务器套接字时,才有必要启用可检测性,因为远程设备必须能够发现该设备,然后才能发起连接。
连接设备
要在两台设备上的应用之间创建连接,必须同时实现服务器端和客户端机制,因为其中一台设备必须开放服务器套接字,而另一台设备必须发起连接(使用服务器设备的 MAC 地址发起连接)。 当服务器和客户端在同一 RFCOMM 通道上分别拥有已连接的 BluetoothSocket
时,二者将被视为彼此连接。 这种情况下,每台设备都能获得输入和输出流式传输,并且可以开始传输数据,在有关管理连接的部分将会讨论这一主题。 本部分介绍如何在两台设备之间发起连接。
连接为服务器
当您需要连接两台设备时,其中一台设备必须通过保持开放的 BluetoothServerSocket
来充当服务器。 服务器套接字的用途是侦听传入的连接请求,并在接受一个请求后提供已连接的 BluetoothSocket
。 从 BluetoothServerSocket
获取 BluetoothSocket
后,可以(并且应该)舍弃 BluetoothServerSocket
,除非您需要接受更多连接。
基本流程
通过调用
listenUsingRfcommWithServiceRecord(String, UUID)
获取BluetoothServerSocket
。- UUID: 通用唯一标识符,是用于唯一标识信息的字符串ID的128为标准化格式
- UUID将作为与客户端设备连接协议的基础,即当客户端尝试连接此设备时,他会携带一个想要连接的服务的UUID,两个UUID必须匹配
调用accept()开始侦听连接请求,操作成功,accept将返回已连接的BluetoothSocket
调用
close()
。这将释放服务器套接字及其所有资源,但不会关闭accept()
所返回的已连接的BluetoothSocket
注意:accept()不应再主Activity UI线程中执行,因为它是阻塞调用。应开启一个新线程,使用
BluetoothServerSocket
或BluetoothSocket
完成所有工作。要终止accept()
等被阻塞的调用,请通过另一个线程在BluetoothServerSocket
(或BluetoothSocket
)上调用close()
,被阻塞的调用将会立即返回//一个用于接受传入连接的服务器组件的简化线程 private class AcceptThread extends Thread {private final BluetoothServerSocket mmServerSocket;public AcceptThread() {// 使用一个临时变量,之后再将它赋值给mmServerSocket,因为mmServerSocket是一个final变量BluetoothServerSocket tmp = null;try {// MY_UUID是此应用的UUID串,同时也被客户端使用tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) { }//赋值mmServerSocket = tmp;}public void run() {BluetoothSocket socket = null;// 持续侦听直到返回了一个socket或者发生异常while (true) {try {socket = mmServerSocket.accept();} catch (IOException e) {break;}// 连接建立成功if (socket != null) {// 在一个单独的线程中管理连接,manageConnectedSocket为虚构的方法,它将启动用于传输数据的线程manageConnectedSocket(socket);mmServerSocket.close();break;}}}/** 将取消侦听socket,并使进程关闭 */public void cancel() {try {mmServerSocket.close();} catch (IOException e) { }} }
连接为客户端
要发起与远程设备(保持开放的服务器套接字的设备)的连接,必须首先获取表示该远程设备的 BluetoothDevice
对象。(在前面有关查找设备的部分介绍了如何获取 BluetoothDevice
)。 然后必须使用 BluetoothDevice
来获取 BluetoothSocket
并发起连接。
基本过程
使用
BluetoothDevice
,通过调用createRfcommSocketToServiceRecord(UUID)
获取BluetoothSocket
。此处使用的UUID必须与服务器设备在使用listenUsingRfcommWithServiceRecord(String, UUID)
开放其BluetoothServerSocket
时所用的 UUID 相匹配。 要使用相同的 UUID,只需将该 UUID 字符串以硬编码方式编入应用,然后通过服务器代码和客户端代码引用该字符串。通过connect()发起连接。执行此调用时,系统将会在远程设备上执行 SDP 查找,以便匹配 UUID。 如果查找成功并且远程设备接受了该连接,它将共享 RFCOMM 通道以便在连接期间使用,并且
connect()
将会返回。 此方法为阻塞调用。 如果由于任何原因连接失败或connect()
方法超时(大约 12 秒之后),它将会引发异常。由于
connect()
为阻塞调用,因此该连接过程应始终在主 Activity 线程以外的线程中执行注意:注:在调用
connect()
时,应始终确保设备未在执行设备发现。 如果正在进行发现操作,则会大幅降低连接尝试的速度,并增加连接失败的可能性。//发起蓝牙连接的线程的基本示例 private class ConnectThread extends Thread {private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {// Use a temporary object that is later assigned to mmSocket,// because mmSocket is finalBluetoothSocket tmp = null;mmDevice = device;// Get a BluetoothSocket to connect with the given BluetoothDevicetry {// MY_UUID is the app's UUID string, also used by the server codetmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) { }mmSocket = tmp;}public void run() {// Cancel discovery because it will slow down the connectionmBluetoothAdapter.cancelDiscovery();try {// Connect the device through the socket. This will block// until it succeeds or throws an exceptionmmSocket.connect();} catch (IOException connectException) {// Unable to connect; close the socket and get outtry {mmSocket.close();} catch (IOException closeException) { }return;}// Do work to manage the connection (in a separate thread)manageConnectedSocket(mmSocket);}/** Will cancel an in-progress connection, and close the socket */public void cancel() {try {mmSocket.close();} catch (IOException e) { }} }
管理连接
- 获取
InputStream
和OutputStream
,二者分别通过套接字以及getInputStream()
和getOutputStream()
来处理数据传输。 - 使用
read(byte[])
和write(byte[])
读取数据并写入到流式传输。
//传输内容示例
private class ConnectedThread extends Thread {private final BluetoothSocket mmSocket;private final InputStream mmInStream;private final OutputStream mmOutStream;public ConnectedThread(BluetoothSocket socket) {//获取socket及输入输出流mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut = null;try {tmpIn = socket.getInputStream();tmpOut = socket.getOutputStream();} catch (IOException e) { }mmInStream = tmpIn;mmOutStream = tmpOut;}public void run() {byte[] buffer = new byte[1024]; int bytes; 获取read()返回的数据// 持续侦听输入流,知道发生异常while (true) {try {从输入流中读取数据bytes = mmInStream.read(buffer);// 将包含的字节流发送到UI activitymHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();} catch (IOException e) {break;}}}/* 在主Activity调用此方法,用以向远程设备发送数据 */public void write(byte[] bytes) {try {mmOutStream.write(bytes);} catch (IOException e) { }}/* 在主activity调用此方法用以关闭连接*/public void cancel() {try {mmSocket.close();} catch (IOException e) { }}
}
Android 使用经典蓝牙相关推荐
- 基于Android Studio经典蓝牙APP---继上一次的完善版
基于Android Studio经典蓝牙APP-继上一次的完善版 考虑到好友网友们反馈的问题总结了以下几点: 1.工程下载爆红:版本问题-gradle:4.1.1. 2.无接收数据功能,怎么实现:这里 ...
- android ble 经典蓝牙,Android 经典蓝牙(Classic Bluetooth)和低功耗蓝牙(BLE)
[实例简介] 从蓝牙4.0开始包含两个蓝牙芯片模块:传统/经典蓝牙模块(Classic Bluetooth,简称BT)和低功耗蓝牙(Bluetooth Low Energy,简称BLE) 经典蓝牙是在 ...
- Android笔记---蓝牙开发经典蓝牙和低功耗蓝牙
目录 前言 一般开发步骤 相关API介绍 一.通用API 1.BluetoothAdapter 2.BluetoothDevice 二.经典蓝牙(BT)API 1.BluetoothSocket 2. ...
- Android经典蓝牙开发简介(Google官网译文)
公司的项目最近需要用到蓝牙开发的相关内容,因此特地查阅了Google官方文档的内容并进行二次整理,希望能对需要学习该部分的朋友有所帮助. 原文地址:http://developer.android.c ...
- 【Android】蓝牙开发——经典蓝牙:配对与解除配对 实现配对或连接时不弹出配对框
目录 一.配对方法 二.解除配对方法 三.配对/解除配对结果 四.justwork配对模式下,不弹出配对框 五.pincode配对模式下,不弹出配对框 六.小结 在之前的文章[Android]蓝牙开发 ...
- Android蓝牙开发前序知识-经典蓝牙低功耗蓝牙区别
最近从网上搜了(抄了)一些经典蓝牙和低功耗蓝牙的区别.关于蓝牙的大概了解,前文已经描述过了. Android中的蓝牙 说到Android中的蓝牙,大家听到的可能有蓝牙1.0.蓝牙2.0.蓝牙3.0.蓝 ...
- Android蓝牙开发—经典蓝牙和BLE(低功耗)蓝牙的区别
找到一篇介紹BT与BLE使用差别的文章, 写的很清晰,看完基本明白了 ----------------------------------------------------------------- ...
- Android蓝牙开发 — 经典蓝牙BLE蓝牙
一,前期基础知识储备 1)蓝牙是一种支持设备之间短距离通信的无线电技术(其他还包括红外,WIFI): 支持移动电话.笔记本电脑.无线耳机等设备之间进行信息的交换: Android支持的蓝牙协议栈:Bl ...
- Android蓝牙开发—经典蓝牙详细开发流程
文章目录 开发流程 权限 核心API BlueToothAdapter getDefaultAdapter():获取BluetoothAdapter对象 判断设备是否支持蓝牙 判断蓝牙是否开启 get ...
最新文章
- couchdb 自动生成html,如何在CouchDB中使用html模板
- mysql缓存 碎片_Mysql查询缓存碎片、缓存命中率及Nagios监控
- Win10最常用的快捷键,效率Max提高100%(常用的应该是最全的)
- 小米10至尊纪念版DXO第一 雷军:这是小米打拼三年第二次登顶
- 8g ubuntu 树莓派4b_树莓派4B如何安装ubuntu20.04
- 文字处理技术:最小布局
- 抗光幕布哪个牌子好?
- 自己写的vue图片上传插件(假装是插件)
- 22071班华清远见(上海中心)
- ffmpeg C++推流
- pandas数据处理基础之标准化与标签数值化
- 【Python】使用pandas_datareader获取股票信息并进行可视化分析
- 黑帽seo 模板生成php,全自动无限生成关键词页面(黑帽SEO优化终极方法)
- Crazy Learning for Day 7
- 气象绘图中出现白条该如何解决
- ubnt 配置软件 android,Ubnt EdgeRouter 路由器中国移动原生IPv6配置
- 2021祥云杯部分pwn
- 发帖需要验证手机-解决办法
- 滴滴如何调度_滴滴调度小助手和热力图是司机的陷阱还是馅饼?
- 怎样记住Integer的最大值(有趣的思维和搞笑的回答)