前言
目前比较通用的蓝牙类型主要有两种,一种为手机端使用的经典蓝牙3.0,一种是当前比较流行在穿戴设备上的低功耗蓝牙,即常说的BLE蓝牙。关于BLE蓝牙开发可以查看另外一篇文章
安卓BLE蓝牙开发详解。
经典蓝牙采用服务器客户端模式进行通信,手机端既可以是服务端也可以是客户端。
安卓手机经典蓝牙开发通信流程如下:
添加权限
<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
为适配安卓6.0以及以上版本需要添加一个模糊定位的权限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
打开蓝牙
// 询问打开蓝牙
if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
// 申请打开蓝牙回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "蓝牙已经开启", Toast.LENGTH_SHORT).show();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "没有蓝牙权限", Toast.LENGTH_SHORT).show();
finish();
}
}
}
BluetoothAdapter类封装了关于安卓系统蓝牙的操作。其获取方式为:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// 设备不支持蓝牙
}
搜索蓝牙设备
安卓对于经典蓝牙的搜索采用注册广播的方式实现。
// 注册扫描监听器,一般写在onCreate()函数中执行
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(searchReceiver, filter);
// 监听器监听蓝牙扫描结果
BroadcastReceiver searchReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
if (device.getName() == null) {
return;
}
if(device.getName().equals("目标设备蓝牙名")) {
targetDevice = device;
}
}
}
}
};
//启动搜索周边设备
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
注:当注册广播后需要在销毁界面时调用unregisterReceiver(searchReceiver);解除注册防止内存泄露。
连接设备
当在广播监听结果中获取到目标设备之后,进行连接设备。安卓启动连接的方式通常需启动服务端线程作为监听,然后创建客户端线程进行连接。连接方法如下:
//启动蓝牙连接
public void connect(BluetoothDevice targetDevice) {
this.targetDevice = targetDevice;
//启动服务端线程
serverThread = new ServerThread();
serverThread.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//启动客户端线程
clientThread = new ClientThread();
clientThread.start();
}
// 服务端线程
private class ServerThread extends Thread {
public void run() {
try {
// 创建一个蓝牙服务器 参数分别:服务器名称、UUID
mserverSocket = mBluetoothAdapter
.listenUsingRfcommWithServiceRecord(
"btspp",
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
// 接受客户端的连接请求
socket = mserverSocket.accept();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 客户端线程
private class ClientThread extends Thread {
public void run() {
try {
Thread.sleep(500);
socket = targetDevice.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//开始连接
socket.connect();
//连接成功后,启动数据通信线程
isReading = true;
new ReadThread().start();
} catch (Exception e) {
}
}
}
通信过程
安卓经典蓝牙的通信采用Socket通信机制。Socket通信线程如下:
private class ReadThread extends Thread {
public void run() {
Log.e("TAG", "开启通信线程");
byte[] buffer = new byte[1024];
int bytes;
in = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (Exception e) {
Log.e("TAG", "获取流出错");
}
while (isReading) {
try {
if ((bytes = in.read(buffer)) > 0) {
//读取到的数据值
byte[] rece = new byte[bytes];
}
} catch (Exception e) {
e.printStackTrace();
try {
Log.e("关闭流", "");
in.close();
} catch (Exception e2) {
e2.printStackTrace();
}
break;
}
}
Log.e(TAG, "DataRead线程关闭");
}
}
Socket通信线程在没有断开连接之前一直在Socket流中读取数据。通常在与设备通信过程中不仅要读取设备数据,同时需要向设备写入数据,发送数据的方法如下:
//发送数据方法
public void sendData(byte[] cmd) {
if (out != null) {
try {
out.write(cmd);
} catch (IOException e) {
Log.e(TAG, "写入失败");
e.printStackTrace();
}
}else {
Log.e(TAG, "建立连接失败");
}
}
结语
通过以上流程可以基本完成与经典蓝牙设备的通信过程。本文采用的是手机端作为服务端,周边蓝牙设备作为客户端的方式。若文章中存在错误,还请指出。