Android BLE 扫描问题

Posted

技术标签:

【中文标题】Android BLE 扫描问题【英文标题】:Android BLE scan issue 【发布时间】:2021-03-06 15:38:17 【问题描述】:

我正在尝试在我的 android 手机上创建一个简单的 BLE 应用程序。 我已经尝试了很多没有成功的例子,我必须忘记一些东西。 希望你能帮助我。 首先你会发现添加的权限,然后是我的简单活动

权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

还有我的活动: 两个按钮,一个用于执行扫描,另一个用于停止它。 我想检测一个 BLE 设备,但我的代码从来没有检测到任何东西。

public class MainActivity extends AppCompatActivity 

        BluetoothManager btManager;
        BluetoothAdapter btAdapter;
        BluetoothLeScanner btScanner;
        Button startScanningButton;
        Button stopScanningButton;
        TextView peripheralTextView;
        private final static int REQUEST_ENABLE_BT = 1;
        private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;

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

            peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
            peripheralTextView.setMovementMethod(new ScrollingMovementMethod());

            startScanningButton = (Button) findViewById(R.id.StartScanButton);
            startScanningButton.setOnClickListener(new View.OnClickListener() 
                public void onClick(View v) 
                    startScanning();
                
            );

            stopScanningButton = (Button) findViewById(R.id.StopScanButton);
            stopScanningButton.setOnClickListener(new View.OnClickListener() 
                public void onClick(View v) 
                    stopScanning();
                
            );
            stopScanningButton.setVisibility(View.INVISIBLE);

            btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
            btAdapter = BluetoothAdapter.getDefaultAdapter();

            if ( btAdapter == null ) 
                Toast.makeText(
                        this,
                        "Bluetooth not supported on this deveice",
                        Toast.LENGTH_LONG).show();
                return;
            

            btScanner = btAdapter.getBluetoothLeScanner();
            btScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
            // Ensures Bluetooth is available on the device and it is enabled. If not,
            // displays a dialog requesting user permission to enable Bluetooth.
            if (btAdapter == null || !btAdapter.isEnabled()) 
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            


            if ( ! btAdapter.isEnabled() ) 
                // Demande à activer l'interface bluetooth
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            

            if ( checkSelfPermission( Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED ) 
                requestPermissions(
                        new String[]   android.Manifest.permission.ACCESS_COARSE_LOCATION  ,
                        456 );
            


            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) 
                Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
                finish();
            



            if (btAdapter != null && !btAdapter.isEnabled()) 
                Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
            


            if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
                final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("This app needs location access");
                builder.setMessage("Please grant location access so this app can detect peripherals.");
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(new DialogInterface.OnDismissListener() 
                    @Override
                    public void onDismiss(DialogInterface dialog) 
                        requestPermissions(new String[]Manifest.permission.ACCESS_COARSE_LOCATION, PERMISSION_REQUEST_COARSE_LOCATION);
                    
                );
                builder.show();
            
        

       
        private ScanCallback leScanCallback = new ScanCallback() 
            @Override
            public void onScanResult(int callbackType, ScanResult result) 
                peripheralTextView.append("Device Name: " + result.getDevice().getName() + " rssi: " + result.getRssi() + "\n");
                super.onScanResult(callbackType, result);
              
                final int scrollAmount = peripheralTextView.getLayout().getLineTop(peripheralTextView.getLineCount()) - peripheralTextView.getHeight();
               
                if (scrollAmount > 0)
                    peripheralTextView.scrollTo(0, scrollAmount);
            
        ;

        @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) 
            switch (requestCode) 
                case PERMISSION_REQUEST_COARSE_LOCATION: 
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                        System.out.println("coarse location permission granted");
                     else 
                        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                        builder.setTitle("Functionality limited");
                        builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.setOnDismissListener(new DialogInterface.OnDismissListener() 

                            @Override
                            public void onDismiss(DialogInterface dialog) 
                            

                        );
                        builder.show();
                    
                    return;
                
            
        
    private boolean mScanning = false;
    private Handler handler = new Handler();
    private static final long SCAN_PERIOD = 30000;

        public void startScanning() 
            System.out.println("start scanning");
            peripheralTextView.setText("");
            startScanningButton.setVisibility(View.INVISIBLE);
            stopScanningButton.setVisibility(View.VISIBLE);
            if (!mScanning) 
                // Stops scanning after a pre-defined scan period.
                handler.postDelayed(new Runnable() 
                    @Override
                    public void run() 
                        mScanning = false;
                        btScanner.stopScan(leScanCallback);
                        System.out.println("stop scanning");
                    
                , SCAN_PERIOD);

                mScanning = true;
                btScanner.startScan(leScanCallback);
                System.out.println("restart scanning");
             else 
                mScanning = false;
                btScanner.stopScan(leScanCallback);
                System.out.println("stop scanning");
            
        

        public void stopScanning() 
            System.out.println("stopping scanning");
            peripheralTextView.append("Stopped Scanning");
            startScanningButton.setVisibility(View.VISIBLE);
            stopScanningButton.setVisibility(View.INVISIBLE);
            AsyncTask.execute(new Runnable() 
                @Override
                public void run() 
                    btScanner.stopScan(leScanCallback);
                
            );
        
    

我从不扫描任何东西.. 完全是新手,非常感谢您的帮助。

问候

【问题讨论】:

【参考方案1】:

您还需要声明 ACCESS_BACKGROUND_LOCATION 才能找到其他蓝牙设备。你可以在这里找到更多信息:-

https://developer.android.com/guide/topics/connectivity/bluetooth#Permissions Bluetooth LE Scan fails in the background - permissions Turn on Android LE scanning without asking user for permission

下面的链接对于开始使用 Android LE 开发很有用:-

The Ultimate Guide to Android BLE Development Android Lollipop: Bluetooth LE Matures Bluetooth LE Send String Data between Devices

【讨论】:

不,如果您只在应用程序处于前台时使用扫描,则不需要后台位置。您需要在运行时向用户询问 android.permission.ACCESS_FINE_LOCATION 权限。

以上是关于Android BLE 扫描问题的主要内容,如果未能解决你的问题,请参考以下文章

BLE 扫描在 Android 中不起作用

Android BLE 扫描屏幕关闭(使用 Galaxy)

Android代码不扫描BLE设备CC2650

检测Android App收到扫描请求时是不是发送BLE扫描响应

由于位置许可,BLE 蓝牙扫描无法在 Android 10 和 11 上运行

Android BLE扫描模式设置间隔