Trabajando con Bluetooth Low Energy (BLE) en Android
Mientras voy desarrollando tengo en mi gradle el minSDK de mi teléfono (Nexus 6p - SDK 24) esto con el simple hecho de compilar mas rápido. La aplicación se espera que trabaje desde Android 4.3 SDK18 que fue cuando se introdujo BLE en Android.
Todo iba muy bien hasta que cambié el gradle a minSDK 18.. encontré que todo mi código estaba hecho para SDK21 donde hay métodos nuevos para escanear BLE devices.
Para ser mas concreto cambian los callBacks a partir del SDK 21. Lo resolví de la siguiente manera
Primero nos creamos dos métodos: scanLeDevice21 y scanLeDevice18.
Luego, cada vez que necesitamos escanear un dispositivo preguntamos en cuál API estamos y utilizamos el método correspondiente. Por ejemplo, tengo mi lista de dispositivos dentro de un RefreshLayout.
Y ya, eso es todo! con esto tenemos nuestra api funcional para las diferentes versiones de Android.
Todo iba muy bien hasta que cambié el gradle a minSDK 18.. encontré que todo mi código estaba hecho para SDK21 donde hay métodos nuevos para escanear BLE devices.
Para ser mas concreto cambian los callBacks a partir del SDK 21. Lo resolví de la siguiente manera
Primero nos creamos dos métodos: scanLeDevice21 y scanLeDevice18.
/** * Scan for BLE devices with Android API 21 and up * * @param enable Enabled scanning */ @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(Listresults) { 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); } }Si observamos, el método scanLeDevice21 tiene la anotación @RequiresApi(21) que dice lo siguiente:
"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"
Luego, cada vez que necesitamos escanear un dispositivo preguntamos en cuál API estamos y utilizamos el método correspondiente. Por ejemplo, tengo mi lista de dispositivos dentro de un RefreshLayout.
/** * Refresh listener */ private void refreshScan() { if (!hasFineLocationPermissions()) { swipeRefreshLayout.setRefreshing(false); requestFineLocationPermission(); } else { swipeRefreshLayout.setRefreshing(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scanLeDevice21(true); } else { scanLeDevice18(true); } } }
Y ya, eso es todo! con esto tenemos nuestra api funcional para las diferentes versiones de Android.
Comentarios
Publicar un comentario
Prove yourself!