最近,公司有一个项目时关于手机蓝牙和硬件蓝牙相互通信的需求。基于之前很久没有学习硬件的知识,这次记录下来,以备下次需要时使用。
首先,需要搞清楚一些基本的概要,蓝牙3.0以前的是传统蓝牙,4.0以后的是低功耗蓝牙,Android蓝牙在不同手机系统版本也有不同的蓝牙,当然也有不一样的调用方法。android4.3(API18)版本以下的对应的是传统蓝牙,在扫描的时候等待时间会比较长。android4.3以上的是低功耗蓝牙,但是android4.3版本到5.0版本的调用方法和android5.0以上的调用方法是不一样的。android用传统的蓝牙连接方式是无法和低功耗蓝牙模块建立通信通道的,因为通信的协议是不一样的。低功耗蓝牙是用GATT这种属性传输协议,而传统蓝牙则是通过Socket的方式进行数据的传输。
android蓝牙权限在6.0以上增加了一个模糊定位的权限,不开启部分手机无法进行扫描蓝牙发出的广播。
蓝牙权限:
为了能够在你开发的应用设备中使用蓝牙功能,必须声明蓝牙的权限"BLUETOOTH"。在进行蓝牙的通信,例如请求连接,接受连接以及交换数据中,需要用到该权限。
<use-permission android:name="android.permission.BLUETOOTH"/>
如果你的应用程序需要实例化蓝牙设备的搜索或者对蓝牙的设置进行操作,那么必须声明BLUETOOTH_ADMIN权限。大多数应用需要该权限对本地的蓝牙设备进行搜索。该权限的其他能力并不应当被使用,除非你的应用是一个电源管理的应用,需要对蓝牙的设置进行修改
<use-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
android 6.0版本之后增加模糊定位授权,如果不增加这个权限部分6.0以上的手机无法扫描出蓝牙。
<use-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
开启关闭蓝牙:
在使用蓝牙通信之前,需要先开启,使用BluetoothAdapter来进行完成
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter ==null) {// Device does not support Bluetooth}
如果BluetoothAdapter为null值,则表示此手机不支持蓝牙功能。
if(!mBluetoothAdapter.isEnabled()){
Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
REQUEST_ENABLE_BT大于0的自己定义的int变量。isEnable()判断蓝牙是否可用。推荐使用这种方式进行开启蓝牙。
还有另一种方式开启,但是在部分手机不会弹出蓝牙的授权限页。
mBluetoothAdapter.enable()也能直接开启蓝牙。
搜索设备:
首先找到手机找出已匹配的蓝牙设备:
// 将已配对的设备添加到列表中
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mDevicesArray.add(device.getName() + "\n" + device.getAddress());
deviceList.add(device);
}
}
注册广播接收器并开启扫描:
IntentFilter filter = new IntentFilter();
//注册设备被发现时的广播
filter.addAction(BluetoothDevice.ACTION_FOUND);
//注册一个搜索结束时的广播
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
广播接收器:
public class BluetoothReceiver extends BroadcastReceiver {
public final String TAG = getClass().getName();
private BluetoothInterface bluetoothInterface;
private List<BluetoothDevice> beans = null;
public BluetoothReceiver(BluetoothInterface bluetoothInterface) {
this.bluetoothInterface = bluetoothInterface;
beans = new ArrayList<>();
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//发现蓝牙广播
if (action.equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
beans.add(device);
//显示已配对设备
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
} else if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
}
//搜索完成回调
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
bluetoothInterface.discoveryCompleted(beans);
}
}
}
只要搜索没有完成,会一直接收外部蓝牙设备发送的广播。如果找到了对应的蓝牙设备,可以取消搜索。
mBluetoothAdapter.cancelDiscovery();
匹配和连接蓝牙
匹配蓝牙
//MY_UUID是蓝牙串口服务对应的应用UUID,网上有说不能写在UI线程,但我写在UI线程也没问题
BluetoothSocket socket =device.createRfcommSocketToServiceRecord(MY_UUID);
连接蓝牙
public class ConnectedThread extends Thread {
private final BluetoothSocket mSocket;
private final InputStream mInStream;
private final OutputStream mOutStream;
private Handler mHandler;
public final static int MESSAGE_READ = 1;
public final static int MESSAGE_EXCEPTIONS = 2;
public final static int MESSAGE_SUCCESS = 3;
public ConnectedThread(BluetoothSocket socket, Handler handler) {
mSocket = socket;
mHandler = handler;
InputStream temIn = null;
OutputStream temOut = null;
try {
temIn = socket.getInputStream();
temOut = socket.getOutputStream();
} catch (IOException e) {
}
mInStream = temIn;
mOutStream = temOut;
}
@Override
public void run() {
try {
mSocket.connect();
mHandler.sendEmptyMessage(MESSAGE_SUCCESS);
} catch (IOException e) {
e.printStackTrace();
mHandler.sendEmptyMessage(MESSAGE_EXCEPTIONS);
try {
mSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
int bytes;
//对输入流保持监听直至一个异常发生
while (true) {
byte[] buffer = new byte[20];
try {
bytes = mInStream.read(buffer);
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/**
* 向蓝牙模块发射数据
*
* @param bytes
*/
public void write(byte[] bytes) {
try {
mOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 关闭Socket的连接
*/
public void cancel() {
try {
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
蓝牙在发送数据时有大小限制,一般为20字节,在6.0之后的版本可以进行设置大小。
如果有不正确的地方,可以在下面评论一起学习。
网友评论