Android Androidx蓝牙扫描和连接

71 阅读4分钟

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 ->
//                println("Received data: $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 result = readCharacteristic(batteryLevel)
                //                    if (result.isSuccess) {
                //                        val value = result.getOrNull() ?: return@connectGatt
                //                        val battery = value[0].toInt() and 0xff
                //                        Log.i(TAG, "battery:$battery")
                //                    }
                //
                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();
//                    connect(deviice, callback);
//                    MyLog.i("bluetoothGatt:" + gatt);
//                    boolean ret = gatt.discoverServices();
//                    MyLog.i("ret:" + ret);
                }
            } else if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) {

                if (switchBlueState(false)) { // 关闭蓝牙
                    handler.postDelayed(() -> {
                        if (switchBlueState(true)) { // 5s后,开启蓝牙
                            handler.postDelayed(new Runnable() { // 5s后重试连接设备
                                @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();//STATE_DISCONNECTED
                        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) {
//                if (currentBleDevice == null) {
                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);
            //MyLog.i(TAG,"ACTION_DATA_WRITE_SUCCESS");
//            broadcastUpdate(ACTION_DATA_WRITE_SUCCESS);
        }
    };

    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);
//                notificationManager.notify(InputADBUtils.getInstance().notificationIdInt, getNotification());
        }
        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)) {
//                                                bluetoothDevices.add(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);
//        BTManager.getInstance().initBluetooth(getApplication());
        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();
//                    NativeManagerUtils.getInstance().sendNativeMsg("1:1");//开屏打开拦截
                    break;
                case Intent.ACTION_SCREEN_OFF: // 锁屏
                    MyLog.i("锁屏");
                    BluetoothDevManager.getInstance().setScreenOff();
//                    NativeManagerUtils.getInstance().sendNativeMsg("1:0");//锁屏关闭拦截
                    break;
                case Intent.ACTION_USER_PRESENT: // 解锁
                    MyLog.i("解锁");
//                    NativeManagerUtils.getInstance().sendNativeMsg("1:1");//解锁打开拦截
                    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;
                                }
//                                canelBond = true;
                                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) {
                            //搜索蓝牙设备第9步,把设备添加到已找到列表中,这里只是显示它的信息.
//                            tvDevices.append(device.getName() + ":" + device.getAddress() + "\n");
                        }
                    } 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)) {
                        //配对的验证码,如果是-1侧不需要验证码
                    }
                }
            }
        }
    };
}