关于传统蓝牙
传统蓝牙这个概念其实不用细说,相信很多人还对蓝牙配对码这个东西有印象,现在大部分都进行ble开发了,而且传统蓝牙不支持与ios互传数据
这里主要讲解思路和概念,和小白扫盲,我当初公司做蓝牙的时候,对蓝牙整体的概念就比较懵,以为ble就是传统蓝牙,后来查阅资料多了,才逐渐分清和了解二者代码开发
本人demo地址,这个demo主要以做实验为主,有多连接,自动配对,通信,所以代码不是特别适合新手看,嘿嘿,主要是懒,所有想实验的功能都是在基本代码上直接加上去的,所以你懂得~
github上demo地址
蓝牙通信
本质还是socket通信
- 服务端启动监听
- 客户端请求
- 连接确认
蓝牙通信两边的 UUID 必须是一样的,这是一个服务的唯一标识,而且这个 UUID 的值必须是 00001101-0000-1000-8000-00805F9B34FB。
为什么呢?因为这个是 Android 的 API 上面说明的,用于普通蓝牙适配器和 Android 手机蓝牙模块连接的,请大家自己看一下 Android 有关 bluetooth的 API。
主要涉及四个类
BluetoothAdapter
这个类代表蓝牙适配器,并且是所有蓝牙交互的入口点,通过这个类,我们可以发现其他的蓝牙设备,并且打开蓝牙功能等;BluetoothDevice
代表一个蓝牙设备,可以通过该类活设备名称、设备地址、配对状态等。BluetoothSocket
socket连接的管理类,可以获取并通过InputStream OutputStream与另一个蓝牙设备交换数据BluetoothServerSocket
是一个开放的服务器套接字,侦听传入请求(类似于一个TCP ServerSocket);
为了连接两个Android设备,设备必须用这个类打开一个服务器套接字;
当一个远程蓝牙设备请求连接到这个设备,如果请求的连接被接受,那么BluetoothServerSocket将返回一个已经连接的BluetoothSocket对象。
以上较官方的解释,其实熟悉socket开发的应该知道,socket就是C/S的开发模式,所以需要一个服务端来监听连接也就是accept
蓝牙基本操作
打开蓝牙
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null){
Log.d(TAG,"设备蓝牙无法使用");
return;
}
if (!mBluetoothAdapter.isEnabled()){
//若没打开则打开蓝牙
mBluetoothAdapter.enable();
}
使设备可以被周围的设备搜索到
Intent intentDiscov = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 让当前蓝牙设备可见,默认值为120秒,超过300秒的请求将被限制
intentDiscov.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mDiscoverableTime);
((Activity)mContext).startActivityForResult(intentDiscov, RESULT_DISCOVERABLE);
客户端蓝牙连接及通信
注册广播,展示搜索到的设备,用户选择点击获取设备的mac地址和设备名称,使用mac地址连接
简单说就是,发现->配对->连接
这个代码就不在这里展示了,直接看demo吧
通过蓝牙地址获取远程设备对象
mDevice = mBluetoothAdapter.getRemoteDevice(mBlueToothAddress);
客户端线程中连接socket
mClientThread = new ClientThread();
mClientThread.start();
使用设备对象和uuid获取socket对象,并连接,出现io异常呢个就说明连接失败
mClientSocket = mDevice.createRfcommSocketToServiceRecord(mUuid);
mClientSocket.connect();
// 启动接收数据
mReadThread = new ReadThread(mClientSocket);
mReadThread.start();
客户端接收线程中
inputStream = socket.getInputStream();
while (true) {
if ((bytes = inputStream.read(buffer)) > 0) {
byte[] bufData = new byte[bytes];
for (int i = 0; i < bytes; i++) {
bufData[i] = buffer[i];
}
String msg = new String(bufData);
//发送给界面更新UI
sendHandlerMsg(MESSAGE, msg);
}
}
客户端发消息
发消息就是socket获取输出流
// 判断socket是服务器获得的还是客户端获得的
if (null != mServerSocket) {
outputStream = mServerSocket.getOutputStream();
outputStream.write(message.getBytes());
}
关闭客户端线程和流
private void shutdownClient() {
Log.e(TAG, "shutdownClient()");
if (mClientThread != null) {
mClientThread.interrupt();
mClientThread = null;
}
if (mReadThread != null) {
mReadThread.interrupt();
mReadThread = null;
}
if (mClientSocket != null) {
try {
mClientSocket.close();
mClientSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
蓝牙自动连接
将你的设备设置成默认密码,如0000或1111,或者无密码
就是在广播搜索到你的设备时,主动连接,并且屏蔽广播,使用默认的密码或者无配对码
搜索设备名,如果mac地址可以预知,直接连mac地址比较好
ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
abortBroadcast();
服务端蓝牙连接代码
初始化蓝牙对象及使设备可被发现,直接启动线程
线程中直接监听客户端的连接
PROTOCOL_SCHEME_RFCOMM是常量随便设置
mBluetoothServer =
mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM, mUuid);
获取socket对象,并启动接收数据的线程即可,代码同客户端
if (mServerSocket == null) {
mServerSocket = mBluetoothServer.accept();
// 启动接受数据
mReadThread = new ReadThread(mServerSocket);
mReadThread.start();
}
蓝牙服务端一对多通信
蓝牙服务端一对多通信,就是监听到连接时,再获取一个socket
if (mServerSocket == null) {
mServerSocket = mBluetoothServer.accept();
// 启动接受数据
mReadThread = new ReadThread(mServerSocket);
mReadThread.start();
}
if (mSeverSocketTwo == null) {
mSeverSocketTwo = mBluetoothServer.accept();
// 启动接受数据
mReadThreadTwo = new ReadThread(mSeverSocketTwo);
mReadThreadTwo.start();
}
在接收发送数据时,同时操作两个socket对象即可,释放也需要都释放掉
蓝牙客户端一对多通信
客户端一对多与服务端一对多类似创建多个socket,多读收数据的线程