Android BLE无法从设备接收Gatt特征通知 [英] Android BLE can't receive Gatt Characteristic notification from device

查看:160
本文介绍了Android BLE无法从设备接收Gatt特征通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在特征上写入值时,我试图从设备接收通知,但什么也没收到.我在特征上启用通知,然后写入值.我已经看到设备中的特征已更改其值,但是我无法获得通知.这是我的代码:

I'm trying to receive a notification from the device when I write a value on a characteristic, but I don´t receive anything. I enable the notification on the characteristic and then I write the value. I've seen that the characteristic in the device have changed its value but I can't get the notification. Here is my code:

DeviceActivity:

DeviceActivity:

public class DevicesActivity extends Activity {

private BLEService mBluetoothLeService;
private String mDeviceAddress;
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;

private final ServiceConnection mServiceConnection = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder service) {
        mBluetoothLeService = ((BLEService.LocalBinder) service).getService();
        if (!mBluetoothLeService.initialize()) {
            finish();
        }
        mBluetoothLeService.context = DevicesActivity.this;
        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 (BLEService.ACTION_GATT_CONNECTED.equals(action)) {
            mConnected = true;
            invalidateOptionsMenu();
        } else if (BLEService.ACTION_GATT_DISCONNECTED.equals(action)) {
            mConnected = false;
            invalidateOptionsMenu();
        } else if (BLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
            List<BluetoothGattService> servicesList;
            servicesList = mBluetoothLeService.getSupportedGattServices();
            Iterator<BluetoothGattService> iter = servicesList.iterator();
            while (iter.hasNext()) {
                BluetoothGattService bService = (BluetoothGattService) iter.next();
                if (bService.getUuid().toString().equals(BLEUUID.SERVICE)){
                    mService = bService;
                }
            }
        } else if (BLEService.ACTION_DATA_AVAILABLE.equals(action)) {
            displayData(intent.getStringExtra(BLEService.EXTRA_DATA));
        }
    }
};

private static final String TAG = "BLEDevice";
public static final String EXTRA_BLUETOOTH_DEVICE = "BT_DEVICE";
private BluetoothAdapter mBTAdapter;
private BluetoothDevice mDevice;
private BluetoothGatt mConnGatt;
private int mStatus;
BluetoothGattService mService;

private EditText pinTxt;
private Button cancelBtn;
private Button unlockBtn;
private Button changePinBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    setContentView(R.layout.activity_devices);

    pinTxt = (EditText) findViewById(R.id.pin_txt);
    cancelBtn = (Button) findViewById(R.id.cancel_btn);
    unlockBtn = (Button) findViewById(R.id.unlock_btn);
    changePinBtn = (Button) findViewById(R.id.change_pin_btn);

    unlockBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String aux = pinTxt.getText().toString();
            mBluetoothLeService.sendCharacteristic(aux, getBTDeviceExtra());
        }
    });

    mDevice = getBTDeviceExtra();
    mDeviceAddress = mDevice.getAddress();
    if (mServiceConnection == null){
        Log.v("NULL", "mServiceConnection NULL");
    }

    Intent gattServiceIntent = new Intent(this, BLEService.class);
    if (gattServiceIntent==null){
        Log.v("NULL", "mServiceConnection NULL");
    }
    bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
    mStatus = BluetoothProfile.STATE_DISCONNECTED;
}

private void displayData(String data) {
    if (data != null) {
        Toast.makeText(DevicesActivity.this, data, Toast.LENGTH_LONG);
    }
}
@Override
protected void onDestroy() {
    super.onDestroy();
    unbindService(mServiceConnection);
    mBluetoothLeService = null;
}

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

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

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
    if (mBluetoothLeService != null) {
        final boolean result = mBluetoothLeService.connect(mDeviceAddress);
    }

}

private BluetoothDevice getBTDeviceExtra() {
    Intent intent = getIntent();
    if (intent
        == null) {            return null;
    }

    Bundle extras = intent.getExtras();
    if (extras == null) {
        return null;
    }

    BluetoothDevice aux = extras.getParcelable(EXTRA_BLUETOOTH_DEVICE);
    return aux;
}

BLEService:

BLEService:

 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.");
            // Attempts to discover services after successful connection.
            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) {
            for (BluetoothGattService service : gatt.getServices()) {
                if ((service == null) || (service.getUuid() == null)) {
                    continue;
                }
                if (BLEUUID.SERVICE.equalsIgnoreCase(service.getUuid().toString())) {
                    mService = service;
                }
            }
            broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            broadcastUpdate(EXTRA_DATA, characteristic);
            Log.i("CARAC","CARACTERISTICA LEIDA onCharacteristicRead()");
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
        readCharacteristic(characteristic);
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        Log.i("CARAC","CAMBIO EN CARACTERISTICA");
    }
};

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
    final Intent intent = new Intent(action);

    if (PIN_CHARACTERISTIC.equals(characteristic.getUuid())) {

        final String pin = characteristic.getStringValue(0);
        intent.putExtra(EXTRA_DATA, String.valueOf(pin));
    } else {
        // For all other profiles, writes the data formatted in HEX.
        final byte[] data = characteristic.getValue();
        if (data != null && data.length > 0) {
            final StringBuilder stringBuilder = new StringBuilder(data.length);
            for(byte byteChar : data)
                stringBuilder.append(String.format("%02X ", byteChar));
            Log.i("RECIBIDO", "RECIBIDOS DATOS");
            intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
        }
    }
    sendBroadcast(intent);
}

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

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

@Override
public boolean onUnbind(Intent intent) {
    // After using a given device, you should make sure that BluetoothGatt.close() is called
    // such that resources are cleaned up properly.  In this particular example, close() is
    // invoked when the UI is disconnected from the Service.
    close();
    return super.onUnbind(intent);
}

private final IBinder mBinder = new LocalBinder();

public boolean initialize() {
    if (mBluetoothManager == null) {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            return false;
        }
    }
    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        return false;
    }
    return true;
}

public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        return false;
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        if (mBluetoothGatt.connect()) {
            mConnectionState = STATE_CONNECTING;
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    if (device == null) {
        return false;
    }

    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
    mBluetoothDeviceAddress = address;
    mConnectionState = STATE_CONNECTING;
    return true;
}

public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.disconnect();
}

public void close() {
    if (mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
    Log.e("CIERRE", "CONEXION CERRADA");
}

public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.readCharacteristic(characteristic);
    Log.i("READ", "CARACTERISTICA LEIDA");
}

public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    if (PIN_CHARACTERISTIC.equals(characteristic.getUuid())){
        BluetoothGattDescriptor descriptor =
                new BluetoothGattDescriptor(UUID.nameUUIDFromBytes(BLEUUID.PIN_CHARACTERISTIC_CONFIG_DESCRIPTOR.getBytes()),
                        BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED);

        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);
    }
}

public List<BluetoothGattService> getSupportedGattServices() {
    if (mBluetoothGatt == null) return null;
    return mBluetoothGatt.getServices();
}

public void sendCharacteristic(String pin, BluetoothDevice device){

    byte[] pinByte = pin.getBytes();
    int pinInt = Integer.valueOf(pin);

    BluetoothGattCharacteristic ch = (BluetoothGattCharacteristic) mService.getCharacteristic(UUID
            .fromString(BLEUUID.PIN_CHARACTERISTIC_UUID));

    ch.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

    ch.setValue(pin);

    Toast.makeText(context, "CARACTERISTICA ASIGNADA", Toast.LENGTH_SHORT).show();
    connect(device.getAddress());
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
    setCharacteristicNotification(ch, true);

    if (mBluetoothGatt.writeCharacteristic(ch)) {
        Toast.makeText(context, "CARACTERISTICA ESCRITA", Toast.LENGTH_SHORT).show();
    }


}

}

BLEUUID

public class BLEUUID {

// CARACTERISTICA PIN
public  static final String SERVICE ="0000fff0-0000-1000-8000-00805f9b34fb";
public static final String PIN_CHARACTERISTIC_UUID="0000fff9-0000-1000-8000-00805f9b34fb";
public static final String PIN_CHARACTERISTIC_CONFIG_DESCRIPTOR="0x2902";

private static HashMap<String, String> attributes = new HashMap();
static {
    attributes.put(SERVICE, "Service");
    attributes.put(PIN_CHARACTERISTIC_UUID, "Pin");
}

当我调试时,onCharacteristicChange()永远不会执行.

When I debug, onCharacteristicChange() never executes.

有人知道问题出在哪里

推荐答案

这是在Android上使用BLE的工作方式的一般模式:

Here is the general pattern for how things need to work with BLE on Android:

  1. 您尝试连接
  2. 您会收到一个回调,表明它已连接
  3. 您发现了服务
  4. 被告知服务被发现
  5. 您掌握了特色
  6. 对于每个特征,您都会获得描述符
  7. 对于描述符,您可以通过BluetoothGattDescriptor.setValue()将其设置为启用通知/指示
  8. 您使用BluetoothGatt.writeDescriptor()编写描述符
  9. 您可以使用BluetoothGatt.setCharacteristicNotification()在本地启用特征通知.没有这个,您将不会被回电.
  10. 您会收到有关描述符已编写的通知
  11. 现在您可以将数据写入特征.在将任何内容写入任何特征之前,已经完成了所有特征和描述符配置.
  1. You try to connect
  2. You get a callback indicating it is connected
  3. You discover services
  4. You are told services are discovered
  5. You get the characteristics
  6. For each characteristic you get the descriptors
  7. For the descriptor you set it to enable notification/indication with BluetoothGattDescriptor.setValue()
  8. You write the descriptor with BluetoothGatt.writeDescriptor()
  9. You enable notifications for the characteristic locally with BluetoothGatt.setCharacteristicNotification(). Without this you won't get called back.
  10. You get notification that the descriptor was written
  11. Now you can write data to the characteristic. All of the characteristic and descriptor configuration has do be done before anything is written to any characteristic.

这篇关于Android BLE无法从设备接收Gatt特征通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆