与 API>=21 AND API<21 兼容的 Android 低功耗蓝牙代码

标签 android bluetooth bluetooth-lowenergy android-bluetooth

我正在开发一个必须与 BLE 设备连接的应用程序,在我的代码中,我想使用从 API 21 (Android 5) 实现的 BLE 的新 Scan 和 ScanCallback,但我必须保持与 Android 4.3 的兼容性及以上。

所以我写了代码,比如,是这样写的:

        if (Build.VERSION.SDK_INT >= 21) {
            mLEScanner.startScan(filters, settings, mScanCallback);
        } else {
            btAdapter.startLeScan(leScanCallback);
        }

我已经定义了 2 个回调,一个用于 API 21 及更高版本,一个用于 API 18 到 20:

    //API 21
private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
              BluetoothDevice btDevice = result.getDevice();
              connectToDevice(btDevice);
         }
         public void connectToDevice(BluetoothDevice device) {
              if (mGatt == null) {
                   mGatt = device.connectGatt(context, false, btleGattCallback);
                   if (Build.VERSION.SDK_INT < 21) {
                        btAdapter.stopLeScan(leScanCallback);
                   } else {
                        mLEScanner.stopScan(mScanCallback);
                   }
               }
         }
    };


//API 18 to 20
        private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {

        btAdapter.stopLeScan(leScanCallback);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mBluetoothGatt = device.connectGatt(context, false, btleGattCallback);
            }
        });


    }
};

我还添加了注释

@TargetApi(21)

但是当我在 Android 4.x 上启动该应用程序时,它立即崩溃并报告找不到类 ScanCallback 的错误(该类仅用于 Android 5 及更高版本)。

我该如何解决这个问题?

非常感谢。 丹妮尔。

最佳答案

阅读几篇文章后,我做了以下事情。为了以防万一,这里有关于 BluetoothLe 的 Android 文档。

首先

创建两个方法 scanLeDevice21scanLeDevice18。在 scanLeDevice21 上添加注释 @RequiresApi(21) 说:

Denotes that the annotated element should only be called on the given API level or higher. This is similar in purpose to the older @TargetApi annotation, but more clearly expresses that this is a requirement on the caller, rather than being used to "suppress" warnings within the method that exceed the minSdkVersion.

第二

实现每个方法,这是我的代码。

@RequiresApi(21)
private void scanLeDevice21(final boolean enable) {

    ScanCallback mLeScanCallback = new ScanCallback() {

        @Override
        public void onScanResult(int callbackType, ScanResult result) {

            super.onScanResult(callbackType, result);

            BluetoothDevice bluetoothDevice = result.getDevice();

            if (!bluetoothDeviceList.contains(bluetoothDevice)) {
                Log.d("DEVICE", bluetoothDevice.getName() + "[" + bluetoothDevice.getAddress() + "]");
                bluetoothDeviceArrayAdapter.add(bluetoothDevice);
                bluetoothDeviceArrayAdapter.notifyDataSetChanged();
            }
        }

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

        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    };

    final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

    if (enable) {
        // Stops scanning after a pre-defined scan period.
        mHandler.postDelayed(() -> {
            mScanning = false;
            swipeRefreshLayout.setRefreshing(false);
            bluetoothLeScanner.stopScan(mLeScanCallback);
        }, SCAN_PERIOD);

        mScanning = true;
        bluetoothLeScanner.startScan(mLeScanCallback);
    } else {
        mScanning = false;
        bluetoothLeScanner.stopScan(mLeScanCallback);
    }
}


 /**
 * Scan BLE devices on Android API 18 to 20
 *
 * @param enable Enable scan
 */
private void scanLeDevice18(boolean enable) {

    BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi,
                                     byte[] scanRecord) {
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            bluetoothDeviceArrayAdapter.add(bluetoothDevice);
                            bluetoothDeviceArrayAdapter.notifyDataSetChanged();
                        }
                    });
                }
            };
    if (enable) {
        // Stops scanning after a pre-defined scan period.
        mHandler.postDelayed(() -> {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }, SCAN_PERIOD);

        mScanning = true;
        mBluetoothAdapter.startLeScan(mLeScanCallback);
    } else {
        mScanning = false;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
    }

}

第三

每次您需要扫描设备时,您都会在代码周围询问您使用的是哪个版本。例如,我有一个 RefreshLayout 来显示设备列表。结果如下:

  /**
 * Refresh listener
 */
private void refreshScan() {
    if (!hasFineLocationPermissions()) {
        swipeRefreshLayout.setRefreshing(false);


        //Up to marshmallow you need location permissions to scan bluetooth devices, this method is not here since is up to you to implement it and it is out of scope of this question. 
        requestFineLocationPermission();

    } else {
        swipeRefreshLayout.setRefreshing(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            scanLeDevice21(true);
        } else {
            scanLeDevice18(true);
        }
    }
}

就是这样。

忘记像 ulusoyca 答案那样扩展、子类化您并不真正需要的类。

关于与 API>=21 AND API<21 兼容的 Android 低功耗蓝牙代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34213951/

相关文章:

暂停时的 Android 寻呼机问题

android - 单击按钮后启动计时器

android - 蓝牙 OOB 切换通过 NFC 无需用户确认(或 : how does Android Beam work)

linux - GATT 服务器不适用于 Bluez 5.32、5.37

ios - iOS上的BLE技术从哪几点入手

android - 实现与 BLE 设备通信的服务

android - Webview 在选择框或任何对话框上崩溃

android - 支持没有硬编码比例的最大屏幕纵横比?

Android - 列出已连接的蓝牙设备

android - Android 上如何覆盖 Minor/Major/txPower 等 iBeacon 属性?