Implementing BLE Device Scanning and Connection

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Implementing BLE Device Scanning and Connection
Medium
~2-3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1050
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

BLE Device Scanning and Connection Implementation

The task seems simple: find a BLE device, connect. In practice — it's handling eight different adapter states, different scan modes, and quirks of specific chipsets. We'll cover only this part of the BLE stack, without reading characteristics.

iOS: Scanning via CBCentralManager

Scanning possible only when CBCentralManager.state == .poweredOn. Other states must be handled:

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
        startScanning()
    case .poweredOff:
        showAlert("Enable Bluetooth in settings")
    case .unauthorized:
        // iOS 13+ — CBManager.authorization
        if CBCentralManager.authorization == .denied {
            showSettingsLink()
        }
    case .unsupported:
        showAlert("Device does not support Bluetooth LE")
    case .resetting:
        // stack reloading, wait for .poweredOn
        break
    default:
        break
    }
}

Filtering During Scan

// Scan only devices with required service
let serviceUUIDs = [CBUUID(string: "YOUR-SERVICE-UUID")]
centralManager.scanForPeripherals(withServices: serviceUUIDs, options: [
    CBCentralManagerScanOptionAllowDuplicatesKey: false
])

withServices: nil — scans all nearby BLE devices. Convenient during development. Don't use in production: uses more battery and clutters list with foreign devices.

Reconnecting to Known Device

If peripheral UUID saved (e.g., in UserDefaults), restore object without rescanning:

let knownUUID = UUID(uuidString: savedUUIDString)!
let peripherals = centralManager.retrievePeripherals(withIdentifiers: [knownUUID])
if let peripheral = peripherals.first {
    centralManager.connect(peripheral, options: nil)
} else {
    // UUID outdated or device replaced — start full scan
    startScanning()
}

Important for apps frequently reconnecting to one device (wristband, sensor). Without retrievePeripherals scan starts every time with delay.

Android: BluetoothLeScanner

val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
val scanner = bluetoothAdapter.bluetoothLeScanner

val filters = listOf(
    ScanFilter.Builder()
        .setServiceUuid(ParcelUuid(UUID.fromString("YOUR-SERVICE-UUID")))
        .build()
)

val settings = ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // during active use
    .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
    .build()

val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        val device = result.device
        val rssi = result.rssi
        val advertisingData = result.scanRecord
        // add to found devices list
    }

    override fun onScanFailed(errorCode: Int) {
        // SCAN_FAILED_ALREADY_STARTED = 1 — scan already running
        // SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2 — too many scanners
        // SCAN_FAILED_FEATURE_UNSUPPORTED = 4 — filters not supported (old devices)
    }
}

scanner.startScan(filters, settings, scanCallback)

Scan Modes

Mode Frequency Power When to Use
SCAN_MODE_LOW_POWER ~512 ms minimal background search
SCAN_MODE_BALANCED ~512 ms / ~1.5s medium default
SCAN_MODE_LOW_LATENCY continuous high active search in UI
SCAN_MODE_OPPORTUNISTIC only if other scanner active zero passive monitoring

Android 12+ Permissions

// Check before scanning
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    when {
        ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED -> {
            requestPermissions(arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT
            ), REQUEST_CODE)
        }
    }
}

BLUETOOTH_SCAN without neverForLocation flag requires ACCESS_FINE_LOCATION. If scanning not for location determination, in manifest:

<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation" />

Then geolocation not needed and users won't be confused why Bluetooth app requests GPS.

Implementation timeframe: 2–3 days — scanning + connecting with all state and permission handling on both platforms. Cost calculated individually.