Androidx
implementation 'androidx.bluetooth:bluetooth:1.0.0-alpha02'
扫描
init {
bluetoothLe = BluetoothLe(context)
}
@SuppressLint("MissingPermission")
suspend fun scan(
deviceName: String,
uuid: UUID?,
getBleDev: (scanResult: ScanResult) -> Unit
) {
bluetoothLe?.scan(
listOf(
ScanFilter(
serviceDataUuid = uuid,
deviceName = deviceName
)
)
)?.apply {
catch { e -> println("An error occurred: $e") }
collect { data ->
getBleDev(data)
}
} ?: {
println("scan flow null")
}
}
Gatt 连接
@SuppressLint("MissingPermission", "RestrictedApi")
suspend fun gattCon(
writeChannel: Channel<ByteArray>,
resultWrite: (datas: ByteArray) -> Unit
): Any {
BluetoothAdapter.getDefaultAdapter().bondedDevices.forEach {
println("bondedDevices:${it.name}")
if (it.bondState == BOND_BONDED) {
val xBleDevice = BluetoothDevice(it)
try {
return connect(xBleDevice, resultWrite, writeChannel)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
return 0
}
@SuppressLint("MissingPermission")
private suspend fun connect(
bluetoothDevice: BluetoothDevice,
resultWrite: (datas: ByteArray) -> Unit,
writeChannel: Channel<ByteArray>
) = bluetoothLe?.connectGatt(device = bluetoothDevice) {
services.forEach {
println("services ${it.uuid}")
if (it.uuid == v3Map.first) {
gattService = it
map = v3Map
return@forEach
} else if (it.uuid == hidMap.first) {
gattService = it
map = hidMap
return@forEach
}
}
val fwService = getService(CHARACTER_DEVICEINFO_UUID)
fwService?.let {
val characteristic = it.getCharacteristic(CHARACTER_FIRMWARE_UUID)
characteristic?.apply {
val result = readCharacteristic(this)
if (result.isSuccess) {
val value = result.getOrNull() ?: return@apply
value.forEach { byte ->
print("${byte.toInt().toChar()}")
}
println()
}
}
}
(gattService?.let {
val characteristic =
it.getCharacteristic(map!!.second[0])
if (characteristic != null) {
val subscribeFlow = subscribeToCharacteristic(characteristic)
val characteristicWrite = gattService!!.getCharacteristic(map!!.second[1])
if (characteristicWrite != null) {
writeChannel.consumeAsFlow().collect{ writeBytes ->
val result = writeCharacteristic(characteristicWrite, writeBytes)
println("write:${writeBytes.toList()} $result")
subscribeFlow.collect { dataBytes ->
resultWrite(dataBytes)
}
}
}
} else {
throw Exception("写入失败!")
}
} ?: {
throw Exception("服务找不到,不是自己的设备!")
})
} ?: {
throw Exception("连接失败!")
}
Java蓝牙连接外设代码:
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.text.TextUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Set;
import java.util.UUID;
import static android.bluetooth.BluetoothAdapter.STATE_CONNECTED;
import static android.bluetooth.BluetoothProfile.GATT;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
public class BluetoothDevService extends Service {
private static final int GATT_CONNECT_RETRY_MAX_COUNT = 3;
public BluetoothAdapter mBluetoothAdapter;
public BluetoothGatt mDeviceBluetoothGatt = null;
private static BluetoothDevService bluetoothDevService;
public boolean ignoreCheck;
private BluetoothManager bm;
public BluetoothDevice currentBleDevice;
protected final HashMap<BluetoothDevice, BluetoothGatt> deviceBluetoothGattHashMap = new HashMap<>();
private Handler handler;
public String byteToString(byte[] buff) {
StringBuilder stringBuilder = new StringBuilder(buff.length);
for (byte byteChar : buff) {
stringBuilder.append(String.format("%02x ", byteChar));
}
return stringBuilder.toString();
}
public void connectDevive(BluetoothGatt gatt, BluetoothDevice device) {
currentBleDevice = device;
mDeviceBluetoothGatt = gatt;
BluetoothDevManager.getInstance().connectDev(currentBleDevice);
MyLog.i("mAddress = " + currentBleDevice.getAddress());
MyLog.i("mBluetoothName = " + currentBleDevice.getName());
MyLog.i("getType = " + currentBleDevice.getType());
BluetoothDevManager.getInstance().getBaseBleDevice().setBluetoothName(currentBleDevice.getName());
BluetoothDevManager.getInstance().getBaseBleDevice().setAddress(currentBleDevice.getAddress());
BluetoothDevManager.getInstance().getBaseBleDevice().setBluetoochType(currentBleDevice.getType());
BluetoothDevManager.getInstance().getBaseBleDevice().setBluetoochClass(currentBleDevice.getBluetoothClass());
}
public boolean switchBlueState(boolean isOpen) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
boolean suc;
if (isOpen) {
suc = adapter.enable();
} else {
suc = adapter.disable();
}
return suc;
}
private int retryCount;
protected final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
BluetoothDevManager.getInstance().getBaseBleDevice().setMtu(mtu);
MyLog.i("mtu " + mtu + " " + status);
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
MyLog.i("-----onConnectionStateChange---" + status + ":" + newState);
if (status == 62) {
if (newState == STATE_DISCONNECTED) {
if (!BluetoothDevManager.getInstance().refreshDeviceCache(gatt))
BluetoothDevManager.getInstance().refreshDeviceCache(gatt);
gatt.connect();
}
} else if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) {
if (switchBlueState(false)) {
handler.postDelayed(() -> {
if (switchBlueState(true)) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
gatt.connect();
}
}, 1000);
} else {
connectDeviceError();
}
}, 1000);
} else {
connectDeviceError();
}
} else if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
MyLog.i("-----STATE_CONNECTED---");
if (!deviceBluetoothGattHashMap.containsValue(gatt))
deviceBluetoothGattHashMap.put(gatt.getDevice(), gatt);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
MyLog.i("-----STATE_DISCONNECTED---");
if (gatt.getDevice() != null && gatt.getDevice().equals(currentBleDevice)) {
BluetoothDevManager.getInstance().disconnectClear();
currentBleDevice = null;
}
} else if (newState == BluetoothProfile.STATE_CONNECTING) {
MyLog.i("-----STATE_CONNECTING---");
} else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
MyLog.i("-----STATE_DISCONNECTING---");
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
MyLog.i("-----onServicesDiscovered ---" + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
boolean self = false;
BluetoothGatt bluetoothGatt = deviceBluetoothGattHashMap.get(gatt.getDevice());
if (bluetoothGatt != null) {
bluetoothGatt.disconnect();
bluetoothGatt.close();
}
deviceBluetoothGattHashMap.remove(gatt.getDevice());
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic) {
BluetoothDevManager.getInstance().onCharacteristicChanged(blueData);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
}
};
private void connectDeviceError() {
}
public static BluetoothDevService getBluetoothService() {
return bluetoothDevService;
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
@Override
public void onCreate() {
startLoopActiveStatus();
startNotification();
registerBroadcast();
super.onCreate();
bluetoothDevService = this;
bm = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
handler = new Handler();
}
private void startLoopActiveStatus() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (currentBleDevice != null) {
BluetoothDevManager.getInstance().sendNativeMsg(1, "0:" + currentBleDevice.getName());
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public final String notificationId = "298";
public final int notificationIdInt = 298;
public void startNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationIdInt);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(notificationId, BluetoothDevManager.getInstance().getNotifyTitle(), NotificationManager.IMPORTANCE_MIN);
notificationManager.createNotificationChannel(channel);
}
startForeground(notificationIdInt, getNotification());
}
private Notification getNotification() {
Notification.Builder builder = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder = new Notification.Builder(this)
.setContentText(BluetoothDevManager.getInstance().getNotifyContent());
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(notificationId);
}
assert builder != null;
return builder.build();
}
public void startConn() {
try {
if (mBluetoothAdapter == null)
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
Set<BluetoothDevice> mBluetoothDeviceList = mBluetoothAdapter.getBondedDevices();
MyLog.e("mBluetoothDeviceList:" + mBluetoothDeviceList);
if (mBluetoothDeviceList != null) {
for (BluetoothDevice mBluetoothDevice : mBluetoothDeviceList) {
int state = bm.getConnectionState(mBluetoothDevice, GATT);
boolean ret = BluetoothDevManager.getInstance().isConnected(mBluetoothDevice);
MyLog.e("name:" + mBluetoothDevice.getName() + " state:" + state + " ret:" + ret);
if (state == STATE_CONNECTED || ret) {
if (BluetoothDevManager.getInstance().iFilterDev == null || !BluetoothDevManager.getInstance().iFilterDev.filterDevBy(mBluetoothDevice)) {
if (BluetoothDevManager.XBOX.equals(mBluetoothDevice.getName()) || BluetoothDevManager.SWITCH.equals(mBluetoothDevice.getName()) || BluetoothDevManager.PS.equals(mBluetoothDevice.getName())) {
connectDevive(null, mBluetoothDevice);
} else if (!deviceBluetoothGattHashMap.containsKey(mBluetoothDevice)) {
BluetoothGatt mDeviceBluetoothGatt = mBluetoothDevice.connectGatt(getApplication(), false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
deviceBluetoothGattHashMap.put(mBluetoothDevice, mDeviceBluetoothGatt);
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
MyLog.e(" conn e:" + e.getMessage());
}
}
public void registerBroadcast() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
getApplicationContext().registerReceiver(broadCastReceiver, intentFilter);
IntentFilter filterScreenStatus = new IntentFilter();
filterScreenStatus.addAction(Intent.ACTION_SCREEN_ON);
filterScreenStatus.addAction(Intent.ACTION_SCREEN_OFF);
filterScreenStatus.addAction(Intent.ACTION_USER_PRESENT);
filterScreenStatus.addAction(Intent.ACTION_BATTERY_CHANGED);
getApplicationContext().registerReceiver(mScreenReceiver, filterScreenStatus);
}
@SuppressLint("WrongConstant")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startConn();
return START_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
try {
stopForeground(true);
if (broadCastReceiver != null)
unregisterReceiver(broadCastReceiver);
getApplication().unregisterReceiver(mScreenReceiver);
} catch (Exception e) {
e.printStackTrace();
}
MyLog.e("serive ondestory");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
assert action != null;
switch (action) {
case Intent.ACTION_SCREEN_ON:
MyLog.i("开屏");
BluetoothDevManager.getInstance().setScreenOn();
break;
case Intent.ACTION_SCREEN_OFF:
MyLog.i("锁屏");
BluetoothDevManager.getInstance().setScreenOff();
break;
case Intent.ACTION_USER_PRESENT:
MyLog.i("解锁");
break;
case Intent.ACTION_BATTERY_CHANGED:
break;
}
}
};
public BroadcastReceiver broadCastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (null != intent) {
int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
int connectState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0);
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String action = intent.getAction();
if (!TextUtils.isEmpty(action)) {
MyLog.i("onReceive device.getName = " + action + " blueState:" + blueState + " connectState:" + connectState + " bondState:" + bondState);
if (TextUtils.equals(action, BluetoothAdapter.ACTION_STATE_CHANGED)) {
switch (blueState) {
case BluetoothAdapter.STATE_OFF:
MyLog.d("STATE_OFF 手机蓝牙关闭");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
MyLog.d("STATE_TURNING_OFF 手机蓝牙正在关闭");
break;
case BluetoothAdapter.STATE_ON:
MyLog.d("STATE_ON 手机蓝牙开启");
break;
case BluetoothAdapter.STATE_TURNING_ON:
MyLog.d("STATE_TURNING_ON 手机蓝牙正在开启");
break;
default:
break;
}
} else if (TextUtils.equals(action, BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
switch (bondState) {
case BluetoothDevice.BOND_NONE:
MyLog.d("BOND_NONE 配对失败");
if (device != null && currentBleDevice != null && TextUtils.equals(device.getName(), currentBleDevice.getName())) {
BluetoothDevManager.getInstance().disconnectClear();
currentBleDevice = null;
}
break;
case BluetoothDevice.BOND_BONDING:
MyLog.d("BOND_BONDING 正在配对");
break;
case BluetoothDevice.BOND_BONDED:
MyLog.d("BOND_BONDED 配对成功");
break;
default:
break;
}
} else if (TextUtils.equals(action, BluetoothDevice.ACTION_ACL_CONNECTED)) {
if (device != null) {
MyLog.d(device.getName() + " ACTION_ACL_CONNECTED");
if (BluetoothDevManager.getInstance().iFilterDev == null || !BluetoothDevManager.getInstance().iFilterDev.filterDevBy(device)) {
if (BluetoothDevManager.XBOX.equals(device.getName()) || BluetoothDevManager.SWITCH.equals(device.getName()) || BluetoothDevManager.PS.equals(device.getName())) {
connectDevive(null, device);
} else if (!deviceBluetoothGattHashMap.containsKey(device)) {
BluetoothGatt mDeviceBluetoothGatt = device.connectGatt(getApplication(), false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
deviceBluetoothGattHashMap.put(device, mDeviceBluetoothGatt);
}
}
}
} else if (TextUtils.equals(action, BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
if (device != null && currentBleDevice != null && TextUtils.equals(device.getName(), currentBleDevice.getName())) {
BluetoothDevManager.getInstance().disconnectClear();
currentBleDevice = null;
MyLog.d(device.getName() + " ACTION_ACL_DISCONNECTED");
}
} else if (TextUtils.equals(BluetoothDevice.ACTION_FOUND, action)) {
MyLog.e("ACTION_FOUND :" + device.getName());
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
}
} else if (TextUtils.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED, action)) {
} else if (TextUtils.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, action)) {
} else if (TextUtils.equals(BluetoothDevice.ACTION_PAIRING_REQUEST, action)) {
}
}
}
}
};
}