Android 蓝牙 onCharacteristicChanged 从未被调用

标签 android bluetooth bluetooth-lowenergy

我已按照 https://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html 中列出的指南进行操作

我不知道如何在特征值发生变化时触发通知。 onCharacteristicChanged 方法从未被调用,但我知道该值每 2 秒更改一次。当我发现该服务时,我通过调用 readCharacteristic 来绕过这个事实,然后再重复调用。我不认为这是正确的方法,而我应该只在 onCharacteristicChanged 方法发送广播时阅读。是否可以让通知起作用,或者这是最好的方法吗?

设备 Controller :

public class WarningActivity extends AppCompatActivity {
    private static final String TAG = "WarningActivity Class";
    private BluetoothLeService mBluetoothLeService;
    public static WarningActivity wInstance;
    private boolean mConnected = false;
    private String mDeviceAddress;
    private boolean quitService;
    private TextView connectStatus;
    private Button connectButton;
    private Button cameraButton;
    private BluetoothManager mBluetoothManager;
    private Vibrator vib;
    private Uri notification;
    private Ringtone ring;

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                Log.e(TAG, "Unable to initialize Bluetooth");
                finish();
            }
            mBluetoothLeService.connect(mDeviceAddress);

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();

            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
                mConnected = true;

            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                mConnected = false;

            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                Log.i("Data: ", mBluetoothLeService.getSupportedGattService().toString());
                BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
                BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
                mBluetoothLeService.setCharacteristicNotification(characteristic, true);
                mBluetoothLeService.readCharacteristic(characteristic);

            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
                BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
                byte[] temp = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);
                String tempString = Arrays.toString(temp);
                Log.i("Data: ", Arrays.toString(temp));
                mBluetoothLeService.readCharacteristic(characteristic);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#268011"));
        getSupportActionBar().setBackgroundDrawable(colorDrawable);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);

        connectButton = (Button) findViewById(R.id.connectButton);
        connectButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.connected_logo, 0, 0);
        connectButton.setClickable(false);

        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

        Intent intent = getIntent();
        mDeviceAddress = intent.getStringExtra("EXTRA_DEVICE_ADDRESS");

        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        ring = RingtoneManager.getRingtone(getApplicationContext(), notification);
        wInstance = this;

        quitService = false;

        connectStatus = (TextView) findViewById(R.id.connectMessage);
        connectStatus.setText("Connected to: \n " + mDeviceAddress);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        if (mBluetoothLeService != null) {
            final boolean result = mBluetoothLeService.connect(mDeviceAddress);
            Log.d(TAG, "Connect request result=" + result);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mGattUpdateReceiver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
        mBluetoothLeService = null;
    }

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
        return intentFilter;
    }
}

蓝牙乐服务

public class BluetoothLeService extends Service {
    private final static String TAG = BluetoothLeService.class.getSimpleName();

    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private String mBluetoothDeviceAddress;
    private BluetoothGatt mBluetoothGatt;
    private int mConnectionState = STATE_DISCONNECTED;

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA = "EXTRA_DATA";

    public final static UUID SERVICE_UUID = UUID.fromString(GattAttributes.BLE_SERVICE);
    public final static UUID ALERT_UUID = UUID.fromString(GattAttributes.BLE_ALERT_CHARACTERISTIC);

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG, "Connected to GATT server.");
                Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.i("BlueToothService: ", "onCharacteristicRead " + characteristic.toString());
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.i("BlueToothService: ", "onCharacteristicChanged " + characteristic.toString());
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    };

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        Log.i("BlueToothService: ", "BroadcastUpdate ActionOnly: " + action);
        sendBroadcast(intent);
    }

    private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        Log.i("BlueToothService: ", "BroadcastUpdateLong " + characteristic.toString() + " Action:" + action);

        intent.putExtra(EXTRA_DATA, characteristic.getValue());
        sendBroadcast(intent);
    }

    public class LocalBinder extends Binder {
        BluetoothLeService getService() {
            return BluetoothLeService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        close();
        return super.onUnbind(intent);
    }

    private final IBinder mBinder = new LocalBinder();

    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter through
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                Log.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }

        return true;
    }

    public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                return true;
            } else {
                return false;
            }
        }

        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }

        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;
        return true;
    }

    public void disconnect() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.disconnect();
    }

    public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }

    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.readCharacteristic(characteristic);
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }

        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        if (SERVICE_UUID.equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(ALERT_UUID);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
    }

    public BluetoothGattService getSupportedGattService() {
        if (mBluetoothGatt == null) return null;

        return mBluetoothGatt.getService(SERVICE_UUID);
    }
}

最佳答案

找到解决方案:错误输入和错误描述符 UUID 的经典案例。我在哪里找到答案BLE GATT onCharacteristicChanged not called after subscribing to notification 。错误是在 setCharacteristicNotification 方法中。更改为 ALERT_UUID 以及哪篇文章让我假设正确的描述符 UUID

public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }

    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    if (ALERT_UUID.equals(characteristic.getUuid())) {
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
}

关于Android 蓝牙 onCharacteristicChanged 从未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42006680/

相关文章:

android - 使用camera2 API createCaptureSession后,Android无法仅播放视频音频

android videoview mp4 seekto只能每10秒寻找一次

android - Eclipse Content Assist 不适用于 Android

bluetooth-lowenergy - C 语言的轻量级蓝牙 LE 库

ios - BLE特性通知属性的本质是什么?

android - 通过 MoPub 调解将 GDPR 同意转发给 AdMob

iOS 7 无法使用 AVAudioSession 通过蓝牙接收器接收音频

android - 接收器生命周期 - 在 onResume() 中重新注册时崩溃

android - 通过蓝牙将 Android 连接到另一台设备并发送数据

android - BLE 蓝牙低功耗设备中的身份验证问题