此处大致描述下目前涉及到的工作上的一块需求,公司有一款应用是PC端与安卓手机端进行交互的,原先采用的是串口线通讯的方式,每次使用都得插线而且有些几率是可能导致通讯失败(比如如果使用场景中如果出现大功率问题可能会导致传输途中的数据发生变化)。于是考虑使用蓝牙通讯方式进行交互。
此处介绍下蓝牙交互的俩种方式:1,安卓客户端作为客户端,PC客户端作为服务端;2,安卓客户端作为服务端,PC客户端作为客户端;
第一种方式的实现:
大致步骤:
1,安卓端打开蓝牙,扫描蓝牙,
2,提供一个蓝牙列表提供给用户进行选中对应蓝牙设备进行连接(这个列表包含第一步中扫描到的蓝牙与已经配对的蓝牙)
3,用户选中对应的蓝牙后,与PC客户端正式进行蓝牙的连接,通过蓝牙的输出流与读取流进行数据的交互
代码实现:
第一步:
//判断蓝牙是否打开,未打开则进行蓝牙打开操作
BluetoothAdapter mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
//判断蓝牙是否为打开状态
if (!mBluetoothAdapter.isEnabled()) {
//蓝牙未打开,进行蓝牙打开操作
mBluetoothAdapter.enable();
}
//蓝牙打开后,进行蓝牙扫描,针对扫描到的设备,这里通过广播的形式进行获取,代码步骤在第二步
mBluetoothAdapter.isDiscovering();
第二步:
//第一步中进行了蓝牙的扫描,通过广播的形式进行添加扫描到的蓝牙,下面是对应的广播类
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); //获取当前正在执行的动作...
//发现蓝牙设备
if (BluetoothDevice.ACTION_FOUND.equals(action)){
// 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//针对蓝牙设备进行一些过滤
if(device.getAddress().equalsIgnoreCase("00:00:00:00:00:01"))
return;
// 如果这个设备是不曾配对过的,添加到list列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED){
//同样的是针对扫描到的设备进行过滤,当原列表中不存在该设备且当前状态为正在扫描状态(isScan 可以在扫描的时候进行声明该变量,加这个操作主要是为了进行一些资源的释放)
if (!deviceList.contains(device) && isScan) {
//将最终过滤到最后的设备添加进扫描到的蓝牙列表中,如果是展示扫描成功的列表,此处在添加完设备后可以再进行对应的adapter.notifychanged进行刷新列表的数据
deviceList.add(device);
}
}
}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){//配对广播
//获取设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//终端进行配对的时候,会接收到总共俩次广播,第一次为配对开始,第二次为配对结束
//如果配对成功会被加入到系统的配对列表里,如果配对列表里有该设备则代表配对成功,反之失败
if(mBluetoothAdapter.getBondedDevices().contains(device)){
//配对成功
}
}
}
};
//上述为整个广播的内容,可以根据具体的业务需求或多或少的进行更改
//注册广播,注册广播的操作可以放在初始化中,或者开始蓝牙扫描前
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(mReceiver,filter);
//进行配对申请,这时候广播后续会开始收到广播,同时安卓端和pc端会同时显示一个码值提供确认进行配对
//这个device是BluetoothDevice,即扫描到的蓝牙列表中通过点击事件获取到的那一个
device.createBond();
第三步:
//如果配对成功或者选中的设备为已经配对过的,则开始进行连接,同样也需要涉及到一个广播
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); //获取当前正在执行的动作...
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getBondState() != BluetoothDevice.BOND_BONDED){//不是已配对设备不回调
return;
}
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) //连接上
{
//进行连接成功的操作,这里说下这个广播的一个问题:
//如果PC服务端没有开启端口,然后你又调用了连接的操作,会先收到一次连接上的广播,后面有收到了一次连接断开的广播,所以这个广播并不能实际上用于判断是否连接成功
}else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) //连接断开
{
//进行连接断开的一些操作,你可以考虑重连,或者直接提示给用户
}
}
};
//针对上述广播进行注册
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
context.registerReceiver(mReceiver,filter);
//正式的进行连接操作,该操作最好放在子线程中进行操作,这个UUID是一个默认的蓝牙串口UUID,基本上都可以用
BluetoothSocket
socket=device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//通过socket连接服务器,注意,这个connect是个阻塞过程,直到建立连接成功或者失败,所以判断是否连接成功在这里进行判断比较好,不要在广播中进行判断
socket.connect()
//代码如果走到这里则代表是连接成功了,可以进行一些连接成功的操作
log.d(“连接成功”)
//上述是获取到socket套接字,准备开始获取读取流进行获取PC端发送过来的数据,下面操作最好放在另一个线程中执行
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
try {
//打开读取流
mmInStream = socket.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
//开始不断获取数据
while (true) {
try {
if( (bytes = mmInStream.read(buffer)) > 0 )
{
byte[] buf_data = new byte[bytes];
for(int i=0; i<bytes; i++){
buf_data[i] = buffer[i];
}
//buf_data 就是本次获取到的数据
logger.info("【接收到】"+HexUtils.bytesToHexString(buf_data));
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
//发送数据,通过socket发送数据,数据的操作(发送和读取)都是byte[]字节数组的形式
if (socket == null || !isServiceConnected) {
//Toast.makeText(mContext, "没有可用的连接", Toast.LENGTH_SHORT).show();
logger.info("【发送数据失败】"+"没有可用的连接");
return false;
}
try {
OutputStream os = socket.getOutputStream();
os.write(data);
logger.info("【发送数据】"+ HexUtils.bytesToHexString(data));
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
第二种方式的实现:
大致步骤:
1,安卓端开启蓝牙,然后开启服务端开始获取数据
2,PC端开启蓝牙,连接终端蓝牙,然后开始发送数据
代码实现:
第一步
//实际上是和第一种方式的实现差不多的,只有一个地方需要替换下,就是创建蓝牙的socket的时候,代码如下
//原先使用的BluetoothSocket 更改为 BluetoothServerSocket
//这里插一句,如果安卓作为服务端而言的话,在电脑上的串口建立后,是会显示出你给服务器起的名字的
//具体打开串口的方式的话,电脑打开蓝牙-》蓝牙更多选项-》串口-》添加(传入或者传出)
BluetoothServerSocket mServerSocket=mBluetoothAdapter.listenUsingRfcommWithServiceRecord("你打算给服务器起的名字",UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//获取到socket后就开启接受客户端连接的流,同样是一个阻塞过程,直到建立一个连接或者连接失效
BluetoothSocket socket=mServerSocket.accept();
log.d(客户端已经连接上)
//获取到socket后,获取读取流进行读取数据,具体操作和第一种实现方式思路相同
InputStream mmInStream = socket.getInputStream();
//然后开始循环读取数据,此处不再重复代码拉
.....
//然后进行发送数据的形式也和第一种实现方式中的相同
OutputStream os = socket.getOutputStream();
os.write(data)
第二步
电脑上蓝牙进行连接,第一种和第二种实现方式都要对电脑上的蓝牙进行设备,具体步骤:打开电脑的蓝牙,进入更多蓝牙选项,查看蓝的属性,展现出来的框中会有一个com口的选择,这个com口需要进行设置,也可能你是自动填满了。具体一些操作可以参考这个链接https://blog.csdn.net/jkq10/article/details/42612559