这里跟大家分享一下 最近蓝牙中遇见的一些问题 以及蓝牙工作顺序 文章中有写的不好的欢迎大神吐槽 需要源码可以私 我么一起学习
蓝牙共分为扫描,配对,连接,通信 当然在扫描之前要做一些操作 判断是否支持蓝牙 以及蓝牙是否已开启 如果没有开启的话可以通过蓝牙适配器去打开
BluetoothAdapter mBluetoothAdapter =BluetoothAdapter.getDefaultAdapter();
蓝牙适配器是蓝牙的核心 Android中所有的蓝牙操作都在此适配器中 我们可以通过他去进行通信
通过判断 mBluetoothAdapter是否为空可以得到本机是否支持蓝牙
mBluetoothAdapter.isEnabled(); 蓝牙是否打开
扫描一般是通过广播去进行接收扫描到的结果的,可以如下设置
ScanBlueReceiver scanBlueReceiver = new ScanBlueReceiver(new ScanBlueCallBack());
IntentFilter filter1 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(scanBlueReceiver, filter1);
registerReceiver(scanBlueReceiver, filter2);
registerReceiver(scanBlueReceiver, filter3);
这样我们通过就广播监听了扫描结果 只需要在我们需求的点击事件或者合适的地方开启蓝牙扫描即可(扫描是异步操作 时间会长一些12s左右)
mBluetoothAdapter.startDiscovery();
4.扫描结束后下一步应该就要进行配对了 要注意的是配对的时候需要连接上蓝牙(之前有个问题卡了很久 每次都可以配对上 但是连不上)通过广播回调的BluetoothDevice也并没有发现连接与未连接之前有什么方法 广播的华主要监听一下(回调里面的方法pin是配对 如果没有我下面说出的问题可以不用管)
//创建广播 注册 配对请求和一个状态发生改变的广播
//配对接收
PinBlueReceiver pinBlueReceiver = new PinBlueReceiver(new PinBlueCallBack() {
@Override
public void onBondRequest() {
Log.d(TAG,"onBondRequest...");
}
@Override
public void onBondFail(BluetoothDevice device) {
pin(cnt ); }
@Override
public void onBonding(BluetoothDevice device) {}
@Override
public void onBondSuccess(BluetoothDevice device) {}
});
IntentFilter filter4 = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
IntentFilter filter5 = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(pinBlueReceiver, filter4);
registerReceiver(pinBlueReceiver, filter5);
//创建好广播 然后通过反射去配对
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
try {
Method createBondMethod = device.getClass().getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
returnValue.booleanValue();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(TAG, "attemp to bond fail!"); }
}
//到这里基本上就配对好了 但是到这里我在调试的时候会经常性的只配对不连接,这个问题卡了好久 通过返回的BluetoothDevice也没有找到什么方法 后来还是通过广播监听蓝牙的连接 断开连接 和发生变化(所以加上一个广播 直接onresume调用就行)
IntentFilter stateChangeFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
IntentFilter connectedFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
IntentFilter disConnectedFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(stateChangeReceiver, stateChangeFilter);
registerReceiver(stateChangeReceiver, connectedFilter);
registerReceiver(stateChangeReceiver, disConnectedFilter);
我们可以在这个广播中进行做出相应的处理
//连接状态广播接受者
private BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
Log.d(TAG,action+"...ACTION_ACL_CONNECTED");
//已连接
}
if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action) {
Log.d(TAG,action+"...ACTION_ACL_DISCONNECTED");
//断开
unpairDevice(cnt);//取消配对
}
if (BluetoothAdapter.ACTION_STATE_CHANGED == action) {
Log.d(TAG,action+"...ACTION_STATE_CHANGED");
//发生变化
unpairDevice(cnt); //取消配对
}
}
};
在这里把这个取消配对的给贴上 主要说一下什么时候取消配对。 蓝牙在连接的时候会经常性的支配对不连接 不管连接没连上没有什么状态改变
如果你在配对时加了配对上上就取消配对逻辑的话 第二次配对可能就配对不上 调试的时候也麻烦
首先说这个配对的广播他基本都是会走成功方法的(有无连接都是)如果是无连接情况就需要取消配对然后重新配对 在连接状态广播中也要去进行合适的取消配对和配对 总之没连上就取消让它不停的去连接只能连接上为止
//取消配对
private void unpairDevice(BluetoothDevice device) {
try {
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.setAccessible(true);
m.invoke(device, (Object[]) null);
pin(cnt);
} catch (Exception e) {
Log.e("ble",e.toString());
}
}
//连接之前把扫描关闭
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
连接需要通过一个BluetoothDevice对象 然后创建socket。socket去绑定上uuid然后和服务器进行连接
new Thread(new Runnable() {
@Override
public void run() {
try{
Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);
socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(ClassicsBluetooth.UUID));
if (socket != null && !socket.isConnected()){
socket.connect();
Log.d("芜湖芜湖",socket.isConnected()+"...连接");
}
}catch (IOException e){
Log.e(TAG,"socket连接失败");
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
Log.e(TAG,"socket关闭失败");
}
}
}
}).start();
到这里应该就打开spp了 我们就可以开始愉快的通信了
这里可以接收我们每次发送完指令返回的信息
//读取返回数据
public void readData(){
if (socket!=null){
new Thread(new Runnable() {
@Override
public void run() {
int length = 0;
String str;
byte[] buf = new byte[1024];
try {
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
while ((length = in.read(buf)) != -1) {
str = new String(buf, 0, length);
Message message = new Message();
message.obj=str;
message.what=1;
handler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
//返回信息 给到handler去展示
private Handler handler =new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what==1){
String str= (String) msg.obj;
Log.d(TAG,str+"。。。。。handler");
Toast.makeText(MainActivity.this, "..."+str, Toast.LENGTH_SHORT).show();
}
}
};
以上就是接收信息的代码 下面我把发送数据的代码贴上来
通过socket获取输出流发送 发送完调用读取方法拿回调信息
if (socket!=null){
new Thread(new Runnable() {
@Override
public void run() {
try {
OutputStream outputStream = socket.getOutputStream();
outputStream.write("MICOPEN".getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
readData(); //开启
}else {
Toast.makeText(MainActivity.this, "你还没有连接socket", Toast.LENGTH_SHORT).show();
}