Android BLE,扫描开始,找到设备但未连接过滤器(ESP32 和三星)

Posted

技术标签:

【中文标题】Android BLE,扫描开始,找到设备但未连接过滤器(ESP32 和三星)【英文标题】:Android BLE, scan started, finds devices but does not connect with filter (ESP32 & Samsung) 【发布时间】:2021-02-11 06:03:58 【问题描述】:

我一直在学习几个 BLE 教程来开发一个连接到 ESP32 的应用程序,但我无法获得连接到 ESP32 的代码。我使用的是三星手机,需要延时,但我尝试过其他手机,仍然无法将 ESP32 连接到移动应用程序。

如果我运行 BLE 扫描仪应用程序,我可以连接到 ESP32,所以我相信 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=AppWindowToken5872671 token=Tokenbc8c18 ActivityRecord8ccf3fb 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=AppWindowToken49e6a47 token=Token9d5c186 ActivityRecord4490261 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=AppWindowToken49e6a47 token=Token9d5c186 ActivityRecord4490261 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

【问题讨论】:

你能粘贴日志吗? 是的,用唯一的TAG名称记录上面的代码日志并过滤它。例如:BleIssue 请将 Log.i("Debug", ...) 和 Log.d("Debug", ..) 更改为 Log.d("BLEISSUE", ..) 并显示给我们 我看到了日志。首先检查 device.type 值。它可以是经典的、ble 或双重的。如果是经典蓝牙设备,则无法通过 LE 传输连接 从日志中我看到“found something 2”已登录 onBatchScanResults() 方法。你应该处理这个事件。调用同一个connectGatt 【参考方案1】:

从日志中我看到“找到了一些东西 2”登录了 ScanCallback 的 onBatchScanResults() 方法。 你应该处理这个事件。调用与 onScanResult() 方法相同的 connectGatt。

当设备连接成功以便从设备读取消息时,您应该订阅服务并为 PROPERTY_NOTIFY 类型特征设置CharacteristicNotification。

【讨论】:

这是一个巨大的帮助,非常感谢你,你能帮助解决最后一个问题如何使用从扫描列表中选择一个设备,即 ScanResult scanResult = results.get(0);把它连接到关贸总协定? device.connect 如何以及需要什么,我们如何从列表中获取该连接? BluetoothGatt gatt = device.connectGatt(getApplicationContext(), true, mGattCallback, BluetoothDevice.TRANSPORT_LE); 你应该处理 mGattCallback 事件 onConnectionStateChange -> 如果状态为 STATE_CONNECTED 调用 discoverServices onServicesDiscovered -> 订阅服务 onCharacteristicWrite -> 从队列 onCharacteristicChanged 发送下一个数据 -> 从 ble 设备读取传入数据 接受的答案不是主要问题的答案,而是我们谈话中出现的下一个问题。【参考方案2】:

例如,您可以在 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);
                
            
        

【讨论】:

非常感谢那是辉煌的,非常解决了头撞到工作的日子

以上是关于Android BLE,扫描开始,找到设备但未连接过滤器(ESP32 和三星)的主要内容,如果未能解决你的问题,请参考以下文章

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

Android 4.4:低功耗蓝牙;无需扫描 BLE 设备即可连接

Android-Ble蓝牙开发Demo示例–扫描,连接,发送和接收数据,分包解包(附源码)

Android 低功耗蓝牙(Ble) 开发总结

如何在 Android 中获取当前连接的 BLE 外围设备