首页 > 解决方案 > BluetoothGatt.discoverServices() 返回 null

问题描述

我正在使用 Android Studio 制作一个简单的应用程序,该应用程序连接到 ble 设备并从中获取数据。已经在 nRFconnect 应用程序中检查了设备输出,并且可以在那里很好地看到流。我设法发现并连接到特定设备,在特定特征上启用了 setCharacteristicNotification,但是在使用 discoverServices() 时得到空结果并且代码被卡住。这是代码:

package com.example.basicapp;

import androidx.appcompat.app.AppCompatActivity;
import android.app.Notification;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.os.ParcelUuid;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import java.text.SimpleDateFormat;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.os.AsyncTask;

import android.os.Binder;
import android.os.IBinder;

import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {

    public static final boolean DEBUG_RX = true;
    final String devcAddress = "D8:A0:1D:47:51:42";
    private static final UUID ServiceUUID = UUID.fromString("00001809-0000-1000-8000-00805F9B34FB");
    private static final UUID CharUUID = UUID.fromString("00002A1C-0000-1000-8000-00805F9B34FB");
    private BluetoothGattCharacteristic mGattChar;
    final String devcName = "Elia";

    private String scanDevcAddress = null;
    private BluetoothAdapter mBTAdapter;
    private CheckBox mCheckBox;
    private ImageView mWaveGirl;
    private TextView mWaveStatus;
    private Button mRefreshBtn;
    private TextView mReadBuffer;
    private TextView readBufferHead;
    private TextView mBluetoothStatus;
    private TextView mBluetoothStatusHead;
    private final static int REQUEST_ENABLE_BT = 1; // used to identify adding bluetooth names
    private final static int MESSAGE_READ = 2; // used in bluetooth handler to identify message update
    private final static int CONNECTING_STATUS = 3; // used in bluetooth handler to identify message status

    private boolean mScanning;
    private static final long SCAN_PERIOD = 10000;
    private BluetoothLeScanner mBluetoothLeScanner;
    private BluetoothDevice BTdevice;
    private BluetoothGatt mBTGatt;

    private int mConnectionState = STATE_DISCONNECTED;

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public final static String ACTION_GATT_CONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED =
            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE =
            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA =
            "com.example.bluetooth.le.EXTRA_DATA";

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


        mCheckBox = (CheckBox) findViewById(R.id.checkBox);
        mBluetoothStatus = (TextView) findViewById(R.id.bluetoothStatus);
        mBluetoothStatus = (TextView) findViewById(R.id.bluetoothStatus);
        mWaveStatus = (TextView) findViewById(R.id.waveStatus);

        mBluetoothStatusHead = (TextView) findViewById(R.id.bluetoothStatusHead);
        readBufferHead = (TextView) findViewById(R.id.readBufferHead);
        mReadBuffer = (TextView) findViewById(R.id.readBuffer);
        mRefreshBtn = (Button) findViewById(R.id.refresh);

        mCheckBox = (CheckBox) findViewById(R.id.checkBox);

        mWaveGirl = (ImageView) findViewById(R.id.waveGirl);
// Initializes Bluetooth adapter.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

        mBTAdapter = bluetoothManager.getAdapter();
        mBluetoothLeScanner = mBTAdapter.getBluetoothLeScanner();

        if (mBTAdapter == null) {
            // Device does not support Bluetooth
            mBluetoothStatus.setText("Status: Bluetooth not found");
            Toast.makeText(getApplicationContext(), "Bluetooth device not found!", Toast.LENGTH_SHORT).show();
        } else {

            init();

            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                Toast.makeText(this, "BLE device detected", Toast.LENGTH_SHORT).show();
                finish();
            }

            searchDevice();

            mCheckBox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCheckBox.isChecked()) {
                        connect(devcAddress);
                    }
                }
            });
        }
    }


    private void init() {
        mCheckBox.setEnabled(false);
        mCheckBox.setText("Elia's head bow");
        mWaveGirl.setVisibility(View.INVISIBLE);
        if (!DEBUG_RX) {
            mReadBuffer.setVisibility(View.INVISIBLE);
            readBufferHead.setVisibility(View.INVISIBLE);


        }
    }

    public boolean connect(final String address) {
        // Previously connected device.  Try to reconnect.
        BTdevice = mBTAdapter.getRemoteDevice(devcAddress);
        mBTGatt = BTdevice.connectGatt(this, false, mGattCallback);
        if (mBTGatt == null){
            Log.d("ADebugTag", "mBTGatt is null");
            return false;
        }
        else {
            try {
                mGattChar = mBTGatt.getService(ServiceUUID).getCharacteristic(CharUUID);
            }
            catch (NullPointerException e){
                Log.d("ADebugTag", "mGattChar is null\n" + e);
            }
            setCharacteristicNotification(mGattChar, true);
            return true;
        }
    }

    // Enter here after user selects "yes" or "no" to enabling radio
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent Data) {
        // Check which request we're responding to
        if (requestCode == REQUEST_ENABLE_BT) {
            // Make sure the request was successful
            if (resultCode == RESULT_OK) {
                // The user picked a contact.
                // The Intent's data Uri identifies which contact was selected.
                mBluetoothStatus.setText("Bluetooth enabled");
                searchDevice();
            } else
                mBluetoothStatus.setText("Bluetooth disabled");
        }
    }

    private void searchDevice() {
        if (mBTAdapter.isEnabled()) {
            scanLeDevice(true);
        } else {
            Toast.makeText(getApplicationContext(), "To begin please turn on bluetooth", Toast.LENGTH_SHORT).show();
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mScanning = true;
            mBluetoothLeScanner.startScan(leScanCallback);
        } else {
            mScanning = false;
            mBluetoothLeScanner.stopScan(leScanCallback);
        }
    }


    // Device scan callback.
    private ScanCallback leScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BTdevice = result.getDevice();
            scanDevcAddress = result.getDevice().getAddress();
            Log.d("ADebugTag", "scanned address: " + scanDevcAddress);
            if (scanDevcAddress.equals(devcAddress)) {
                mCheckBox.setText("Elia's head bow detected");
                mCheckBox.setEnabled(true);
                scanLeDevice(false);
                Toast.makeText(getApplicationContext(), "Scanning stopped", Toast.LENGTH_SHORT).show();
            }
        }
    };

    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,mGattChar);
                Log.d("ADebugTag", "Connected to GATT server.");
                // Attempts to discover services after successful connection.
                Log.d("ADebugTag", "Attempting to start service discovery:" + mBTGatt.discoverServices());
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.d("ADebugTag", "Disconnected from GATT server.");
                broadcastUpdate(intentAction,mGattChar);
            }
        }


        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                final byte[] dataInput = characteristic.getValue();
                Log.d("ADebugTag", "Data:" + dataInput);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            final byte[] dataInput = characteristic.getValue();
            Log.d("ADebugTag", "Data:" + dataInput);
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    };


    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        // For all other profiles, writes the data formatted in HEX.
        if (characteristic == null) {
            Log.d("ADebugTag", "characteristic is null");
        }
        else {
            final byte[] data = characteristic.getValue();
            Log.d("ADebugTag", "Data:" + data);
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for (byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
                Log.d("ADebugTag", "Data:" + stringBuilder.toString());
            }
            sendBroadcast(intent);
        }
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBTAdapter == null || mBTGatt == null) {
            Log.d("ADebugTag", "BluetoothAdapter not initialized");
            return;
        }

        Log.d("ADebugTag", "mGattChar" + mGattChar.getUuid().toString());
        mBTGatt.setCharacteristicNotification(mGattChar, enabled);
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CharUUID);
        descriptor.setValue(descriptor.ENABLE_NOTIFICATION_VALUE);
        mBTGatt.writeDescriptor(descriptor);
    }

    /**
     * Disconnects an existing connection or cancel a pending connection. The disconnection result
     * is reported asynchronously through the
     * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
     * callback.
     */
    public void disconnect() {
        if (mBTAdapter == null || mBTGatt == null) {
            Log.d("ADebugTag", "BluetoothAdapter not initialized");
            return;
        }
        mBTGatt.disconnect();
    }

    /**
     * After using a given BLE device, the app must call this method to ensure resources are
     * released properly.
     */
    public void close() {
        if (mBTGatt == null) {
            return;
        }
        mBTGatt.close();
        mBTGatt = null;
    }

}






标签: javaandroidbluetoothbluetooth-lowenergy

解决方案


推荐阅读