一、配置权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 似乎android M需要位置权限才能扫描 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
二、添加依赖
implementation 'com.clj.fastble:FastBleLib:2.3.4'
三、蓝牙工具类
/**
* @anthor GrainRain
* @funcation 蓝牙4.0工具类
* @date 2020/11/10
*/
public class BluetoothUtil {
private BluetoothGatt bluetoothGatt;
private static BleDevice bleDevice = null;
private static Context context;
private static String serviceUUID;
private static String readUUID;
private static String writeUUID;
private static String mac; //要连接的设备MAC地址
private static boolean isShowDeviceDialog;
private static List<BleDevice> bleDeviceList;
private static ArrayAdapter adapter;
private static List<String> data;
private static OnBluetoothMessageListener onBluetoothMessageListener;
public BluetoothUtil() {
applyPermission();
initBluetooth();
if (isShowDeviceDialog) {
showBluetoothDeviceListDialog();
}
}
private void initBluetooth() {
BleManager.getInstance().init(((Activity) context).getApplication());
BleManager.getInstance()
.enableLog(true)
.setReConnectCount(1, 5000)
.setSplitWriteNum(200)
.setConnectOverTime(10000)
.setOperateTimeout(5000);
//打开蓝牙
if (!BleManager.getInstance().isBlueEnable()) {
BleManager.getInstance().enableBluetooth();
}
//配置扫描规则
BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
//.setDeviceMac(mac) // 只扫描指定mac的设备,可选
.setScanTimeOut(10000) // 扫描超时时间
.build();
BleManager.getInstance().initScanRule(scanRuleConfig);
//扫描蓝牙
BleManager.getInstance().scan(new BleScanCallback() {
@Override
public void onScanFinished(List<BleDevice> scanResultList) {
// Toast.makeText(context, "扫描结束", Toast.LENGTH_LONG).show();
}
@Override
public void onScanStarted(boolean success) {
Toast.makeText(context, "开始寻找蓝牙", Toast.LENGTH_LONG).show();
}
@Override
public void onScanning(BleDevice bleDevice) {
L.e(bleDevice.getName() + " " + bleDevice.getMac());
bleDeviceList.add(bleDevice);
listAddItem(bleDevice.getName() + " - " + bleDevice.getMac());
try {
//连接指定设备
if (!isShowDeviceDialog && mac != null && !mac.equals("")) {
if (bleDevice.getMac().equals(mac)) {
connect(bleDevice);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
//连接
private void connect(final BleDevice bleDevice) {
BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
@Override
public void onStartConnect() {
// 开始连接
L.e("开始连接");
}
@Override
public void onConnectFail(BleDevice bleDevice, BleException exception) {
// 扫描失败
}
@Override
public void onConnectSuccess(final BleDevice mBleDevice, BluetoothGatt gatt, int status) {
// 连接成功
L.e("连接成功");
Toast.makeText(context, "蓝牙已连接", Toast.LENGTH_SHORT).show();
bluetoothGatt = gatt;
BluetoothUtil.bleDevice = mBleDevice;
openNotification(mBleDevice);
//获取所有的Service和Characteristic的UUID
// List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
// for (BluetoothGattService service : serviceList) {
// uuidService = service.getUuid();
// L.e("dataAnalysis: " + uuid_service.toString());
// List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
// for (BluetoothGattCharacteristic characteristic : characteristicList) {
// uuidChara = characteristic.getUuid();
// L.e("c: " + uuid_chara.toString());
// }
}
@Override
public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status) {
Toast.makeText(context, "蓝牙连接中断", Toast.LENGTH_LONG).show();
}
});
}
//连接成功后打开通知,也就是用来接收来自蓝牙传输过来的内容
private static void openNotification(BleDevice bleDevice) {
BleManager.getInstance().notify(
bleDevice,
serviceUUID,
readUUID,
new BleNotifyCallback() {
@Override
public void onNotifySuccess() {
L.e("onNotifySuccess");
}
@Override
public void onNotifyFailure(final BleException exception) {
L.e("onNotifyFailure");
}
@Override
public void onCharacteristicChanged(byte[] data) {
//接收
L.e(ByteUtils.byteArrayToHexString(data, true));
if (onBluetoothMessageListener != null) {
onBluetoothMessageListener.onMessage(data);
}
}
});
}
//发送
public static void send(byte[] input) {
if (bleDevice != null) {
BleManager.getInstance().write(
bleDevice,
serviceUUID,
writeUUID,
input, null);
}
}
//显示蓝牙设备列表的dialog
private void showBluetoothDeviceListDialog() {
View view = ((Activity) context).getLayoutInflater().inflate(R.layout.list, null);
data = new ArrayList<>();
final AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(view)
.create();
ListView listView = view.findViewById(R.id.list_view);
adapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, data);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
L.e(data.get(position));
for (int i = 0; i < bleDeviceList.size(); i++) {
BleDevice bleDevice = bleDeviceList.get(i);
if (data.get(position).equals(bleDevice.getName() + " - " + bleDevice.getMac())) {
connect(bleDevice);
alertDialog.dismiss();
Toast.makeText(context, bleDevice.getName() + " - " + bleDevice.getMac(), Toast.LENGTH_SHORT).show();
}
}
}
});
alertDialog.show();
}
private static void listAddItem(String s) {
if (data == null) data = new ArrayList<>();
data.add(s);
if (adapter != null) adapter.notifyDataSetChanged();
}
//动态获取权限
private static void applyPermission() {
ActivityCompat.requestPermissions((Activity) context, new String[]{
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.WRITE_SETTINGS,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
}, 1);
}
public static final class Builder {
private String serviceUUID;
private String readUUID;
private String writeUUID;
private String mac;
private boolean showDeviceDialog;
private Context context;
private OnBluetoothMessageListener onBluetoothMessageListener;
public Builder() {
//数据初始化
isShowDeviceDialog = false;
mac = null;
bleDeviceList = new ArrayList<>();
}
public Builder setServiceUUID(String val) {
serviceUUID = val;
return this;
}
public Builder setReadUUID(String val) {
readUUID = val;
return this;
}
public Builder setWriteUUID(String val) {
writeUUID = val;
return this;
}
public Builder setContext(Context val) {
context = val;
return this;
}
public Builder setMAC(String val) {
mac = val;
return this;
}
public Builder isShowDeviceDialog(boolean val) {
showDeviceDialog = val;
return this;
}
public Builder setMessageListener(OnBluetoothMessageListener listener) {
onBluetoothMessageListener = listener;
return this;
}
public BluetoothUtil build() {
BluetoothUtil.context = context;
BluetoothUtil.mac = mac;
BluetoothUtil.serviceUUID = serviceUUID;
BluetoothUtil.readUUID = readUUID;
BluetoothUtil.writeUUID = writeUUID;
BluetoothUtil.isShowDeviceDialog = showDeviceDialog;
BluetoothUtil.onBluetoothMessageListener = onBluetoothMessageListener;
return new BluetoothUtil();
}
}
public interface OnBluetoothMessageListener {
void onMessage(byte[] bytes);
}
}
四、布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
五、使用
new BluetoothUtil.Builder()
.setContext(this)
.isShowDeviceDialog(false)
.setMAC("BA:95:A3:20:C8:12")
.setServiceUUID("d973f2e0-b19e-11e2-9e96-080020f29a66")
.setReadUUID("d973f2e1-b19e-11e2-9e96-9e08000c9a66")
.setWriteUUID("d973f2e2-b19e-11e2-9e96-0800200c9a66")
.setMessageListener(new BluetoothUtil.OnBluetoothMessageListener() {
@Override
public void onMessage(byte[] bytes) {
}
})
.build();