订阅BLE GAT通知Android

我正在开发一个BLE应用程序,基于GAT提供的示例项目: https : //developer.android.com/samples/BluetoothLeGatt/index.html 。 所以,我可以成功地发送数据写入特征。 现在我需要知道这个特性何时改变它的价值。 我知道我需要实现setCharacteristicNotification()方法和onDescriptorWrite()方法。 但我不能这样做的工作。 search,我发现了一些想法: Android BLE API:未收到GATT通知 , 通过蓝牙低功耗(BLE)设备获取通知的步骤是什么? ,但仍然没有运气,我不明白它是如何工作的,我需要什么参数定义或我需要做什么!!! 一些好的灵魂可以分享我一个完成这个项目的完整项目。 我所需要的只是在BLE设备返回一些数据时可视化特征的值。

我阅读了官方的Android文档,但没有那么具体。 提前致谢

这些是我的代码:

设备

public class DeviceControlActivity extends Activity { public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME"; public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS"; private TextView mConnectionState; private TextView mDataField; private TextView mRssiField; private String mDeviceName; private String mDeviceAddress; private ExpandableListView mGattServicesList; private BluetoothLeService mBluetoothLeService; static ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); private boolean mConnected = false; private BluetoothGattCharacteristic mNotifyCharacteristic; private BluetoothGattCharacteristic mWriteCharacteristic, mReadCharacteristic; Button Escritor; byte hello[] = { 0 }; private final String LIST_NAME = "NAME"; private final String LIST_UUID = "UUID"; // BluetoothGattCharacteristic characteristic; // public BluetoothGatt mBluetoothGatt; // Code to manage Service lifecycle. private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (!mBluetoothLeService.initialize()) { Log.e("Unable to initialize Bluetooth"); finish(); } // Automatically connects to the device upon successful start-up // initialization. mBluetoothLeService.connect(mDeviceAddress); mBluetoothLeService.setBLEServiceCb(mDCServiceCb); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } }; // If a given GATT characteristic is selected, check for supported features. // This sample // demonstrates 'Read' and 'Notify' features. See // http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for // the complete // list of supported characteristic features. private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (mGattCharacteristics != null) { final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition); final int charaProp = characteristic.getProperties(); if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) { // If there is an active notification on a characteristic, // clear // it first so it doesn't update the data field on the user // interface. Log.d("BluetoothGattCharacteristic has PROPERTY_READ, so send read request"); if (mNotifyCharacteristic != null) { mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, true); mNotifyCharacteristic = null; } mBluetoothLeService.readCharacteristic(characteristic); /*Toast.makeText(getApplicationContext(), "Leyó Algo", Toast.LENGTH_SHORT).show();*/ } if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { Log.d("BluetoothGattCharacteristic has PROPERTY_NOTIFY, so send notify request"); mNotifyCharacteristic = characteristic; mBluetoothLeService.setCharacteristicNotification(characteristic, true); } if (((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) | (charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) > 0) { Log.d("BluetoothGattCharacteristic has PROPERY_WRITE | PROPERTY_WRITE_NO_RESPONSE"); mWriteCharacteristic = characteristic; // popup an dialog to write something. showCharactWriteDialog(); } return true; } return false; } }; private void showCharactWriteDialog() { DialogFragment newFrame = new BleCharacterDialogFragment(); newFrame.show(getFragmentManager(), "blewrite"); } private void clearUI() { mGattServicesList.setAdapter((SimpleExpandableListAdapter) null); mDataField.setText(R.string.no_data); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gatt_services_characteristics); final Intent intent = getIntent(); mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME); mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS); // Sets up UI references. ((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress); mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list); mGattServicesList.setOnChildClickListener(servicesListClickListner); mConnectionState = (TextView) findViewById(R.id.connection_state); mDataField = (TextView) findViewById(R.id.data_value); mRssiField = (TextView) findViewById(R.id.signal_rssi); getActionBar().setTitle(mDeviceName); getActionBar().setDisplayHomeAsUpEnabled(true); Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); } @Override protected void onResume() { super.onResume(); // registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); if (mBluetoothLeService != null) { final boolean result = mBluetoothLeService.connect(mDeviceAddress); Log.d("Connect request result=" + result); } } @Override protected void onPause() { super.onPause(); // unregisterReceiver(mGattUpdateReceiver); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection); mBluetoothLeService = null; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.gatt_services, menu); if (mConnected) { menu.findItem(R.id.menu_connect).setVisible(false); menu.findItem(R.id.menu_disconnect).setVisible(true); } else { menu.findItem(R.id.menu_connect).setVisible(true); menu.findItem(R.id.menu_disconnect).setVisible(false); } return true; } @TargetApi(Build.VERSION_CODES.ECLAIR) @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_connect: mBluetoothLeService.connect(mDeviceAddress); return true; case R.id.menu_disconnect: mBluetoothLeService.disconnect(); return true; case android.R.id.home: onBackPressed(); return true; } return super.onOptionsItemSelected(item); } private void updateConnectionState(final int resourceId) { runOnUiThread(new Runnable() { @Override public void run() { mConnectionState.setText(resourceId); } }); } private void displayData(String data) { if (data != null) { mDataField.setText(data); } } private void displayRssi(String rssi) { if (rssi != null) { // Log.d("-- dispaly Rssi: " + rssi); mRssiField.setText(rssi); } } private void displayRetorno(String rssi) { if (rssi != null) { // Log.d("-- dispaly Rssi: " + rssi); mRssiField.setText(rssi+"Ñ"); Toast.makeText(getApplicationContext(), "SsSsSs"+"viendo", Toast.LENGTH_SHORT).show(); } } // Demonstrates how to iterate through the supported GATT // Services/Characteristics. // In this sample, we populate the data structure that is bound to the // ExpandableListView // on the UI. @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void displayGattServices(List<BluetoothGattService> gattServices) { Log.d("displayGATTServices"); if (gattServices == null) return; String uuid = null; String unknownServiceString = getResources().getString(R.string.unknown_service); String unknownCharaString = getResources().getString(R.string.unknown_characteristic); ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>(); ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>(); mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); // Loops through available GATT Services. for (BluetoothGattService gattService : gattServices) { HashMap<String, String> currentServiceData = new HashMap<String, String>(); uuid = gattService.getUuid().toString(); currentServiceData.put(LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString)); currentServiceData.put(LIST_UUID, uuid); gattServiceData.add(currentServiceData); ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>(); List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>(); // Loops through available Characteristics. for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { charas.add(gattCharacteristic); HashMap<String, String> currentCharaData = new HashMap<String, String>(); uuid = gattCharacteristic.getUuid().toString(); currentCharaData.put(LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString)); currentCharaData.put(LIST_UUID, uuid); gattCharacteristicGroupData.add(currentCharaData); } mGattCharacteristics.add(charas); gattCharacteristicData.add(gattCharacteristicGroupData); } SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(this, gattServiceData, android.R.layout.simple_expandable_list_item_2, new String[] { LIST_NAME, LIST_UUID }, new int[] { android.R.id.text1, android.R.id.text2 }, gattCharacteristicData, android.R.layout.simple_expandable_list_item_2, new String[] { LIST_NAME, LIST_UUID }, new int[] { android.R.id.text1, android.R.id.text2 }); mGattServicesList.setAdapter(gattServiceAdapter); final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(2).get(0); final int charaProp = characteristic.getProperties(); mWriteCharacteristic = characteristic; mBluetoothLeService.setCharacteristicNotification(mWriteCharacteristic, true); if (mWriteCharacteristic != null) { byte[] value = { (byte) 0x0D }; mWriteCharacteristic.setValue("ATZ"); Toast.makeText(getApplicationContext(), String.valueOf(mWriteCharacteristic.getStringValue(0)), Toast.LENGTH_SHORT).show(); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); boolean jo=mBluetoothLeService.mBluetoothGatt.readCharacteristic(mWriteCharacteristic); Toast.makeText(getApplicationContext(), String.valueOf(mWriteCharacteristic.getStringValue(0)), Toast.LENGTH_SHORT).show(); /*mWriteCharacteristic.setValue("ATE0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATE0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATL0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATM0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATS0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATH0"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue("ATAT2"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);*/ /*mWriteCharacteristic.setValue("ATZ"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); mWriteCharacteristic.setValue(value); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);*/ } final BluetoothGattCharacteristic characteristic2 = mGattCharacteristics.get(0).get(0); final int charaProp2 = characteristic2.getProperties(); mReadCharacteristic = characteristic2; mBluetoothLeService.readCharacteristic(mReadCharacteristic); } private DCServiceCb mDCServiceCb = new DCServiceCb(); public class DCServiceCb implements BluetoothLeService.BLEServiceCallback { @Override public void displayRssi(final int rssi) { runOnUiThread(new Runnable() { @Override public void run() { DeviceControlActivity.this.displayRssi(String.valueOf(rssi)); } }); } @Override public void displayRetorno (final int rssi) { runOnUiThread(new Runnable() { @Override public void run() { DeviceControlActivity.this.displayRetorno("algo!!!!"); } }); } @Override public void displayData(final String data) { runOnUiThread(new Runnable() { @Override public void run() { DeviceControlActivity.this.displayData(data); Toast.makeText(getApplicationContext(), data+"SsSsSs", Toast.LENGTH_SHORT).show(); } }); } @Override public void notifyConnectedGATT() { runOnUiThread(new Runnable() { @Override public void run() { mConnected = true; updateConnectionState(R.string.connected); invalidateOptionsMenu(); } }); } @Override public void notifyDisconnectedGATT() { runOnUiThread(new Runnable() { @Override public void run() { mConnected = false; updateConnectionState(R.string.disconnected); invalidateOptionsMenu(); clearUI(); } }); } @Override public void displayGATTServices() { Log.d("displayGATTServices."); runOnUiThread(new Runnable() { @Override public void run() { if (mBluetoothLeService != null) { DeviceControlActivity.this.displayGattServices(mBluetoothLeService.getSupportedGattServices()); } } }); } } @SuppressLint("ValidFragment") public class BleCharacterDialogFragment extends DialogFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.write_charact_dialog, container, false); final EditText ed = (EditText) v.findViewById(R.id.charact_value); Button ok = (Button) v.findViewById(R.id.dialog_confirm); Button cancel = (Button) v.findViewById(R.id.dialog_cancel); ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mWriteCharacteristic != null) { mWriteCharacteristic.setValue("AA"); mBluetoothLeService.mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); } // characteristic.setValue("FF"); // characteristic.setValue(new byte[] {(byte) 0xFF}); // writeCharacteristicValue(characteristic); // Toast.makeText(getApplicationContext(), "Se envío el dato", Toast.LENGTH_SHORT).show(); dismiss(); return; } }); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); return v; } } public void writeCharacteristicValue(BluetoothGattCharacteristic characteristica) { byte[] value = { (byte) 0xFF }; characteristica.setValue(bytesToHex(value)); boolean status = mBluetoothLeService.mBluetoothGatt.writeCharacteristic(characteristica); } final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); public String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; int v; for (int j = 0; j < bytes.length; j++) { v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } } 

服务

 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public class BluetoothLeService extends Service { // private final static String TAG = // BluetoothLeService.class.getSimpleName(); private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private String mBluetoothDeviceAddress; BluetoothGatt mBluetoothGatt; private int mConnectionState = STATE_DISCONNECTED; private BLEServiceCallback mBLEServiceCb = null; private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; private static final int GATT_SUCCESS=0; public final static UUID UUID_HEART_RATE_MEASUREMENT = UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); private final long READING_RSSI_TASK_FREQENCY = 500; private static final int READ_RSSI_REPEAT = 1; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case READ_RSSI_REPEAT: if (mBluetoothGatt != null) { mBluetoothGatt.readRemoteRssi(); if(DeviceControlActivity.mGattCharacteristics.size()==3) { boolean pp=mBluetoothGatt.readCharacteristic(DeviceControlActivity.mGattCharacteristics.get(2).get(0));// //BluetoothGattCallback.onCharacteristicRead(mBluetoothGatt, DeviceControlActivity.mGattCharacteristics.get(2).get(0), GATT_SUCCESS); } } sendMessageDelayed(obtainMessage(READ_RSSI_REPEAT), READING_RSSI_TASK_FREQENCY); break; } } }; private void startReadRssi() { if (mHandler.hasMessages(READ_RSSI_REPEAT)) { Log.w("+++++++++ Handler already has Message: READ_RSSI_REPEAT"); } mHandler.sendEmptyMessage(READ_RSSI_REPEAT); } private void stopReadRssi() { mHandler.removeMessages(READ_RSSI_REPEAT); } // Implements callback methods for GATT events that the app cares about. For // example, // connection change and services discovered. private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { Log.d("onConnectionStateChange status = " + status + ", newState = " + newState); if (newState == BluetoothProfile.STATE_CONNECTED) { if (mBLEServiceCb != null) { mBLEServiceCb.notifyConnectedGATT(); } Log.d("Connected to GATT server."); // Attempts to discover services after successful connection. Log.d("Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); startReadRssi(); //si se conecta empiece a leer mi caracteritica } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { if (mBLEServiceCb != null) { mBLEServiceCb.notifyDisconnectedGATT(); } stopReadRssi(); Log.d("Disconnected from GATT server."); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { Log.d("onServicesDiscovered status = " + status); if (status == BluetoothGatt.GATT_SUCCESS) { if (mBLEServiceCb != null) { mBLEServiceCb.displayGATTServices(); } } else { Log.d("onServicesDiscovered received: " + status); } setCharacteristicNotification(DeviceControlActivity.mGattCharacteristics.get(2).get(0), true);//puede que sea mejor no ponerlo, pero no se } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.d("onCharacteristicRead status: " + status); Toast.makeText(getApplicationContext(), "MMMM"+"BBB"+"SsSsSs", Toast.LENGTH_SHORT).show(); if (status == BluetoothGatt.GATT_SUCCESS) { displayCharacteristic(characteristic); } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.d("------------- onCharacteristicWrite status: " + status); // handler callback of write characteristic. // do somethings here. } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.d("onCharacteristicChanged"); Toast.makeText(getApplicationContext(), "se ejecutó el metodo de cambio en caracteristica", Toast.LENGTH_SHORT).show(); displayCharacteristic(characteristic); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { // Log.d("onReadRemoteRssi rssi = " + rssi + "; status = " + // status); if (mBLEServiceCb != null) { mBLEServiceCb.displayRssi(rssi); } } }; public void setBLEServiceCb(BLEServiceCallback cb) { if (cb != null) { mBLEServiceCb = cb; } } private void displayCharacteristic(final BluetoothGattCharacteristic characteristic) { String msg = null; // This is special handling for the Heart Rate Measurement profile. Data // parsing is // carried out as per profile specifications: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; Log.d("Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d("Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); Log.d(String.format("Received heart rate: %d", heartRate)); msg = String.valueOf(heartRate); } 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)); msg = new String(data) + "\n" + stringBuilder.toString(); } } if (mBLEServiceCb != null) { mBLEServiceCb.displayData(msg); } } 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 // BluetoothManager. if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.e("Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.e("Unable to obtain a BluetoothAdapter."); return false; } return true; } public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { Log.w("BluetoothAdapter not initialized or unspecified address."); return false; } // Previously connected device. Try to reconnect. if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { Log.d("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("Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the // autoConnect // parameter to false. mBluetoothGatt = device.connectGatt(this, false, mGattCallback); Log.d("Trying to create a new connection."); mBluetoothDeviceAddress = address; mConnectionState = STATE_CONNECTING; return true; } public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w("BluetoothAdapter not initialized"); return; } mBluetoothGatt.disconnect(); } public void close() { if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; } /** * Request a read on a given {@code BluetoothGattCharacteristic}. The read * result is reported asynchronously through the * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. * * @param characteristic * The characteristic to read from. */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { Toast.makeText(getApplicationContext(), "readCharacteristic en Servicio", Toast.LENGTH_SHORT).show(); if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w("BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); } /** * Requst a write on a give {@code BluetoothGattCharacteristic}. The write * result is reported asynchronously through the * {@code BluetoothGattCallback#onCharacteristicWrite(andorid.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. */ public void writeCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w("BluetoothAdapter not initialized"); return; } mBluetoothGatt.writeCharacteristic(characteristic); } /** * Enables or disables notification on a give characteristic. * * @param characteristic * Characteristic to act on. * @param enabled * If true, enable notification. False otherwise. */ public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w("BluetoothAdapter not initialized"); return; } mBluetoothGatt.setCharacteristicNotification(characteristic, true); // This is specific to Heart Rate Measurement. if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } } /** * Retrieves a list of supported GATT services on the connected device. This * should be invoked only after {@code BluetoothGatt#discoverServices()} * completes successfully. * * @return A {@code List} of supported services. */ public List<BluetoothGattService> getSupportedGattServices() { if (mBluetoothGatt == null) return null; return mBluetoothGatt.getServices(); } public interface BLEServiceCallback { public void displayRssi(int rssi); public void displayData(String data); public void notifyConnectedGATT(); public void notifyDisconnectedGATT(); public void displayGATTServices(); public void displayRetorno(int rssi); } } 

Solutions Collecting From Web of "订阅BLE GAT通知Android"

要在Android中接收通知,您需要将特征通知设置为true

 gatt.setCharacteristicNotification(characteristic, true); 

您还需要设置客户端特征configuration描述符0x2902

 // 0x2902 org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); BluetoothGattDescriptor descriptor = characteristic.getDescriptor(uuid); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(descriptor); 

一个更好的API将是setCharacteristicNotification来设置描述符,但不幸的是,它似乎并没有这样工作。

除了接受的答案之外,订阅运行在OS X上的外设时,必须将特征设置为WRITE_TYPE_DEFAULT。

 characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);