Android 低功耗蓝牙代码兼容 API>=21 AND API<21 [英] Android Bluetooth Low Energy code compatible with API>=21 AND API<21

查看:22
本文介绍了Android 低功耗蓝牙代码兼容 API>=21 AND API<21的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing an app that have to connect with a BLE device, in my code I want to use the new Scan and ScanCallback for BLE implemented from API 21 (Android 5) but I have to maintain the compatibility with Android 4.3 and above.

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

So I wrote the code, for example, in this way:

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

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

And I have defined the 2 callbacks, one for API 21 and above and one for API 18 to 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 及更高版本).

but when I launch the App on Android 4.x it crashes immediately reporting the error that the class ScanCallback cannot be found (the one intended to be used only with Android 5 and above).

我该如何解决这个问题?

How can I solve this?

非常感谢.丹尼尔.

推荐答案

在阅读了几篇文章后,我做了以下工作.以防万一,这里是关于 BluetoothLe

After reading several posts I did the following. Just in case, here is the documentation of Android about BluetoothLe

第一

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

Create two methods one scanLeDevice21 and scanLeDevice18. On scanLeDevice21 add the annotation @RequiresApi(21) that says:

表示注解元素只能在给定的 API 级别或更高级别上调用.这与旧的@TargetApi 注释的目的相似,但更清楚地表示这是对调用者的要求,而不是用于抑制"方法内超过 minSdkVersion 的警告.

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.

第二

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

Implement each method, here's my code.

@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 来显示设备列表.结果如下:

Every time you need to scan devices you surround your code asking which version you are. For instance, I have a RefreshLayout to display the list of devices. Here's the result:

  /**
 * 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 的答案一样.

Forget about extending, subclassing classes you don't really need like ulusoyca answer.

这篇关于Android 低功耗蓝牙代码兼容 API&gt;=21 AND API&lt;21的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆