java - 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;
}
}
解决方案
推荐阅读
- python - 如何修复 django.db.utils.ProgrammingError:关系“blog_no_of_views”不存在
- c++ - 有没有办法将类型说明符存储在变量中?
- jquery - 如何通过在联系表 7 中使用 Jquery 添加数字来修复 NaN 结果
- c# - 无法修复'IdentityUserLogin
需要主键'错误 - python - 如何在python的几个可用函数中随机重复10次?
- google-cloud-platform - vision api产品搜索的产品集数据UI
- ios - IOS推送通知RootViewController对于关闭的应用程序是nil如何呈现rootview控制器然后需要deeplink控制器
- r - 在R中使用循环改组数据帧
- php - Open Graph 协议不适用于我的 php 网站
- react-native - React Native 如何使用外部样式表文件