Android BLE,扫描开始,找到设备但未连接过滤器(ESP32 和三星)
Android BLE, scan started, finds devices but does not connect with filter (ESP32 & Samsung)
我一直在研究几个 BLE 教程来开发一个连接到 ESP32 的应用程序,但我无法获得连接到 ESP32 的代码。我用的三星 phone 需要延时,但我试过其他 phones 仍然无法将 ESP32 连接到移动应用程序。
如果我 运行 我可以连接到 ESP32 的 BLE 扫描仪应用程序,所以我相信 ESP32 端没问题。如果我们扫描设备,我们可以在蓝牙设备列表中看到它。
代码已设置为检测和连接,我尝试了 UUID 和设备名称文件管理器,但无法连接。 ScanCallback 被触发,我们调用了 onBatchScanResults 函数,因此我们可以看到设备列表,但它不会连接到 ESP32。我认为它应该自动连接 gatt 函数。
我不知道为什么它不会自动连接到 ESP32,因为它看到设备并且扫描连接已被触发。非常感谢任何帮助来解决这个问题,因为我 运行 不知道如何解决它。
package com.example.sandpit_ble002;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
// Based on the following resource
// https://medium.com/@martijn.van.welie/making-android-ble-work-part-1-a736dcd53b02
// https://developer.android.com/guide/topics/connectivity/bluetooth-le#java
public class MainActivity extends AppCompatActivity
{
UUID BLP_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
private static final int REQUEST_ENABLE_BT = 1;
private static final int ACCESS_COARSE_LOCATION_REQUEST = 2;
private boolean mScanning;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState)
{
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
CheckPermissions();
hasPermissions();
if (!bluetoothAdapter.isEnabled())
{
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
.setReportDelay(10)
.build();
/*
UUID[] serviceUUIDs = new UUID[]{BLP_SERVICE_UUID};
List<ScanFilter> filters = null;
Log.d("Debug", "debug 005");
if(serviceUUIDs != null)
{
Log.d("Debug", "debug 004");
filters = new ArrayList<>();
for (UUID serviceUUID : serviceUUIDs) {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(new ParcelUuid(serviceUUID))
.build();
filters.add(filter);
}
}
*/
String[] names = new String[]{"ESP32 UART Test"};
List<ScanFilter> filters = null;
if(names != null) {
filters = new ArrayList<>();
for (String name : names) {
ScanFilter filter = new ScanFilter.Builder()
.setDeviceName(name)
.build();
filters.add(filter);
}
}
if (scanner != null)
{
scanner.startScan(filters, scanSettings, scanCallback);
Log.d("Debug", "scan started");
} else {
Log.e("Debug", "could not get scanner object");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private boolean hasPermissions() {
Log.i("Debug", "Debug 020");
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.i("Debug", "Debug 021");
requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
return false;
}
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState)
{
if (newState == BluetoothProfile.STATE_CONNECTED)
{
Log.i("Debug", "Debug 014");
gatt.discoverServices();
} else {
Log.i("Debug", "Debug 015");
gatt.close();
}
}
private final ScanCallback scanCallback = new ScanCallback()
{
@Override
public void onScanResult(int callbackType, ScanResult result)
{
BluetoothDevice device = result.getDevice();
Log.i("Debug", "fScanCallback");
// ...do whatever you want with this found device
Log.i("Debug", "found something 1");
BluetoothGatt gatt = device.connectGatt( getApplicationContext(), true, mGattCallback, BluetoothDevice.TRANSPORT_LE);
Log.d("Debug", "Trying to create a new connection.");
}
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState)
{
Log.i("Debug", "Debug 017");
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED)
{
// We successfully connected, proceed with service discovery
Log.i("Debug", "Debug 013");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED)
{
// We successfully disconnected on our own request
Log.i("Debug", "Debug 012");
gatt.close();
} else
{
// We're CONNECTING or DISCONNECTING, ignore for now
Log.i("Debug", "Debug 011");
}
} else {
// An error happened...figure out what happened!
Log.i("Debug", "Debug 010");
gatt.close();
}
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback()
{
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED)
{
Log.i("Debug", "Connected to GATT server.");
// Attempts to discover services after successful connection.
}
else if (newState == BluetoothProfile.STATE_DISCONNECTED)
{
Log.i("Debug", "Debug 009");
}
}
};
@Override
public void onBatchScanResults(List<ScanResult> results)
{
Log.i("Debug", "found something 2");
}
@Override
public void onScanFailed(int errorCode) {
Log.i("Debug", "found something 3");
}
};
private boolean CheckPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
Log.i("Debug", "Debug 001");
requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
Log.i("Debug", "Debug 002");
}
return true;
}
}
清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.sandpit_ble002">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
日志文件
2020-10-28 20:02:58.856 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{5872671 token=Token{bc8c18 ActivityRecord{8ccf3fb u0 com.sec.android.app.launcher/.activities.LauncherActivity t256}}})/@0x319a60 - animation-bounds]
2020-10-28 20:02:58.859 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{49e6a47 token=Token{9d5c186 ActivityRecord{4490261 u0 com.example.sandpit_ble002/.MainActivity t333}}})/@0x5fb6af6 - animation-leash]
2020-10-28 20:02:58.860 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{49e6a47 token=Token{9d5c186 ActivityRecord{4490261 u0 com.example.sandpit_ble002/.MainActivity t333}}})/@0x5fb6af6 - animation-bounds]
2020-10-28 20:02:59.075 10090-10090/com.example.sandpit_ble002 I/Debug: Debug 002
2020-10-28 20:02:59.075 10090-10090/com.example.sandpit_ble002 I/Debug: Debug 020
2020-10-28 20:02:59.085 10090-10090/com.example.sandpit_ble002 D/Debug: scan started
2020-10-28 20:02:59.295 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [1aaa92c com.example.sandpit_ble002/com.example.sandpit_ble002.MainActivity]
2020-10-28 20:02:59.322 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [com.example.sandpit_ble002/com.example.sandpit_ble002.MainActivity$_10090]
2020-10-28 20:02:59.382 3867-3941/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=e0e9827 Splash Screen com.example.sandpit_ble002)/@0x3d1cb48 - animation-leash]
2020-10-28 20:03:04.132 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
2020-10-28 20:03:09.159 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
2020-10-28 20:03:14.180 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
从日志中我看到“found something 2”记录在 ScanCallback 的 onBatchScanResults() 方法中。
你应该处理这个事件。调用 onScanResult() 方法中使用的相同 connectGatt。
当设备连接成功以便从设备读取消息时,您应该为 PROPERTY_NOTIFY 类型特征订阅服务和 setCharacteristicNotification。
例如,您可以在 onBatchScanResults()
中执行类似的操作
@Override
public void onBatchScanResults(List<ScanResult> results)
{
for (ScanResult result: results) {
BluetoothDevice myDevice = result.getDevice();
Log.i("Debug", "onBatchScanResults: " + myDevice.getName());
if(myDevice.getName().equals("ESP32 UART Test")){
BluetoothGatt bluetoothGatt = myDevice.connectGatt(getApplicationContext(), true, mGattCallback, BluetoothDevice.TRANSPORT_LE);
}
}
}
我一直在研究几个 BLE 教程来开发一个连接到 ESP32 的应用程序,但我无法获得连接到 ESP32 的代码。我用的三星 phone 需要延时,但我试过其他 phones 仍然无法将 ESP32 连接到移动应用程序。
如果我 运行 我可以连接到 ESP32 的 BLE 扫描仪应用程序,所以我相信 ESP32 端没问题。如果我们扫描设备,我们可以在蓝牙设备列表中看到它。
代码已设置为检测和连接,我尝试了 UUID 和设备名称文件管理器,但无法连接。 ScanCallback 被触发,我们调用了 onBatchScanResults 函数,因此我们可以看到设备列表,但它不会连接到 ESP32。我认为它应该自动连接 gatt 函数。
我不知道为什么它不会自动连接到 ESP32,因为它看到设备并且扫描连接已被触发。非常感谢任何帮助来解决这个问题,因为我 运行 不知道如何解决它。
package com.example.sandpit_ble002;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
// Based on the following resource
// https://medium.com/@martijn.van.welie/making-android-ble-work-part-1-a736dcd53b02
// https://developer.android.com/guide/topics/connectivity/bluetooth-le#java
public class MainActivity extends AppCompatActivity
{
UUID BLP_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
private static final int REQUEST_ENABLE_BT = 1;
private static final int ACCESS_COARSE_LOCATION_REQUEST = 2;
private boolean mScanning;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState)
{
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
CheckPermissions();
hasPermissions();
if (!bluetoothAdapter.isEnabled())
{
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
.setReportDelay(10)
.build();
/*
UUID[] serviceUUIDs = new UUID[]{BLP_SERVICE_UUID};
List<ScanFilter> filters = null;
Log.d("Debug", "debug 005");
if(serviceUUIDs != null)
{
Log.d("Debug", "debug 004");
filters = new ArrayList<>();
for (UUID serviceUUID : serviceUUIDs) {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(new ParcelUuid(serviceUUID))
.build();
filters.add(filter);
}
}
*/
String[] names = new String[]{"ESP32 UART Test"};
List<ScanFilter> filters = null;
if(names != null) {
filters = new ArrayList<>();
for (String name : names) {
ScanFilter filter = new ScanFilter.Builder()
.setDeviceName(name)
.build();
filters.add(filter);
}
}
if (scanner != null)
{
scanner.startScan(filters, scanSettings, scanCallback);
Log.d("Debug", "scan started");
} else {
Log.e("Debug", "could not get scanner object");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private boolean hasPermissions() {
Log.i("Debug", "Debug 020");
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.i("Debug", "Debug 021");
requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
return false;
}
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState)
{
if (newState == BluetoothProfile.STATE_CONNECTED)
{
Log.i("Debug", "Debug 014");
gatt.discoverServices();
} else {
Log.i("Debug", "Debug 015");
gatt.close();
}
}
private final ScanCallback scanCallback = new ScanCallback()
{
@Override
public void onScanResult(int callbackType, ScanResult result)
{
BluetoothDevice device = result.getDevice();
Log.i("Debug", "fScanCallback");
// ...do whatever you want with this found device
Log.i("Debug", "found something 1");
BluetoothGatt gatt = device.connectGatt( getApplicationContext(), true, mGattCallback, BluetoothDevice.TRANSPORT_LE);
Log.d("Debug", "Trying to create a new connection.");
}
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState)
{
Log.i("Debug", "Debug 017");
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED)
{
// We successfully connected, proceed with service discovery
Log.i("Debug", "Debug 013");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED)
{
// We successfully disconnected on our own request
Log.i("Debug", "Debug 012");
gatt.close();
} else
{
// We're CONNECTING or DISCONNECTING, ignore for now
Log.i("Debug", "Debug 011");
}
} else {
// An error happened...figure out what happened!
Log.i("Debug", "Debug 010");
gatt.close();
}
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback()
{
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED)
{
Log.i("Debug", "Connected to GATT server.");
// Attempts to discover services after successful connection.
}
else if (newState == BluetoothProfile.STATE_DISCONNECTED)
{
Log.i("Debug", "Debug 009");
}
}
};
@Override
public void onBatchScanResults(List<ScanResult> results)
{
Log.i("Debug", "found something 2");
}
@Override
public void onScanFailed(int errorCode) {
Log.i("Debug", "found something 3");
}
};
private boolean CheckPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
Log.i("Debug", "Debug 001");
requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
Log.i("Debug", "Debug 002");
}
return true;
}
}
清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.sandpit_ble002">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
日志文件
2020-10-28 20:02:58.856 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{5872671 token=Token{bc8c18 ActivityRecord{8ccf3fb u0 com.sec.android.app.launcher/.activities.LauncherActivity t256}}})/@0x319a60 - animation-bounds]
2020-10-28 20:02:58.859 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{49e6a47 token=Token{9d5c186 ActivityRecord{4490261 u0 com.example.sandpit_ble002/.MainActivity t333}}})/@0x5fb6af6 - animation-leash]
2020-10-28 20:02:58.860 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=AppWindowToken{49e6a47 token=Token{9d5c186 ActivityRecord{4490261 u0 com.example.sandpit_ble002/.MainActivity t333}}})/@0x5fb6af6 - animation-bounds]
2020-10-28 20:02:59.075 10090-10090/com.example.sandpit_ble002 I/Debug: Debug 002
2020-10-28 20:02:59.075 10090-10090/com.example.sandpit_ble002 I/Debug: Debug 020
2020-10-28 20:02:59.085 10090-10090/com.example.sandpit_ble002 D/Debug: scan started
2020-10-28 20:02:59.295 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [1aaa92c com.example.sandpit_ble002/com.example.sandpit_ble002.MainActivity]
2020-10-28 20:02:59.322 3867-4291/? I/SurfaceFlinger: createSurf start. lock debugging [com.example.sandpit_ble002/com.example.sandpit_ble002.MainActivity$_10090]
2020-10-28 20:02:59.382 3867-3941/? I/SurfaceFlinger: createSurf start. lock debugging [Surface(name=e0e9827 Splash Screen com.example.sandpit_ble002)/@0x3d1cb48 - animation-leash]
2020-10-28 20:03:04.132 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
2020-10-28 20:03:09.159 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
2020-10-28 20:03:14.180 10090-10090/com.example.sandpit_ble002 I/Debug: found something 2
从日志中我看到“found something 2”记录在 ScanCallback 的 onBatchScanResults() 方法中。 你应该处理这个事件。调用 onScanResult() 方法中使用的相同 connectGatt。
当设备连接成功以便从设备读取消息时,您应该为 PROPERTY_NOTIFY 类型特征订阅服务和 setCharacteristicNotification。
例如,您可以在 onBatchScanResults()
@Override
public void onBatchScanResults(List<ScanResult> results)
{
for (ScanResult result: results) {
BluetoothDevice myDevice = result.getDevice();
Log.i("Debug", "onBatchScanResults: " + myDevice.getName());
if(myDevice.getName().equals("ESP32 UART Test")){
BluetoothGatt bluetoothGatt = myDevice.connectGatt(getApplicationContext(), true, mGattCallback, BluetoothDevice.TRANSPORT_LE);
}
}
}