3、使用蓝牙之前,首先要检查当前手机是否支持蓝牙。如果支持蓝牙,检查手机蓝牙是否已开启。如果没有开启,则需要先打开蓝牙。打开手机蓝牙,有两种方式,推荐使用第二种打开方式。
private void initBluetooth() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter == null){
Toast.makeText(this, "当前手机设备不支持蓝牙", Toast.LENGTH_SHORT).show();
}else{
//手机设备支持蓝牙,判断蓝牙是否已开启
if(bluetoothAdapter.isEnabled()){
Toast.makeText(this, "手机蓝牙已开启", Toast.LENGTH_SHORT).show();
}else{
//蓝牙没有打开,去打开蓝牙。推荐使用第二种打开蓝牙方式
//第一种方式:直接打开手机蓝牙,没有任何提示
// bluetoothAdapter.enable(); //BLUETOOTH_ADMIN权限
//第二种方式:友好提示用户打开蓝牙
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
}
}
}
4、确保手机蓝牙已打开,就可以开始搜索设备。搜索设备只需调用startDiscovery()方法,但搜索的结果是通过广播来获取的,所以,还需要定义广播来获取搜索到的设备。
(1)搜索设备
private void searchBtDevice() {
if(bluetoothAdapter.isDiscovering()){ //当前正在搜索设备...
return;
}
//开始搜索
bluetoothAdapter.startDiscovery();
}
(2)自定义广播接收器,接收搜索到的设备。
/**
* 蓝牙广播接收器
*/
private static class BtBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_STARTED)) { //开启搜索
if (onDeviceSearchListener != null) {
onDeviceSearchListener.onDiscoveryStart(); //开启搜索回调
}
} else if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {//完成搜素
if (onDeviceSearchListener != null) {
onDeviceSearchListener.onDiscoveryStop(); //完成搜素回调
}
} else if (TextUtils.equals(action, BluetoothDevice.ACTION_FOUND)) { //3.0搜索到设备
//蓝牙设备
BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//信号强度
int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
Log.d(TAG, "扫描到设备:" + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
if (onDeviceSearchListener != null) {
onDeviceSearchListener.onDeviceFound(bluetoothDevice,rssi); //3.0搜素到设备回调
}
}
}
/**
* 蓝牙设备搜索监听者
* 1、开启搜索
* 2、完成搜索
* 3、搜索到设备
*/
public interface OnDeviceSearchListener {
void onDiscoveryStart(); //开启搜索
void onDiscoveryStop(); //完成搜索
void onDeviceFound(BluetoothDevice bluetoothDevice, int rssi); //搜索到设备
}
private OnDeviceSearchListener onDeviceSearchListener;
public void setOnDeviceSearchListener(OnDeviceSearchListener onDeviceSearchListener) {
this.OnDeviceSearchListener= onDeviceSearchListener;
}
}
(3)注册广播接收器
private void initBtBroadcast() {
//注册广播接收
btBroadcastReceiver = new BtBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); //开始扫描
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//搜索到设备
registerReceiver(btBroadcastReceiver,intentFilter);
}
(4)注册过广播之后,要记得在onDestroy()中注销广播
@Override
protected void onDestroy() {
super.onDestroy();
//注销广播接收
unregisterReceiver(btBroadcastReceiver);
}
5、搜索到目标设备之后,就可以与蓝牙设备建立连接。
(1)发起连接
/**
* 开始连接设备
* @param bluetoothDevice 蓝牙设备
* @param uuid 发起连接的UUID
* @param conOutTime 连接超时时间
*/
public void startConnectDevice(final BluetoothDevice bluetoothDevice, String uuid, long conOutTime){
if(bluetoothDevice == null){
Log.e(TAG,"startConnectDevice-->bluetoothDevice == null");
return;
}
if(bluetoothAdapter == null){
Log.e(TAG,"startConnectDevice-->bluetooth3Adapter == null");
return;
}
//发起连接
cOnnectThread= new ConnectThread(bluetoothAdapter,curBluetoothDevice,uuid);
connectThread.setOnBluetoothConnectListener(new ConnectThread.OnBluetoothConnectListener() {
@Override
public void onStartConn() {
Log.d(TAG,"startConnectDevice-->开始连接..." + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
}
@Override
public void onConnSuccess(BluetoothSocket bluetoothSocket) {
//移除连接超时
mHandler.removeCallbacks(connectOuttimeRunnable);
Log.d(TAG,"startConnectDevice-->移除连接超时");
Log.w(TAG,"startConnectDevice-->连接成功");
Message message = new Message();
message.what = CONNECT_SUCCESS;
mHandler.sendMessage(message);
//标记当前连接状态为true
curCOnnState= true;
//管理连接,收发数据
managerConnectSendReceiveData(bluetoothSocket);
}
@Override
public void onConnFailure(String errorMsg) {
Log.e(TAG,"startConnectDevice-->" + errorMsg);
Message message = new Message();
message.what = CONNECT_FAILURE;
mHandler.sendMessage(message);
//标记当前连接状态为false
curCOnnState= false;
//断开管理连接
clearConnectedThread();
}
});
connectThread.start();
//设置连接超时时间
mHandler.postDelayed(connectOuttimeRunnable,conOutTime);
}
//连接超时
private Runnable cOnnectOuttimeRunnable= new Runnable() {
@Override
public void run() {
Log.e(TAG,"startConnectDevice-->连接超时" );
Message message = new Message();
message.what = CONNECT_FAILURE;
mHandler.sendMessage(message);
//标记当前连接状态为false
curCOnnState= false;
//断开管理连接
clearConnectedThread();
}
};
(2)管理连接,数据收发
managerConnectSendReceiveData()方法中,connectedThread对象进行数据发送结果、接收结果监听。
/**
* 管理已建立的连接,收发数据
* @param bluetoothSocket 已建立的连接
*/
public void managerConnectSendReceiveData(BluetoothSocket bluetoothSocket){
//管理已有连接
cOnnectedThread= new ConnectedThread(bluetoothSocket);
connectedThread.start();
connectedThread.setOnSendReceiveDataListener(new ConnectedThread.OnSendReceiveDataListener() {
@Override
public void onSendDataSuccess(byte[] data) {
Log.w(TAG,"发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length));
Message message = new Message();
message.what = SEND_SUCCESS;
message.obj = "发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length);
mHandler.sendMessage(message);
}
@Override
public void onSendDataError(byte[] data,String errorMsg) {
Log.e(TAG,"发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length));
Message message = new Message();
message.what = SEND_FAILURE;
message.obj = "发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length);
mHandler.sendMessage(message);
}
@Override
public void onReceiveDataSuccess(byte[] buffer) {
Log.w(TAG,"成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length));
Message message = new Message();
message.what = RECEIVE_SUCCESS;
message.obj = "成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length);
mHandler.sendMessage(message);
}
@Override
public void onReceiveDataError(String errorMsg) {
Log.e(TAG,"接收数据出错:" + errorMsg);
Message message = new Message();
message.what = RECEIVE_FAILURE;
message.obj = "接收数据出错:" + errorMsg;
mHandler.sendMessage(message);
}
});
}
sendData()方法中,connectedThread对象发送数据。
/**
* 发送数据
* @param data 要发送的数据 字符串
* @param isHex 是否是16进制字符串
* @return true 发送成功 false 发送失败
*/
public boolean sendData(String data,boolean isHex){
if(cOnnectedThread== null){
Log.e(TAG,"sendData:string -->cOnnectedThread== null");
return false;
}
if(data == null || data.length() == 0){
Log.e(TAG,"sendData:string-->要发送的数据为空");
return false;
}
if(isHex){ //是16进制字符串
data.replace(" ",""); //取消空格
//检查16进制数据是否合法
if(data.length() % 2 != 0){
//不合法,最后一位自动填充0
String lasts = "0" + data.charAt(data.length() - 1);
data = data.substring(0,data.length() - 2) + lasts;
}
Log.d(TAG,"sendData:string -->准备写入:" + data); //加空格显示
return connectedThread.write(hexString2Bytes(data));
}
//普通字符串
Log.d(TAG,"sendData:string -->准备写入:" + data);
return connectedThread.write(data.getBytes());
}
6、与蓝牙设备通讯结束之后,可与蓝牙设备断开连接。
/**
* 断开已有的连接
*/
public void clearConnectedThread(){
Log.d(TAG,"clearConnectedThread-->即将断开");
//connectedThread断开已有连接
if(cOnnectedThread== null){
Log.e(TAG,"clearConnectedThread-->cOnnectedThread== null");
return;
}
connectedThread.terminalClose(connectThread);
//等待线程运行完后再断开
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
connectedThread.cancel(); //释放连接
cOnnectedThread= null;
}
},10);
Log.w(TAG,"clearConnectedThread-->成功断开连接");
Message message = new Message();
message.what = DISCONNECT_SUCCESS;
mHandler.sendMessage(message);
}
7、项目演示
(1)扫描到设备,点击“连接”按钮, 会在“搜索”按钮下方显示连接结果 。注意经典蓝牙连接是,第一次连接时会有弹出一个配对框,这个具体配对方式是蓝牙设备开发人员设置的。
(2)手机给蓝牙设备(设备名为:BTyqy)发送数据成功之后,蓝牙设备把接收到的数据再回发送给手机。
(3)断开连接。点击“断开”按钮, 会在“搜索”按钮下方显示断开结果 。
四、Demo案例源码地址:
注意:源码中没有进行位置权限的静态声明以及动态申请,小伙伴们使用时需要自己添加,谢谢!
CSDN:https://download.csdn.net/download/qq_38950819/11615060
码云:https://gitee.com/lilium_foliage/Android-Bluetooth