{"id":13591115,"url":"https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library","last_synced_at":"2025-04-08T14:32:30.370Z","repository":{"id":37334757,"uuid":"41294846","full_name":"NordicSemiconductor/Android-Scanner-Compat-Library","owner":"NordicSemiconductor","description":"A compat library for Bluetooth Low Energy scanning on Android.","archived":false,"fork":false,"pushed_at":"2024-01-19T21:39:00.000Z","size":329,"stargazers_count":775,"open_issues_count":19,"forks_count":158,"subscribers_count":42,"default_branch":"master","last_synced_at":"2025-04-01T14:01:41.511Z","etag":null,"topics":["android","ble","bluetooth-le","bluetooth-low-energy","compatibility","scanning"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NordicSemiconductor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-24T09:36:45.000Z","updated_at":"2025-03-25T09:35:59.000Z","dependencies_parsed_at":"2024-06-21T07:11:49.214Z","dependency_job_id":"bc24b06f-5176-47fd-a8ad-f3da78d8fb13","html_url":"https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NordicSemiconductor%2FAndroid-Scanner-Compat-Library","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NordicSemiconductor%2FAndroid-Scanner-Compat-Library/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NordicSemiconductor%2FAndroid-Scanner-Compat-Library/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NordicSemiconductor%2FAndroid-Scanner-Compat-Library/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NordicSemiconductor","download_url":"https://codeload.github.com/NordicSemiconductor/Android-Scanner-Compat-Library/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247860968,"owners_count":21008399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","ble","bluetooth-le","bluetooth-low-energy","compatibility","scanning"],"created_at":"2024-08-01T16:00:53.787Z","updated_at":"2025-04-08T14:32:29.919Z","avatar_url":"https://github.com/NordicSemiconductor.png","language":"Java","funding_links":[],"categories":["Java"],"sub_categories":[],"readme":"# Android BLE Scanner Compat library\n\n[ ![Download](https://maven-badges.herokuapp.com/maven-central/no.nordicsemi.android.support.v18/scanner/badge.svg?style=plastic) ](https://search.maven.org/artifact/no.nordicsemi.android.support.v18/scanner)\n\nThe Scanner Compat library solves the problem with scanning for Bluetooth Low Energy devices on Android. \nThe scanner API, initially created in Android 4.3, has changed in Android 5.0 and has been extended in 6.0 and 8.0. \nThis library allows to use modern API even on older phones, emulating not supported features. If a feature \n(for example offloaded filtering or batching) is not available natively, it will be emulated by \nthe compat library. Also, native filtering, batching and reporting first match or match lost may\nbe disabled if you find them not working on some devices. Advertising Extension (`ScanSetting#setLegacy(boolean)` \nor `setPhy(int)`) is available only on Android Oreo or newer and such calls will be ignored on \nolder platforms where only legacy advertising packets on PHY LE 1M will be reported, \ndue to the Bluetooth chipset capabilities.\n\n### Background scanning\n\n`SCAN_MODE_LOW_POWER` or `SCAN_MODE_OPPORTUNISTIC` should be used when scanning in background.\nNote, that newer Android versions will enforce using low power mode in background, even if another one has been set.\nThis library allows to emulate [scanning with PendingIntent](https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.app.PendingIntent))\non pre-Oreo devices by starting a background service that will scan with requested scan mode. \nThis is much less battery friendly than when the original method is used, but works and saves\na lot of development time if such feature should be implemented anyway. Please read below \nfor more details.\n\nNote, that for unfiltered scans, scanning is stopped on screen off to save power. Scanning is\nresumed when screen is turned on again. To avoid this, use scanning with desired ScanFilter.\n\n## Usage\n\nThe compat library may be found on Maven Central repository. Add it to your project by adding the \nfollowing dependency:\n\n```Groovy\nimplementation 'no.nordicsemi.android.support.v18:scanner:1.6.0'\n```\n\nProject not targeting API 31 (Android 12) or newer should use version 1.5.1.\n\nProjects not migrated to Android Jetpack should use version 1.3.1, which is feature-equal to 1.4.0.\n\nAs JCenter has shut down, starting from version 1.4.4 the library is available only on Maven Central. \nMake sure you have `mavenCentral()` in your main *build.gradle* file:\n```gradle\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n}\nallprojects {\n    repositories {\n        mavenCentral()\n    }\n}\n```\n\nSince version 1.5 you will need to [enable desugaring of Java 8 language features](https://developer.android.com/studio/write/java8-support.html#supported_features) \nif you have not already done so.(And if you are releasing an Android library, then anyone who uses \nthat library will also have to enable desugaring.) We expect for nearly all Android projects to have \nalready enabled desugaring. But if this causes problems for you, please use version 1.4.5.\n\n## Permissions\n\nFollowing [this](https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner#startScan(android.bluetooth.le.ScanCallback)) link:\n\n\u003e An app must have [ACCESS_COARSE_LOCATION](https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION)\npermission in order to get results. An App targeting Android Q or later must have\n[ACCESS_FINE_LOCATION](https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION)\npermission in order to get results.\nFor apps targeting [Build.VERSION_CODES#R](https://developer.android.com/reference/android/os/Build.VERSION_CODES#R)\nor lower, this requires the [Manifest.permission#BLUETOOTH_ADMIN](https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_ADMIN)\npermission which can be gained with a simple `\u003cuses-permission\u003e` manifest tag.\nFor apps targeting [Build.VERSION_CODES#S](https://developer.android.com/reference/android/os/Build.VERSION_CODES#S)\nor or higher, this requires the [Manifest.permission#BLUETOOTH_SCAN](https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_SCAN)\npermission which can be gained with\n[Activity.requestPermissions(String[], int)](https://developer.android.com/reference/android/app/Activity#requestPermissions(java.lang.String[],%20int)).\nIn addition, this requires either the [Manifest.permission#ACCESS_FINE_LOCATION](https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION)\npermission or a strong assertion that you will never derive the physical location of the device.\nYou can make this assertion by declaring `usesPermissionFlags=\"neverForLocation\"` on the relevant\n`\u003cuses-permission\u003e` manifest tag, but it may restrict the types of Bluetooth devices you can interact with.\n\n## API\n\nThe Scanner Compat API is very similar to the original one, known from Android Oreo.\n\nInstead of getting it from the **BluetoothAdapter**, acquire the scanner instance using:\n\n```java\nBluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();\n```\n\nYou also need to change the packets for **ScanSettings**, **ScanFilter** and **ScanCallback** \nclasses to:\n\n```java\nno.nordicsemi.android.support.v18.scanner\n```\n\n## Sample\n\nTo start scanning use (example):\n\n```java\n\tBluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();\n\tScanSettings settings = new ScanSettings.Builder()\n\t\t\t\t.setLegacy(false)\n\t\t\t\t.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)\n\t\t\t\t.setReportDelay(5000)\n\t\t\t\t.setUseHardwareBatchingIfSupported(true)\n\t\t\t\t.build();\n\tList\u003cScanFilter\u003e filters = new ArrayList\u003c\u003e();\n\tfilters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());\n\tscanner.startScan(filters, settings, scanCallback);\n```\n\nto stop scanning use:\n\n```java\n\tBluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();\n\tscanner.stopScan(scanCallback);\n```\n\n### Scanning modes\n\nThere are 4 scanning modes available in native [ScanSettings](https://developer.android.com/reference/android/bluetooth/le/ScanSettings).\n3 of them are available since Android Lollipop while the opportunistic scan mode has been added in Marshmallow.\nThis library tries to emulate them on platforms where they are not supported natively.\n1. [SCAN_MODE_LOW_POWER](https://developer.android.com/reference/android/bluetooth/le/ScanSettings#SCAN_MODE_LOW_POWER) - \nPerform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the least power. \nThe scanner will scan for 0.5 second and rest for 4.5 seconds. A Bluetooth LE device should advertise \nvery often (at least once per 100 ms) in order to be found with this mode, otherwise the scanning interval may miss some or even all \nadvertising events. This mode may be enforced if the scanning application is not in foreground.\n2. [SCAN_MODE_BALANCED](https://developer.android.com/reference/android/bluetooth/le/ScanSettings#SCAN_MODE_BALANCED) - \nPerform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that provides a \ngood trade-off between scan frequency and power consumption. The scanner will scan for 2 seconds followed\nby 3 seconds of idle.\n3. [SCAN_MODE_LOW_LATENCY](https://developer.android.com/reference/android/bluetooth/le/ScanSettings#SCAN_MODE_LOW_LATENCY) -\nScan using highest duty cycle. It's recommended to only use this mode when the application is running in the foreground.\n4. [SCAN_MODE_OPPORTUNISTIC](https://developer.android.com/reference/android/bluetooth/le/ScanSettings#SCAN_MODE_OPPORTUNISTIC) - \nA special Bluetooth LE scan mode. Applications using this scan mode will passively listen for other scan results \nwithout starting BLE scans themselves.\n\n3 first modes are emulated on Android 4.3 and 4.4.x by starting a handler task that scans for a period of time\nand rests in between. To set scanning and rest intervals use `Builder#setPowerSave(long,long)`.\n\nOpportunistic scanning is not possible to emulate and will fallback to `SCAN_MODE_LOW_POWER` on Lollipop and\npower save settings on pre-Lollipop devices. That means that this library actually will initiate scanning \non its own. This may have impact on battery consumption and should be used with care.\n\n### Scan filters and batching\n\nOffloaded filtering is available on Lollipop or newer devices where \n[BluetoothAdapter#isOffloadedFilteringSupported()](https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#isOffloadedFilteringSupported())\nreturns *true* (when Bluetooth is enabled). If it is not supported, this library will scan without a filter and\napply the filter to the results. If you find offloaded filtering unreliable you may force using compat filtering by calling\n`Builder#useHardwareFilteringIfSupported(false)`. Keep in mind that, newer Android versions may prohibit \nbackground scanning without native filters to save battery, so this method should be used with care.\n\nAndroid Scanner Compat Library may also emulate batching. To enable scan batching call `Builder#setScanDelay(interval)`\nwith an interval greater than 0. For intervals less 5 seconds the actual interval may vary.\nIf you want to get results in lower intervals, call `Builder#useHardwareBatchingIfSupported(false)`, which will\nstart a normal scan and report results in given interval. Emulated batching uses significantly more battery\nthan offloaded as it wakes CPU with every device found.\n\n### Scanning with Pending Intent\n\nAndroid 8.0 Oreo introduced [Background Execution Limits](https://developer.android.com/about/versions/oreo/background)\nwhich made background running services short-lived. At the same time, to make background scanning possible, a new \n[method](https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.app.PendingIntent))\nwas added to [BluetoothLeScanner](https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html)\nwhich allows registering a [PendingIntent](https://developer.android.com/reference/android/app/PendingIntent)\nthat will be sent whenever a device matching filter criteria is found. This will also work after \nyour application has been killed (the receiver must be added in *AndroidManifest* and the \n`PendingIntent` must be created with an explicit Intent).\n\nStarting from version 1.3.0, this library may emulate such feature on older Android versions.\nIn order to do that, a background service will be started after calling \n`scanner.startScan(filters, settings, context, pendingIntent, requestCode)`, which will be scanning in \nbackground with given settings and will send the given `PendingIntent` when a device \nmatching filter is found. To lower battery consumption it is recommended to set \n`ScanSettings.SCAN_MODE_LOW_POWER` scanning mode and use filter, but even with those conditions fulfilled\n**the battery consumption will be significantly higher than on Oreo+**. To stop scanning call \n`scanner.stopScan(context, pendingIntent, requestCode)` with \n[the same](https://developer.android.com/reference/android/app/PendingIntent) intent in parameter. \nThe service will be stopped when the last scan was stopped.\n\nOn Android Oreo or newer this library will use the native scanning mechanism. However, as it may also \nemulate batching or apply filtering (when `useHardwareBatchingIfSupported` or `useHardwareFilteringIfSupported` \nwere called with parameter *false*) the library will register its own broadcast \nreceiver that will translate results from native to compat classes. \n\nThe receiver and service will be added automatically to the manifest even if they are not used by \nthe application. No changes are required to make it work.\n\nTo use this feature:\n\n```java\n    Intent intent = new Intent(context, MyReceiver.class); // explicit intent\n\tintent.setAction(\"com.example.ACTION_FOUND\");\n\tintent.putExtra(\"some.extra\", value); // optional\n\tPendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);\n\t\n\tBluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();\n\tScanSettings settings = new ScanSettings.Builder()\n\t\t\t\t.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)\n\t\t\t\t.setReportDelay(10000)\n\t\t\t\t.build();\n\tList\u003cScanFilter\u003e filters = new ArrayList\u003c\u003e();\n\tfilters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());\n\tscanner.startScan(filters, settings, context, pendingIntent, requestCode);\n```\n\nAdd your `MyReceiver` to *AndroidManifest*, as the application context might have been released\nand all broadcast receivers registered to it together with it.\n\nTo stop scanning call:\n\n```java\n\t// To stop scanning use the same PendingIntent and request code as one used to start scanning.\n    Intent intent = new Intent(context, MyReceiver.class);\n\tintent.setAction(\"com.example.ACTION_FOUND\");\n\tPendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);\n\t\n\tBluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();\n\tscanner.stopScan(context, pendingIntent, requestCode);\n```\n\n**Note:** Android versions 6 and 7 will not report any advertising packets when in Doze mode.\nRead more about it here: https://developer.android.com/training/monitoring-device-state/doze-standby\n\n**Note 2:** An additional parameter called `requestCode` was added in version 1.4.5 to the above API.\nIt is to ensure that the scanning would be correctly stopped. If not provided, a request code equal\nto 0 will be used preventing from having multiple scanning tasks. \n\n## Background scanning guidelines\n\nTo save power it is recommended to use as low power settings as possible and and use filters.\nHowever, the more battery friendly settings are used, the longest time to finding a device.\nIn general, scanning with `PendingIntent` and `SCAN_MODE_LOW_POWER` or `SCAN_MODE_OPPORTUNISTIC`\nshould be used, together with report delay set and filters used.\n`useHardwareFilteringIfSupported` and `useHardwareBatchingIfSupported` should be set to *true* (default).\n\nBackground scanning on Android 4.3 and 4.4.x will use a lot of power, as all those properties \nwill have to be emulated. It is recommended to scan in background only on Lollipop or newer, or\neven Oreo or newer devices and giving the user an option to disable this feature.\n\nNote, that for unfiltered scans, scanning is stopped on screen off to save power. Scanning is\nresumed when screen is turned on again. To avoid this, use scanning with desired ScanFilter.\n\n## License\n\nThe Scanner Compat library is available under BSD 3-Clause license. See the LICENSE file for more info.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNordicSemiconductor%2FAndroid-Scanner-Compat-Library","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNordicSemiconductor%2FAndroid-Scanner-Compat-Library","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNordicSemiconductor%2FAndroid-Scanner-Compat-Library/lists"}