Java 使用notify not TRIGGED的Android onCharacteristicChanged()
我制作了一个应用程序,通过BLE与设备通信。我写下了沟通所需的一切。设备通过Java 使用notify not TRIGGED的Android onCharacteristicChanged(),java,android,ios,bluetooth-lowenergy,Java,Android,Ios,Bluetooth Lowenergy,我制作了一个应用程序,通过BLE与设备通信。我写下了沟通所需的一切。设备通过characteristic.setValue()接收发送的值,但不会像预期的那样在方法onCharacteristicChanged中返回反馈,尽管已为通知设置了描述符。例如,我发送“GTN”,应该获得“GTN设备id”(就像在iOS上一样),但它只调用onCharacteristicWrite()。还检查了特征支持的属性。它支持PROPERTY\u NOTIFY和PROPERTY\u WRITE\u NO\u RES
characteristic.setValue()
接收发送的值,但不会像预期的那样在方法onCharacteristicChanged
中返回反馈,尽管已为通知设置了描述符。例如,我发送“GTN”
,应该获得“GTN设备id”
(就像在iOS上一样),但它只调用onCharacteristicWrite()
。还检查了特征支持的属性。它支持PROPERTY\u NOTIFY
和PROPERTY\u WRITE\u NO\u RESPONSE
。我想不出它为什么不想收到回叫信息。有人能检查并告诉我发送/订阅时是否犯了一些大错误吗
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION = 1;
private static final int REQUEST_ENABLE_BLUETOOTH = 2;
private static final int REQUEST_ENABLE_LOCATION = 3;
private static final int BLUETOOTH_ENABLED = -1;
private static final int LOCATION_ENABLED = -1;
private static final int MANUFACTURER_ID = xxxxx;
private static final UUID SERVICE =xxxxxxxxxxxxx;
private static final UUID CHARACTERISTIC =xxxxxxxxxxxxxxxxx;
private static final UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private final static String TAG = "BLE";
private byte[] mfrData;
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private BluetoothGatt bluetoothGatt;
private BluetoothLeScanner bluetoothLeScanner;
private BluetoothGattService customService;
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
BluetoothGattService service = gatt.getService(SERVICE);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
enableDataNotifications(gatt, characteristic);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicRead: ");
}
@Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicWrite: ");
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(TAG, "onCharacteristicChanged: ");
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.d(TAG, "onDescriptorRead: ");
}
@Override
public void onDescriptorWrite(final BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d(TAG, "onDescriptorWrite: ");
checkCharacteristicProperties(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
new Thread(new Runnable() {
@Override
public void run() {
writeDataToCharCommand("GTN", gatt);
}
}).start();
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
Log.d(TAG, "onReliableWriteCompleted: ");
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
Log.d(TAG, "onReadRemoteRssi: ");
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
Log.d(TAG, "onMtuChanged: ");
}
};
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result.getScanRecord() != null && result.getScanRecord().getManufacturerSpecificData(MANUFACTURER_ID) != null) {
Log.d(TAG, "onScanResult: found device");
bluetoothLeScanner.stopScan(scanCallback);
boolean isBonded = result.getDevice().createBond();
if (isBonded) {
bluetoothGatt = result.getDevice().connectGatt(MainActivity.this, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
}
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.d(TAG, "onBatchScanResults: ");
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.d(TAG, "onScanFailed: ");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupBluetoothData();
checkIfSupportedBluetooth();
checkLocationPermission();
}
private void checkCharacteristicProperties(BluetoothGattCharacteristic pChar) {
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_READ " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_NOTIFY " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_BROADCAST " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_BROADCAST) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_EXTENDED_PROPS " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_INDICATE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_SIGNED_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE_NO_RESPONSE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0));
}
private void setupBluetoothData() {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
}
private void checkIfSupportedBluetooth() {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
if (bluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
}
private void checkLocationPermission() {
if (!hasGrantedLocationPermission()) {
requestLocationPermission();
} else {
checkIfBluetoothEnabled();
}
}
private boolean hasGrantedLocationPermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestLocationPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
}
private void checkIfBluetoothEnabled() {
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BLUETOOTH);
} else {
displayLocationSettingsRequest();
}
}
private void displayLocationSettingsRequest() {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(@NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS: {
scanForDevices();
break;
}
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: {
try {
status.startResolutionForResult(MainActivity.this, REQUEST_ENABLE_LOCATION);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
break;
}
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: {
break;
}
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_ENABLE_BLUETOOTH: {
if (resultCode == BLUETOOTH_ENABLED) {
displayLocationSettingsRequest();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
case REQUEST_ENABLE_LOCATION: {
if (resultCode == LOCATION_ENABLED) {
scanForDevices();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void scanForDevices() {
Log.d(TAG, "scanForDevices: ");
Toast.makeText(this, "Scanning", Toast.LENGTH_SHORT).show();
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
ScanFilter scanFilter = new ScanFilter.Builder()
.setManufacturerData(0x0361, mfrData)
.build();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(Collections.singletonList(scanFilter),
scanSettings, scanCallback);
}
private String translate(byte[] value) throws UnsupportedEncodingException {
return new String(value, StandardCharsets.UTF_8);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkIfBluetoothEnabled();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void writeDataToCharCommand(String data, BluetoothGatt gatt) {
Log.d(TAG, "writeDataToCharCommand: ");
gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC).setValue(data);
gatt.writeCharacteristic(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
}
private void enableDataNotifications(BluetoothGatt gatt, BluetoothGattCharacteristic gattCharacteristic) {
Log.d(TAG, "enableDataNotifications: ");
boolean enabled = gatt.setCharacteristicNotification(gattCharacteristic, true);
if (enabled) {
BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(DESCRIPTOR);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
public类MainActivity扩展了AppCompatActivity{
私有静态最终int请求\位置\权限=1;
专用静态最终整数请求\u启用\u蓝牙=2;
私有静态最终整数请求\启用\位置=3;
私有静态最终int BLUETOOTH_ENABLED=-1;
私有静态最终整型位置_ENABLED=-1;
私有静态最终int制造商\u ID=xxxxx;
专用静态最终UUID服务=XXXXXXXXXXXX;
专用静态最终UUID特性=xxxxxxxxxxxxxxxx;
私有静态最终UUID描述符=UUID.fromString(“00002902-0000-1000-8000-00805f9b34fb”);
私有最终静态字符串TAG=“BLE”;
专用字节[]mfrData;
私人BluetoothManager BluetoothManager;
私人蓝牙适配器;
私人蓝牙关贸总协定蓝牙关贸总协定;
私人蓝牙扫描仪;
私人蓝牙服务客户服务;
私有BluetoothGattCallback BluetoothGattCallback=新的BluetoothGattCallback(){
@凌驾
连接状态更改的公共无效(蓝牙gatt gatt、int状态、int新闻状态){
超级连接状态更改(关贸总协定、状态、新状态);
if(newState==BluetoothProfile.STATE\u CONNECTED){
关贸总协定。发现服务();
}
}
@凌驾
发现服务上的公共无效(Bluetooth gatt,int状态){
超级服务发现(关贸总协定,状态);
BluetoothGattService服务=gatt.getService(服务);
BluetoothGattCharacteristic characteristic=service.getCharacteristic(特征);
gatt.setCharacteristicNotification(特征,真实);
使能数据通知(gatt,特征);
}
@凌驾
特征读取的公共无效(蓝牙gatt、蓝牙gatt特征特征、国际状态){
超级特征阅读(关贸总协定,特征,地位);
Log.d(标签“onCharacteristicRead:”);
}
@凌驾
公共无效特征写入(最终蓝牙gatt、最终蓝牙gatt特征特征、int状态){
超级特征写入(关贸总协定、特征、状态);
Log.d(标记“onCharacteristicWrite:”);
}
@凌驾
特征变更后的公共无效(蓝牙gatt、蓝牙gatt特征特征){
超级特征改变(关贸总协定,特征);
Log.d(标记“onCharacteristicChanged”);
}
@凌驾
公共无效onDescriptorRead(蓝牙gatt、蓝牙GATTDescriptor描述符、int状态){
super.onDescriptorRead(gatt,描述符,状态);
Log.d(标记“onDescriptorRead:”);
}
@凌驾
public void onDescriptorWrite(最终蓝牙gatt、蓝牙GATTDescriptor描述符、int状态){
super.onDescriptorWrite(gatt、描述符、状态);
Log.d(标记“onDescriptorWrite:”);
checkCharacteristicProperties(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
新线程(newrunnable()){
@凌驾
公开募捐{
书面声明(GTN,gatt);
}
}).start();
}
@凌驾
公共无效可靠书面完成(蓝牙gatt,int状态){
超级可靠写入完成(关贸总协定,状态);
Log.d(标记“onReliableWriteCompleted:”);
}
@凌驾
公共无效onReadRemoteRssi(蓝牙gatt gatt、int rssi、int状态){
super.onReadRemoteRssi(gatt,rssi,status);
Log.d(标签“onReadRemoteRssi:”);
}
@凌驾
更改后的公共状态(蓝牙gatt、国际关税及贸易总协定、国际mtu、国际状态){
super.onmtu(关贸总协定、多边贸易联盟、地位);
Log.d(标记“onMtuChanged:”);
}
};
private ScanCallback ScanCallback=新建ScanCallback(){
@凌驾
公共void onScanResult(int callbackType、ScanResult){
super.onScanResult(回调类型、结果);
if(result.getScanRecord()!=null&&result.getScanRecord().getManufacturerSpecificATA(制造商ID)!=null){
Log.d(标记“onScanResult:found device”);
bluetoothLeScanner.stopScan(扫描回调);
布尔值isbond=result.getDevice().createBond();
如果(已绑定){
bluetoothGatt=result.getDevice().connectGatt(MainActivity.this,false,bluetoothGattCallback,BluetoothDevice.TRANSPORT_LE);
}
}
}
@凌驾
public void onBatchScanResults(列出结果){
super.onBatchScanResults(结果);
Log.d(标记为“onBatchScanResults:”);
}
@凌驾
公共无效OnScan失败(内部错误代码){
super.onscan失败(错误代码);
Log.d(标记“onScanFa
public void markCharForNotification(BluetoothGattCharacteristic readableChar) {
mBluetoothGatt.setCharacteristicNotification(readableChar, true);
List<BluetoothGattDescriptor> listDescr = readableChar.getDescriptors();
BluetoothGattDescriptor descriptor = listDescr.get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
int properties = characteristic.getProperties();
if (descriptor != null) {
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
gatt.writeDescriptor(descriptor);