扫描蓝牙 LE 设备时出现问题(无回调)

Posted

技术标签:

【中文标题】扫描蓝牙 LE 设备时出现问题(无回调)【英文标题】:Problem in scanning Bluetooth LE devices (no callback) 【发布时间】:2020-04-28 10:23:09 【问题描述】:

我正在尝试开发一个能够连接到 BLE 设备的 android 应用。但是我很难找到 ble 设备。 scanLeDevice 方法运行但我没有回调。您可以在下面找到我的代码:我使用 Log.i() 来显示 ble 设备。 使用另一个应用程序(从商店下载),我可以找到我的 ble 设备和其他蓝牙设备。所以这不是我手机的问题。

感谢您的帮助!




public class MainActivity extends AppCompatActivity 
    private BluetoothAdapter bluetoothAdapter;
    private final int REQUEST_ENABLE_BT = 1;
    private boolean mScanning;

    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("MainActivity", "Begin");

        // Initializes Bluetooth adapter.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        // Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) 
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        
        Log.i("MainActivity", "End for permissions");

        if(Build.VERSION.SDK_INT < 21)
            scanLeDevice(true);
        else
            scanDevice(true);
        

    

    private Handler handler = new Handler();
    private void scanLeDevice(final boolean enable) 
        if (enable) 
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() 
                @Override
                public void run() 
                    mScanning = false;
                    bluetoothAdapter.stopLeScan(leScanCallback);
                
            , SCAN_PERIOD);

            mScanning = true;
            bluetoothAdapter.startLeScan(leScanCallback);
            Log.i("MainActivity", "scanning");
         else 
            mScanning = false;
            bluetoothAdapter.stopLeScan(leScanCallback);
        

    

    // Device scan callback.
    private BluetoothAdapter.LeScanCallback leScanCallback =
            new BluetoothAdapter.LeScanCallback() 
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) 
                    runOnUiThread(new Runnable() 
                        @Override
                        public void run() 
                            //Ici///////////////////////////////////////
                            Log.i("MainActivity", "Nam: "+device.getName()+" Adresse: "+device.getAddress());
                            if(device.getName() != null && device.getName().equals("RN4871-85D7"))
                                scanLeDevice(false);
                        
                    );
                
            ;

    ///////////////////Scan for API 21
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothLeScanner mLEScanner;
    private void scanDevice(final boolean enable)
        if (mLEScanner==null)
            mLEScanner = bluetoothAdapter.getBluetoothLeScanner();
            settings = new ScanSettings.Builder()
                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                    .build();
            filters = new ArrayList<ScanFilter>();
        

        if (enable) 
            if (mScanning) return;
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(new Runnable() 
                @Override
                public void run() 
                    if (!mScanning) return;
                    try 
                        mScanning = false;
                        //Log.d("MainActivity","STOP SCAN AFTER DELAY");
                        mLEScanner.stopScan(mScanCallback);
                        Log.i("MainActivity", "stop scanning API 21");
                     catch (Exception e)Log.e("MainActivity",e.getMessage());
                
            , SCAN_PERIOD);

            mScanning = true;
            //Log.d("MainActivity","START SCAN FROM EXPLICIT CALL");
            mLEScanner.startScan(filters, settings, mScanCallback);
            Log.i("MainActivity", "scanning API 21");
         else  if (mLEScanner!=null)
            if (!mScanning) return;
            mScanning = false;
            try 
                //Log.d("MainActivity","STOP SCAN FROM EXPLICIT CALL");
                mLEScanner.stopScan(mScanCallback);
                Log.i("MainActivity", "stop scanning API 21");
             catch (Exception e)Log.i("MainActivity",e.getMessage());
        
    

    //call back for API 21
    //@TargetApi(21)
    private ScanCallback mScanCallback = new ScanCallback() 
        @Override
        public void onScanResult(int callbackType, ScanResult result) 
            super.onScanResult(callbackType, result);
            Log.i("MainActivity", "onScanResult API 21");
        

        @Override
        public void onBatchScanResults(List<ScanResult> results) 
            super.onBatchScanResults(results);
            Log.i("MainActivity", "onBatchScanResults API 21");
        

        @Override
        public void onScanFailed(int errorCode) 
            super.onScanFailed(errorCode);
            Log.i("MainActivity", "onScanFailed API 21");
        
    ;



感谢您的帮助``

【问题讨论】:

您能否分享您在运行扫描时获得的日志并且 BLE 设备就在附近? 是附近的设备。问题是授权该应用访问该位置。感谢您的反应。 【参考方案1】:

我发现这个位置有什么问题。 事实上,如果您使用 API >= 23,您必须授权您的应用程序访问该位置(不仅在 Manifest 文件中,而且在您自己的代码中)。 所以如果你有同样的问题:

    首先,手动转到手机的设置,并自动让您的应用访问位置:确保这是问题所在。 然后添加下面的代码,以便应用程序要求用户授权应用程序访问该位置

    /////////////////////////Location/////
    @TargetApi(Build.VERSION_CODES.M)
    private void loadPermissions(String perm,int requestCode) 
        if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) 
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) 
                ActivityCompat.requestPermissions(this, new String[]perm,requestCode);
            
         else if (checkLocationEnabled())
            initScanner();
    
    private boolean checkLocationEnabled()
        LocationManager lm = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
        boolean gps_enabled = false;
        boolean network_enabled = false;

        try 
            gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
         catch(Exception ex) 

        try 
            network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
         catch(Exception ex) 

        if(!gps_enabled && !network_enabled) 
            // notify user
            AlertDialog.Builder dialog = new AlertDialog.Builder(this);
            dialog.setMessage("GPS desabled");
            dialog.setPositiveButton("Open GPS settings", new DialogInterface.OnClickListener() 
                @Override
                public void onClick(DialogInterface paramDialogInterface, int paramInt) 
                    // TODO Auto-generated method stub
                    Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(myIntent);
                    //get gps
                
            );
            dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() 

                @Override
                public void onClick(DialogInterface paramDialogInterface, int paramInt) 
                    // TODO Auto-generated method stub

                
            );
            dialog.show();
            return false;
         else return true;
    
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
        switch (requestCode) 
            case REQUEST_FINE_LOCATION: 
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                    // granted
                    if (checkLocationEnabled())
                        initScanner();
                
                else
                    // no granted
                
                return;
            

        

    

【讨论】:

【参考方案2】:

我也遇到了这个问题,因为我在权限上使用了ACCESS_COARSE_LOCATION

当我更改为ACCESS_FINE_LOCATION 时,它终于对我有用了!

【讨论】:

以上是关于扫描蓝牙 LE 设备时出现问题(无回调)的主要内容,如果未能解决你的问题,请参考以下文章

蓝牙 LE 不扫描设备

IOS 蓝牙 LE 扫描设备未添加到 uitableview

如何从蓝牙 LE 设备获取数据

蓝牙 LE iOS 无法在后台扫描

某些设备上没有蓝牙 gatt 回调

连接蓝牙时出现蓝牙设备不支持是怎么回事