Android 应用蓝牙连接通信实现
Android 应用蓝牙连接通信实现,主要包括如下步骤:
一.打开蓝牙
// 获取蓝牙适配器
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
1.判断蓝牙是否打开,
bluetoothAdapter.isEnabled()
2. 如果未打开,执行打开蓝牙,需要权限:Manifest.permission.BLUETOOTH
bluetoothAdapter.enable()
或者打开系统蓝牙设置界面让用户点击打开蓝牙。
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
二.搜索蓝牙设备列表,配对需要连接的设备
1.启动设备发现
bluetoothAdapter.startDiscovery()
2.注册广播监听发现到的蓝牙设备
如果发现蓝牙设备可以获取BluetoothDevice对象
// 注册广播接收器监听设备发现
private final BroadcastReceiver findDeviceReceiver = 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);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
Log.d("Bluetooth", "发现设备: " + device.getName() + " - " + device.getAddress());
// 添加到设备列表(如 RecyclerView)
}
}
};
// 注册广播监听附近蓝牙设备
//IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
//registerReceiver(findDeviceReceiver, filter);
3.配对
3.1 客户端设备(主动发起连接的设备)发起配对(系统自动处理弹窗)
device.createBond();
手机A系统弹窗显示配对码待用户点击确定,
3.2 服务端设备(等待连接的设备)处理配对
发起配对后,同时待连接蓝牙设备也会弹窗显示配对码待用户点击确定。
发起配对端和待连接蓝牙设备在配对界面点击确定后完成配对。如果超时未点击确定,会弹窗超时提醒。
这里可以 注册广播接收器监听ACTION_PAIRING_REQUEST来监听请求配对信息,该广播会在蓝牙配对时触发并携带设备信息。
ps:一般Android系统已经做了广播监听处理配对请求,无需用户自定义。
//广播监听蓝牙配对请求
BroadcastReceiver pairRequestReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_PIN) {
// 处理PIN码请求,可以调用startSystemPairDialog打开系统蓝牙配对弹窗
// 或者调用startUserPairDialog打开用户自定义蓝牙配对弹窗
}
}
}
};
// 注册广播监听配对请求
//IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
//registerReceiver(pairRequestReceiver, filter);
/**
* 打开系统蓝牙配对弹窗
* @param context
* @param device 通过action ACTION_PAIRING_REQUEST 获取到的请求配对的BluetoothDevice.
*/
private void startSystemPairDialog(Context context, BluetoothDevice device) {
Intent pairingIntent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
pairingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
context.startActivity(pairingIntent);
}
/**
* 打开用户自定义蓝牙配对弹窗,点击确定完成配对请求。
* @param context
* @param device
*/
private void startUserPairDialog(Context context, BluetoothDevice device) {
//todo 自定义弹窗 点击确定, 执行如下 调用setPin处理PIN码配对
try {
Method setPin = device.getClass().getMethod("setPin", byte[].class);
setPin.invoke(device, "1234".getBytes()); // 替换为设备预设的PIN码
Method createBond = device.getClass().getMethod("createBond");
createBond.invoke(device);
} catch (Exception e) {
e.printStackTrace();
}
}
3.3 如果是已经配对过,可获取已配对设备列表
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
String macAddress = device.getAddress(); // 获取已连接设备的MAC地址
}
三. 连接设备,数据通信
1. 客户端设备(主动发起连接的设备)创建RFCOMM Socket并连接 连接远程设备
//配对过后,创建RFCOMM Socket并连接到服务:使用UUID指定服务标识符,创建RFCOMM Socket并连接到远程设备。
/**
* 客户端设备(主动发起连接的设备)连接服务端获取 BluetoothSocket 和服务端socket数据通信
*
* @param context
* @param device
* @throws IOException
*/
private void clientConnect(Context context, BluetoothDevice device) throws IOException {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
socket.connect(); // 阻塞式连接
//连接之后就可以获取输入输出流进行 读写操作了
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
}
2.服务端设备(等待连接的设备)监听连接(BluetoothServerSocket)
连接之后就可以基于socket获取输入输出流进行 读写操作了。
/**
* 服务端设备(等待连接的设备)连接客户端后 获取BluetoothServerSocket 和客户端socket数据通信
*
* @param context
* @param device
* @throws IOException
*/
private void serverListen(Context context, BluetoothDevice device) throws IOException {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//name:字符串参数,表示服务的名称,这个名称会被写入设备的SDP(服务发现协议)数据库。
//uuid:UUID,用于标识服务,客户端和服务器必须使用相同的UUID才能建立连接。
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
BluetoothServerSocket serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("MyBluetoothApp", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
BluetoothSocket socket;
while (true) {
try {
socket = serverSocket.accept(); // 阻塞等待客户端连接
if (socket != null) {
// 连接成功,启动数据传输线程
//客户端连接之后就可以获取输入输出流进行 读写操作了
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
serverSocket.close();
break;
}
} catch (IOException e) {
Log.e("Bluetooth", "ServerSocket异常", e);
break;
}
}
}