2014-11-05 51 views
1

我正在尝试获取自定义设备的通知。我知道设备正在工作,因为在iOS中使用Lightblue应用程序时,我收到了通知。我已经尝试了一个nexus 5和一个三星s4(都kitkats)。似乎没有任何工作。我的“onCharacteristicChanged”没有被调用。如何在android中获取BLE通知?

MainActivity.java

package com.foo.ble; 

import android.app.Activity; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothManager; 
import android.content.Context; 
import android.os.Bundle; 
import android.os.Handler; 
import android.util.Log; 


public class MainActivity extends Activity implements BluetoothAdapter.LeScanCallback { 
    private BluetoothAdapter adapter; 

    final private static char[] hexArray = "ABCDEF".toCharArray(); 
    private Callback callback; 

    /** 
    * Converts 0xfe to "FE" 
    * @return hex representation of the adScanned 
    */ 
    public static String getPayload(final byte[] adScanned) { 
     if (adScanned == null) return "N/A"; 

     final char[] hexChars = new char[adScanned.length * 2]; 
     for (int j = 0; j < adScanned.length; j++) { 
      final int v = adScanned[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
     adapter = manager.getAdapter(); 
     callback = new Callback(); 

     Handler handler = new Handler(); 
     handler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       adapter.stopLeScan(MainActivity.this); 
      } 
     }, 3*10000); 

     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       adapter.startLeScan(MainActivity.this); 
      } 
     }); 
    } 

    @Override 
    public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { 
     if (device.getAddress().equals("CE:AD:09:F2:BB:DC")) { 
      Log.d("foo", "onLeScan payload:" + getPayload(scanRecord)); 
      adapter.stopLeScan(this); 
      runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        device.connectGatt(MainActivity.this, true, callback); 
       } 
      }); 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     callback.close(); 
    } 
} 

Callback.java

package com.foo.ble; 

import android.bluetooth.BluetoothGatt; 
import android.bluetooth.BluetoothGattCallback; 
import android.bluetooth.BluetoothGattCharacteristic; 
import android.bluetooth.BluetoothGattDescriptor; 
import android.bluetooth.BluetoothProfile; 
import android.util.Log; 

import java.util.UUID; 

public class Callback extends BluetoothGattCallback { 
    final static UUID SERVICE = UUID.fromString("something1"); 
    final static UUID ADV_CHAR = UUID.fromString("something2"); 
    final static UUID ADV_DESCRIPTOR = UUID.fromString("something3"); 

    BluetoothGatt gatt; 

    public void close() { 
     if (gatt == null) return; 
     Log.d("foo", "close with gatt"); 

     gatt.disconnect(); 
     gatt.close(); 
     gatt = null; 
    } 

    @Override 
    public void onConnectionStateChange(final BluetoothGatt gatt, final int status, 
             final int newState) { 
     Log.d("foo", "onConnectionStateChange"); 
     if (newState == BluetoothProfile.STATE_CONNECTED) { 
      Log.d("foo", "status connected"); 
      this.gatt = gatt; 
      gatt.discoverServices(); 
     } 
    } 

    @Override 
    public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { 
     Log.d("foo", "onServicesDiscovered"); 
     if (status == BluetoothGatt.GATT_SUCCESS) { 
      final BluetoothGattCharacteristic characteristic = 
        gatt.getService(SERVICE).getCharacteristic(ADV_CHAR); 
      final BluetoothGattDescriptor descriptor = 
        characteristic.getDescriptor(ADV_DESCRIPTOR); 
      descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
      gatt.setCharacteristicNotification(characteristic, true); 
      gatt.writeDescriptor(descriptor); 
     } 
    } 

    @Override 
    public void onCharacteristicRead(final BluetoothGatt gatt, 
            final BluetoothGattCharacteristic characteristic, 
            final int status) { 
     Log.d("foo", "onCharacteristicRead status:" + status + " payload: " + 
       MainActivity.getPayload(characteristic.getValue())); 
    } 

    @Override 
    public void onCharacteristicWrite(final BluetoothGatt gatt, 
             final BluetoothGattCharacteristic characteristic, 
             final int status) { 
     Log.d("foo", "onCharacteristicWrite"); 
    } 

    @Override 
    public void onCharacteristicChanged(final BluetoothGatt gatt, 
             final BluetoothGattCharacteristic characteristic) { 
     Log.d("foo", "onCharacteristicChanged payload:" + 
       MainActivity.getPayload(characteristic.getValue())); 
    } 

    @Override 
    public void onDescriptorWrite(final BluetoothGatt gatt, 
            final BluetoothGattDescriptor descriptor, 
            final int status) { 
     Log.d("foo", "onDescriptorWrite status: " + status); 
     final BluetoothGattCharacteristic characteristic = 
       gatt.getService(SERVICE).getCharacteristic(ADV_CHAR); 
     if (characteristic.getValue() != null) { 
      Log.d("foo", "value: " + MainActivity.getPayload(characteristic.getValue())); 
     } else { 
      gatt.readCharacteristic(characteristic); 
     } 
    } 

} 

我的AndroidManifest.xml有:

<uses-permission android:name="android.permission.BLUETOOTH" /> 
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 

日志看起来是这样的:

11-05 12:17:13.314 3683-3683/com.foo.ble D/BluetoothAdapter﹕ startLeScan(): null 
11-05 12:17:13.364 3683-3695/com.foo.ble D/BluetoothAdapter﹕ onClientRegistered() - status=0 clientIf=5 
11-05 12:17:13.394 3683-3683/com.foo.ble I/Adreno-EGL﹕ <qeglDrvAPI_eglInitialize:320>: EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13 
11-05 12:17:13.414 3683-3683/com.foo.ble D/OpenGLRenderer﹕ Enabling debug mode 0 
11-05 12:17:13.454 3683-3683/com.foo.ble D/dalvikvm﹕ GC_FOR_ALLOC freed 238K, 2% free 16971K/17240K, paused 14ms, total 14ms 
11-05 12:17:15.174 3683-3694/com.foo.ble D/foo﹕ onLeScan payload:02010517FF0000000000000005000000000000000000395401001207086C6976656C7911072E9AB04DB9790F857A4CF0634C7AB94A000000000000000000 
11-05 12:17:15.174 3683-3694/com.foo.ble D/BluetoothAdapter﹕ stopLeScan() 
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ connect() - device: CE:AD:09:F2:BB:DC, auto: true 
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ registerApp() 
11-05 12:17:15.184 3683-3683/com.foo.ble D/BluetoothGatt﹕ registerApp() - UUID=605cbd6f-6080-4fd8-97ff-1f97b406258e 
11-05 12:17:15.194 3683-3695/com.foo.ble D/BluetoothGatt﹕ onClientRegistered() - status=0 clientIf=5 
11-05 12:17:43.344 3683-3683/com.foo.ble D/BluetoothAdapter﹕ stopLeScan() 
11-05 12:23:59.194 3683-3694/com.foo.ble D/BluetoothGatt﹕ onClientConnectionState() - status=0 clientIf=5 device=CE:AD:09:F2:BB:DC 
11-05 12:23:59.194 3683-3694/com.foo.ble D/foo﹕ onConnectionStateChange 
11-05 12:23:59.204 3683-3694/com.foo.ble D/foo﹕ status connected 
11-05 12:23:59.204 3683-3694/com.foo.ble D/BluetoothGatt﹕ discoverServices() - device: CE:AD:09:F2:BB:DC 
11-05 12:24:00.754 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=randomService1 
11-05 12:24:00.764 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=randomService2 
11-05 12:24:00.784 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetService() - Device=CE:AD:09:F2:BB:DC UUID=something1 
11-05 12:24:00.794 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID1 
11-05 12:24:00.804 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID2 
11-05 12:24:00.804 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID3 
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID4 
11-05 12:24:00.814 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID5 
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID6 
11-05 12:24:00.814 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=randomUUID7 
11-05 12:24:00.814 3683-3695/com.foo.ble D/BluetoothGatt﹕ onGetCharacteristic() - Device=CE:AD:09:F2:BB:DC UUID=something2 
11-05 12:24:00.824 3683-3694/com.foo.ble D/BluetoothGatt﹕ onGetDescriptor() - Device=CE:AD:09:F2:BB:DC UUID=something3 
11-05 12:24:00.824 3683-3695/com.foo.ble D/BluetoothGatt﹕ onSearchComplete() = Device=CE:AD:09:F2:BB:DC Status=0 
11-05 12:24:00.824 3683-3695/com.foo.ble D/foo﹕ onServicesDiscovered 
11-05 12:24:00.824 3683-3695/com.foo.ble D/BluetoothGatt﹕ setCharacteristicNotification() - uuid: something2 enable: true 
11-05 12:24:00.834 3683-3695/com.foo.ble D/BluetoothGatt﹕ writeDescriptor() - uuid: something3 
11-05 12:24:00.894 3683-3694/com.foo.ble D/BluetoothGatt﹕ onDescriptorWrite() - Device=CE:AD:09:F2:BB:DC UUID=something3 
11-05 12:24:00.894 3683-3694/com.foo.ble D/foo﹕ onDescriptorWrite status: 0 
11-05 12:24:00.894 3683-3694/com.foo.ble D/BluetoothGatt﹕ readCharacteristic() - uuid: something2 
11-05 12:24:00.994 3683-3695/com.foo.ble D/BluetoothGatt﹕ onCharacteristicRead() - Device=CE:AD:09:F2:BB:DC UUID=something2 Status=0 
11-05 12:24:00.994 3683-3695/com.foo.ble D/foo﹕ onCharacteristicRead status:0 payload: 0000000000050000000000000000005154010012 

任何帮助将不胜感激!

+0

什么不工作?您的日志似乎显示成功状态。 – 2014-11-05 21:48:20

+0

我没有收到通知,没有“onCharacteristicChanged” – eipipuz 2014-11-05 21:53:28

+0

在调试过程中,如果您在OnCharacteristicChanged方法的其他地方设置了断点,实际上您会收到来自远程设备的通知。 – 2014-11-06 11:50:30

回答

2

我观察到通知或者不能使用某些电话/外设/环境组合,或者在工作于相同连接会话后停止工作,没有明显的原因。所有通话都会返回成功,但通知不会通过。无论您是否解决眼前的问题,您都应该考虑为您的特征值进行读取轮询,作为备用解决方案。

您的onServicesDiscovered()方法中的各种调用也应该通过对您调用的各种gatt方法的返回值进行条件检查来进行门控。

无论如何,有些事情你可以尝试:

  • 尝试重置蓝牙堆栈通过你的手机设置,甚至重新启动整个手机。
  • 测试其他设备。有适用于iOS的应用程序可让您的iPhone充当外围设备。尝试连接到这样的“模拟设备”,看看通知是否在这种情况下工作。
  • 尝试其他Android手机。我观察到,如果这就是您使用的Nexus 4,它的通知最多。

最后,我会像技术支持一样询问计算机是否插入:确保外设的特性值确实在变化。

+0

感谢您的回答Doug 。我不知道如何继续。正如你所说,一旦我尝试使用另一部电话,相同的代码工作。对于nexus,我发现这是一个等待高达7分钟的问题o对于S4我一直无法使它工作(是的,我正在运行在UI线程上)。我不知道什么是解决这个问题的最好方法。 – eipipuz 2014-11-14 17:34:58

+0

7分钟等待通过将device.connectGatt(MainActivity.this,true,callback);更改为'device.connectGatt(MainActivity.this,false,callback);'来“固定”。我不知道第二个参数造成如此大的差异。 – eipipuz 2014-11-14 17:37:52

+0

是autoConnect非常复杂。对于某些电话和无线设备的组合,这个布尔值必须是真的,对于其他的则是假的。对于其他人来说,真实的是更持续成功,但连接起来更慢对于强大的连接流程,您必须在运行时进行基本实验,即时尝试不同的组合,直至成功连接,然后记住后续连接尝试的设置。如果最终使用“autoConnect”设置为true,则必须小心,因为本机堆栈可以非常积极地尝试永久连接,甚至是首先被发现。 – 2014-11-14 20:36:16