android Ble扫描回调仅被调用几次,然后停止

lawou6xi  于 2023-02-10  发布在  Android
关注(0)|答案(2)|浏览(287)

我有2手机与Android 5.0.2,他们都安装了最新的半径信标的应用程序:定位信标,同时,我打开了2 IBeacon发送器,可以看到RSSI不断变化在两个手机与应用程序.
但当我尝试编写一些示例代码来模拟上述情况时,我发现ble scan回调总是在调用2或3次后**stop get call,我最初怀疑“定位信标”可能使用不同的方式,所以我尝试了2种API,一种是旧版4.4,另一种是Android 5中引入的新方式,但两者的行为相同(但都运行在Android 5上)。
4.4版本:

public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private static final String LOG_TAG = "BleCollector";
private TextView calledTimesTextView = null;
private int calledTimes = 0;
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
            byte[] scanRecord) {
        calledTimes++;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                calledTimesTextView.setText(Integer.toString(calledTimes));
            }
        });
        Log.e(LOG_TAG, "in onScanResult, " + " is coming...");
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    calledTimesTextView = (TextView) findViewById(R.id.CalledTimes);
    mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE))
            .getAdapter();
    mBluetoothAdapter.startLeScan(mLeScanCallback);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}}

以及5.0.2:

public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothLeScanner mLescanner;
private ScanCallback mLeScanCallback;
private static final String LOG_TAG = "BleFingerprintCollector";
private TextView calledTimesTextView = null;
private int calledTimes = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    calledTimesTextView = (TextView) findViewById(R.id.CalledTimes);
    this.mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE))
            .getAdapter();
    this.mLescanner = this.mBluetoothAdapter.getBluetoothLeScanner();

    ScanSettings bleScanSettings = new ScanSettings.Builder().setScanMode(
            ScanSettings.SCAN_MODE_LOW_LATENCY).build();

    this.mLeScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            calledTimes++;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    calledTimesTextView.setText(Integer
                            .toString(calledTimes));
                }
            });
            Log.e(LOG_TAG, "in onScanResult, " + " is coming...");
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {

        }

        @Override
        public void onScanFailed(int errorCode) {
        }
    };
    this.mLescanner.startScan(null, bleScanSettings, this.mLeScanCallback);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}}

它们非常简单,只是在UI中显示一个计数器,最终证明总是停在2或3。
我以前在三星Note 2上玩过这个ble广告接收与安卓4.4设备,它工作完美,回调得到调用每一秒.那么任何人都可以帮助?为什么半径'定位信标在这里工作得很好

nx7onnlm

nx7onnlm1#

    • 扫描 * 可连接 * BLE广告时,不同的Android设备表现不同。**在某些设备上(例如旧的Nexus 4),对于发送 * 可连接 * 广告的发射机,扫描API每次扫描仅获得一个回调,而对于 * 不可连接的 * 通告,它们获得针对每个通告的扫描回调。(例如Nexus 5和大多数2015年以后生产的产品)提供扫描回叫,无论是否可连接。

您提到的Locate app使用开源Android Beacon Library来检测信标。它基于您在问题中展示的相同扫描API构建,但它通过定义扫描周期(前台默认为1.1秒)并在此间隔停止和重新启动扫描来解决此问题。停止和重新启动扫描会导致Android发送新回调。
这里还有一些其他注意事项:

  • 获取可连接设备的多个扫描回调的问题适用于4.x和5.x扫描API。
  • 目前尚不清楚在不同设备上为可连接广告传递扫描回调的差异是由于Android固件差异还是蓝牙硬件芯片组差异。
  • 似乎没有一种方法可以检测设备是否需要重新启动扫描以获取可连接广告的其他回调,因此如果您的目标是各种设备,则需要计划停止并重新启动扫描。
  • 使用Android的原始扫描API是了解BLE信标如何工作的好方法,但使用BLE信标有很多复杂性(这只是一个例子),这就是为什么使用Android Beacon Library这样的SDK是一个很好的选择,可以让您高枕无忧。

充分披露:我是Locate app的作者,是Android Beacon Library开源项目的首席开发人员。

gt0wga4j

gt0wga4j2#

大卫-您确定扫描回调会针对每个不可连接广告调用吗?我有一部小米Redmi 3和另一部Nexus 5手机,运行Android 6.0。我有一个BLE传感器,每隔1分钟发送一次数据。这些作为中央BLE设备的手机应该接收并处理来自传感器的数据。我可以从空中下载看到(OTA)BLE捕获设备,其传感器每1分钟发送一次数据。然而,两部手机似乎以1分钟的间隔处理数据几分钟,但之后停止处理4 - 6分钟,然后开始处理ag enter code here ain。手机处理的时间间隔如下所示:1分钟、2分钟、3分钟、8分钟、9分钟、10分钟、11分钟因此,在以1分钟的间隔处理3个分组之后,任一电话将停止处理4 - 6分钟。
下面是执行处理的代码。

public class BluetoothDataReader {
    private final Context context;

    public BluetoothDataReader(Context context) {
        this.context = context;
    }

    public void startReading() {
        BluetoothAdapter btAdapter = getBluetoothAdapter();
        if (btAdapter == null) return;

        BluetoothLeScanner scanner = btAdapter.getBluetoothLeScanner();
        ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .build();
        scanner.startScan(Collections.<ScanFilter>emptyList(), settings, new ScanRecordReader());
    }

    public void uploadScanBytes(SensorDataUploader sensorDataUploader, int count) {
        BluetoothAdapter btAdapter = getBluetoothAdapter();
        if (btAdapter == null) return;

        BluetoothLeScanner scanner = btAdapter.getBluetoothLeScanner();
        ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
                .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                .build();
 //       scanner.startScan(Arrays.asList(new ScanFilter.Builder().setDeviceAddress("26:50:26:50:26:50").build()), settings, new LimitedScanRecordReader(sensorDataUploader, count, scanner));
           scanner.startScan(Collections.<ScanFilter>emptyList(), settings, new LimitedScanRecordReader(sensorDataUploader, count, scanner));
    }

    @Nullable
    private BluetoothAdapter getBluetoothAdapter() {
        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        if(btAdapter == null){
            Log.i(BluetoothDataReader.class.getName(), "No bluetooth adapter available");
            return null;
        }

        if(!btAdapter.isEnabled()){
            Log.i(BluetoothDataReader.class.getName(), "Enable bluetooth adapter");
            Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            context.startActivity(enableBluetooth);
        }
        return btAdapter;
    }

    private class LimitedScanRecordReader extends ScanCallback {
        private final int limit;
        private final BluetoothLeScanner scanner;

        private int scanRecordRead = 0;
        private final SensorDataUploader sensorDataUploader;

        private LimitedScanRecordReader( SensorDataUploader sensorDataUploader, int limit, BluetoothLeScanner scanner) {
            this.limit = limit;
            this.scanner = scanner;
            this.sensorDataUploader = sensorDataUploader;
        }

        @Override
        public void onScanResult(int callbackType, ScanResult result) {
//            if(scanRecordRead++ < limit) {
   //         if(result.getDevice().getAddress().equals("A0:E6:F8:01:02:03")) {
   //         if(result.getDevice().getAddress().equals("C0:97:27:2B:74:D5")) {

            if(result.getDevice().getAddress().equals("A0:E6:F8:01:02:03")) {
                long timestamp = System.currentTimeMillis() -
                        SystemClock.elapsedRealtime() +
                        result.getTimestampNanos() / 1000000;


                byte[] rawBytes = result.getScanRecord().getBytes();
                Log.i(DataTransferService.class.getName(), "Raw bytes: " + byteArrayToHex(rawBytes));
                sensorDataUploader.upload(timestamp, rawBytes);
            }
//            }else {
//                scanner.stopScan(this);
//            }
        }
        public String byteArrayToHex(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for(byte b: a)
                sb.append(String.format("%02x", b & 0xff));
            return sb.toString();
        }

        public void onScanFailed(int errorCode) {
            Log.i(DataTransferService.class.getName(), "Error code is:" + errorCode);
        }

        public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult> results) {
            Log.i(DataTransferService.class.getName(), "Batch scan results");
        }
    }

    private class ScanRecordReader extends ScanCallback {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            byte []rawBytes = result.getScanRecord().getBytes();
            Log.i(DataTransferService.class.getName(), "Raw bytes: " + byteArrayToHex(rawBytes ));
//            Map<ParcelUuid, byte[]> serviceData = result.getScanRecord().getServiceData();
//            for(ParcelUuid uuid : serviceData.keySet()) {
//                Log.i(DataTransferService.class.getName(), uuid.toString() + ":" +  byteArrayToHex(serviceData.get(uuid)));
//            }
//            Log.i(DataTransferService.class.getName(),result.toString());
        }
        public String byteArrayToHex(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for(byte b: a)
                sb.append(String.format("%02x", b & 0xff));
            return sb.toString();
        }

        public void onScanFailed(int errorCode) {
            Log.i(DataTransferService.class.getName(), "Error code is:" + errorCode);
        }

        public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult> results) {
            Log.i(DataTransferService.class.getName(), "Batch scan results");
        }
    }
}

相关问题