Java 使用notify not TRIGGED的Android onCharacteristicChanged()

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

我制作了一个应用程序,通过BLE与设备通信。我写下了沟通所需的一切。设备通过
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);