未连接 Gatt 服务器

Not Connecting Gatt Server

我正在尝试通过 Gatt 协议连接两个 android 设备。

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.ParcelUuid;
import android.util.Log;

import java.util.HashSet;
import java.util.Set;

public class GattServer {
    private final String TAG = GattServer.class.getSimpleName();

    private Context applicationContext;
    private BluetoothManager bluetoothManager;
    private BluetoothAdapter bluetoothAdapter;
    private LocationManager locationManager;

    BluetoothLeAdvertiser bluetoothLeAdvertiser;


    private static GattServer gattServer;
    private BluetoothGattServer bluetoothGattServer;

    private Set<BluetoothDevice> connectedDevices = new HashSet<>();


    public GattServer(Context applicationContext) {
        this.applicationContext = applicationContext;
        bluetoothManager = (BluetoothManager) applicationContext.getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        locationManager = (LocationManager) applicationContext.getSystemService(Context.LOCATION_SERVICE);
        registerBluetoothStateReceiver();
    }

    public static GattServer getInstance(Context context) {
        if (gattServer == null) {
            gattServer = new GattServer(context.getApplicationContext());
        }
        return gattServer;
    }

    private BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    println("Bluetooth adapter state is changed to ON");
                    break;
                case BluetoothAdapter.STATE_OFF:
                    println("Bluetooth adapter state is changed to OF");
                    break;
                default:
                    // Do nothing
            }
        }
    };

    private void println(String message) {
        Log.e(TAG, message);
    }

    private void registerBluetoothStateReceiver() {
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        try {
            applicationContext.registerReceiver(bluetoothStateReceiver, filter);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void unregisterBluetoothStateReceiver() {
        try {
            applicationContext.unregisterReceiver(bluetoothStateReceiver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void destroy() {
        stop();
        unregisterBluetoothStateReceiver();
        gattServer = null;
    }


    private AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            println("Advertise Started");
            listener.onAdvertiseStarted();
        }

        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            println("Advertise Failed : " + errorCode);
            listener.onAdvertiseFail(errorCode);
        }
    };

    private void startAdvertising() {
        bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
        if (bluetoothLeAdvertiser == null || !bluetoothAdapter.isMultipleAdvertisementSupported()) {
            Log.e(TAG, "Failed to create advertiser");
            listener.onAdvertiseFail(-1);
            return;
        }

        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
                .setConnectable(true)
                .setTimeout(0)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
                .build();

        AdvertiseData data = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)
                .setIncludeTxPowerLevel(false)
                .addServiceUuid(new ParcelUuid(GattServerConfiguration.SERVICE_UUID))
                .build();


        bluetoothLeAdvertiser.startAdvertising(settings, data, advertiseCallback);
    }

    private BluetoothGattServerCallback gattCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            super.onConnectionStateChange(device, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                println("Device Connected : " + device.getAddress());
                connectedDevices.add(device);
                listener.onDeviceConnected(device);
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                println("Device Disconnected : " + device.getAddress());
                connectedDevices.remove(device);
                listener.onDeviceDisconnected(device);
            }
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);
            Log.d(TAG, "onServiceAdded() called with: status = [" + status + "], service = [" + service + "]");
            listener.onServiceAdded();
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            Log.d(TAG, "onCharacteristicReadRequest() called with: device = [" + device + "], requestId = [" + requestId + "], offset = [" + offset + "], characteristic = [" + characteristic + "]");
            listener.onReceive(device, characteristic);
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
            Log.d(TAG, "onCharacteristicWriteRequest() called with: device = [" + device + "], requestId = [" + requestId + "], characteristic = [" + characteristic + "], preparedWrite = [" + preparedWrite + "], responseNeeded = [" + responseNeeded + "], offset = [" + offset + "], value = [" + value + "]");
        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor);
            Log.d(TAG, "onDescriptorReadRequest() called with: device = [" + device + "], requestId = [" + requestId + "], offset = [" + offset + "], descriptor = [" + descriptor + "]");


            if (GattServerConfiguration.CCC_DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
                Log.d(TAG, "Config descriptor read");
                byte[] returnValue;
                if (connectedDevices.contains(device)) {
                    returnValue = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                } else {
                    returnValue = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
                }
                bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, returnValue);
            } else {
                Log.w(TAG, "Unknown descriptor read request");
                bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
            }

        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            Log.d(TAG, "onDescriptorWriteRequest() called with: device = [" + device + "], requestId = [" + requestId + "], descriptor = [" + descriptor + "], preparedWrite = [" + preparedWrite + "], responseNeeded = [" + responseNeeded + "], offset = [" + offset + "], value = [" + value + "]");
            if (GattServerConfiguration.CCC_DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
                Log.d(TAG, "Config descriptor read");
                byte[] returnValue;
                if (connectedDevices.contains(device)) {
                    returnValue = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                } else {
                    returnValue = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
                }
                bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, returnValue);
            } else {
                Log.w(TAG, "Unknown descriptor read request");
                bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
            }
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);
            Log.d(TAG, "onExecuteWrite() called with: device = [" + device + "], requestId = [" + requestId + "], execute = [" + execute + "]");
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            Log.d(TAG, "onNotificationSent() called with: device = [" + device + "], status = [" + status + "]");
        }

        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            super.onMtuChanged(device, mtu);
            Log.d(TAG, "onMtuChanged() called with: device = [" + device + "], mtu = [" + mtu + "]");
        }

        @Override
        public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) {
            super.onPhyUpdate(device, txPhy, rxPhy, status);
            Log.d(TAG, "onPhyUpdate() called with: device = [" + device + "], txPhy = [" + txPhy + "], rxPhy = [" + rxPhy + "], status = [" + status + "]");
        }

        @Override
        public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) {
            super.onPhyRead(device, txPhy, rxPhy, status);
            Log.d(TAG, "onPhyRead() called with: device = [" + device + "], txPhy = [" + txPhy + "], rxPhy = [" + rxPhy + "], status = [" + status + "]");
        }
    };

    private void startServer() {
        bluetoothGattServer = bluetoothManager.openGattServer(applicationContext, gattCallback);
        if (bluetoothGattServer == null) {
            println("Server is null");
            return;
        }

        bluetoothGattServer.addService(GattServerConfiguration.createGattService());
    }

    public void launch() {
        if (isReady()) {
            startServer();
            startAdvertising();
        }
    }

    private void stopAdvertising() {
        if (bluetoothLeAdvertiser == null) return;
        bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);
    }

    private void stopServer() {
        if (bluetoothGattServer == null) return;
        bluetoothGattServer.close();
    }

    public void stop() {
        stopAdvertising();
        stopServer();
        connectedDevices.clear();
    }

    private boolean isReady() {
        if (bluetoothManager == null) {
            return false;
        }

        return bluetoothAdapter.isEnabled() && locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }


    private IGattServer listener;

    public void setCallback(IGattServer listener) {
        this.listener = listener;
    }
}

以上代码,成功启动广告, 另一个设备在 LE 扫描中成功接收设备(使用 UUID 的过滤器) 但是connectGatt()没有提供任何回调。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            bluetoothGatt = bluetoothDevice.connectGatt(
                    getApplicationContext(), true, gattCallback,
                    BluetoothDevice.TRANSPORT_LE
            );
        } else {
            bluetoothGatt = bluetoothDevice.connectGatt(getApplicationContext(), true, gattCallback);
        }

Gatt 回调示例代码。

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            writeLog("onConnectionStateChange() called with: gatt = [" + gatt + "], status = [" + status + "], newState = [" + newState + "]");
            broadcastUpdate(
                    ACTION_GATT_MESSAGE,
                    "onConnectionStateChange() called with: gatt = $gatt, status = $status, newState = $newState"
            );
            if (status == 8) {
                writeLog("BLE Out Of Range");
                broadcastUpdate(ACTION_GATT_MESSAGE, "BLE Out Of Range status == 8");
            } else if (status == 19) {
                writeLog("BLE Disconnected By Device");
                broadcastUpdate(ACTION_GATT_MESSAGE, "BLE Disconnected By Device status == 19");
            } else if (status == 22) {
                writeLog("BLE Issue with bond");
                broadcastUpdate(ACTION_GATT_MESSAGE, "BLE Issue with bond status == 22");
            } else if (status == 133 || status == 62) {
                writeLog("BLE Device not found");
                broadcastUpdate(
                        ACTION_GATT_MESSAGE,
                        "BLE Device not found status == 133 || status == 62"
                );
                disconnect();
                close();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                connectDevice(bluetoothAdapter.getRemoteDevice(PrefManager.getInstance(getApplicationContext()).getLeAddress()));
                return;
            }


            if (newState == BluetoothProfile.STATE_CONNECTED) {
                connected = true;
                broadcastUpdate(ACTION_GATT_CONNECTED);
                bluetoothGatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                connected = false;
                broadcastUpdate(ACTION_GATT_DISCONNECTED);
                stopSelf();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            writeLog("onServicesDiscovered() called with: gatt = [" + gatt + "], status = [" + status + "]");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Intent intent = new Intent(ACTION_GATT_SERVICES_DISCOVERED);
                ArrayList<BluetoothGattService> services = new ArrayList<BluetoothGattService>();
                for (BluetoothGattService gattService : gatt.getServices()) {
                    services.add(gattService);
                }
                intent.putParcelableArrayListExtra("services", services);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                broadcastUpdate(intent);
            } else {
                broadcastUpdate(ACTION_GATT_NO_SERVICES_DISCOVERED);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            Log.e(
                    TAG,
                    "onCharacteristicRead() called with: gatt = $gatt, characteristic = $characteristic, status = $status"
            );

            if (status == BluetoothGatt.GATT_SUCCESS) {
                Intent intent = new Intent(ACTION_DATA_AVAILABLE);
                intent.putExtra("bytes", characteristic.getValue());
                //lintent.putExtra("data", characteristic.getValue().toString());
                broadcastUpdate(intent);
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Log.e(
                    TAG,
                    "onCharacteristicWrite() called with: gatt = " + gatt + ", characteristic = " + characteristic + ", status = " + status
            );

            if (canceled || !connected || writeCharacteristic == null) {
                writeLog("Return Form write 1");
                return;
            }
            if (status != BluetoothGatt.GATT_SUCCESS) {
                writeLog("Return Form write 2");
                broadcastUpdate(ACTION_DATA_WRITE_FAIL);
                return;
            }
            if (canceled) return;
            writeLog("Write Success Checking for next bytes");
            if (characteristic.getUuid().toString().equals(writeCharacteristic.getUuid().toString())) { // NOPMD - test object identity
                writeNext();
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.e(
                    TAG,
                    "onCharacteristicChanged() called with: gatt = $gatt, characteristic = $characteristic"
            );

            if (characteristic.getUuid().toString().equals(readCharacteristic.getUuid().toString())) {
                Intent intent = new Intent(ACTION_DATA_AVAILABLE);
                intent.putExtra("bytes", characteristic.getValue());
                broadcastUpdate(intent);
            }
        }

        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
            Log.e(
                    TAG,
                    "onDescriptorRead() called with: gatt = $gatt, descriptor = $descriptor, status = $status"
            );
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
            writeLog("onDescriptorWrite() called with: gatt = [" + gatt + "], descriptor = [" + descriptor + "], status = [" + status + "]");
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
            writeLog("onReliableWriteCompleted() called with: gatt = [" + gatt + "], status = [" + status + "]");
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
            writeLog("onReadRemoteRssi() called with: gatt = [" + gatt + "], rssi = [" + rssi + "], status = [" + status + "]");
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                payloadSize = mtu - 3;
                writeLog("payload size $payloadSize");
            }
            enableTxNotification();
        }

        @Override
        public void onServiceChanged(@NonNull BluetoothGatt gatt) {
            super.onServiceChanged(gatt);
        }
    };

我解决了连接问题。

bluetoothGatt = bluetoothDevice.connectGatt(
            getApplicationContext(), false, gattCallback,
            BluetoothDevice.TRANSPORT_AUTO
    );