Scooter Unlock via BLE/QR in Mobile App

Scooter Unlock via BLE/QR in Mobile App We develop unlock systems for electric scooters via mobile app. The user scans a QR code, our app communicates with the server and sends a BLE command—all within seconds. With 5+ years of work on 10+ sharing projects, we know: any failure in this path immed

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 1All 1734 services
Scooter Unlock via BLE/QR in Mobile App
Medium
~1-2 weeks

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    897
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    599

Scooter Unlock via BLE/QR in Mobile App

We develop unlock systems for electric scooters via mobile app. The user scans a QR code, our app communicates with the server and sends a BLE command—all within seconds. With 5+ years of work on 10+ sharing projects, we know: any failure in this path immediately erodes trust in the service. Any delay is perceived as a bug, so we pay attention to every millisecond. One of our clients, launching a kick-scooter sharing service in a city with 500 scooters, encountered that 15% of users abandoned the rental at the unlock stage—due to slow BLE connection. We optimized the protocol, and the churn dropped to 3%.

How QR Unlock Works

The QR on the scooter encodes the device ID: a string like https://ride.example.com/unlock?id=SC-00234 or simply SC-00234. We scan via ML Kit Barcode Scanning (Android/iOS) or AVFoundation AVCaptureMetadataOutput. ML Kit is preferred—it works without a network connection and is faster in low-light conditions.

After obtaining the ID, we send a request to the server: POST /api/v1/unlock with {scooterId, userId, sessionToken}. The server checks the balance/subscription, reserves the scooter, and returns {bleUnlockToken, bleDeviceAddress, lockServiceUUID, lockCharacteristicUUID, expiresAt}. The token is one-time, valid for 30–60 seconds—if the BLE connection fails in time, the user receives an error and initiates a new request.

// iOS: QR scanning via AVFoundation class QRScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { guard let readableObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, let stringValue = readableObject.stringValue, let scooterId = parseScooterId(from: stringValue) else { return } captureSession.stopRunning() Task { await viewModel.initiateUnlock(scooterId: scooterId) } } } 

Why BLE Token Expires

Scooters in sharing use BLE modules based on Nordic nRF52 or ESP32 with custom GATT profile. The scheme is simple: we write the token to a WriteCharacteristic, the controller verifies the HMAC signature (shared secret embedded in firmware), and if matches, releases the electromagnetic lock and allows the motor.

// Android: writing unlock token to BLE characteristic class ScooterUnlockManager(private val context: Context) { private var gatt: BluetoothGatt? = null suspend fun unlock(address: String, token: UnlockToken): UnlockResult { return suspendCancellableCoroutine { cont -> val device = bluetoothAdapter.getRemoteDevice(address) gatt = device.connectGatt(context, false, object : BluetoothGattCallback() { override fun onConnectionStateChange(g: BluetoothGatt, status: Int, state: Int) { if (state == BluetoothProfile.STATE_CONNECTED) g.discoverServices() else if (status != BluetoothGatt.GATT_SUCCESS) { cont.resume(UnlockResult.BleConnectionFailed(status)) } } override fun onServicesDiscovered(g: BluetoothGatt, status: Int) { val characteristic = g .getService(token.serviceUUID) ?.getCharacteristic(token.characteristicUUID) ?: run { cont.resume(UnlockResult.ServiceNotFound); return } characteristic.value = token.payload.toByteArray() characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT g.writeCharacteristic(characteristic) } override fun onCharacteristicWrite(g: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) { val result = if (status == BluetoothGatt.GATT_SUCCESS) UnlockResult.Success else UnlockResult.WriteFailed(status) cont.resume(result) g.disconnect() } }, BluetoothDevice.TRANSPORT_LE) cont.invokeOnCancellation { gatt?.disconnect() } } } } 

Critical detail: TRANSPORT_LE in connectGatt—without this flag, Android might try to connect via Classic Bluetooth, resulting in status=133 on BLE-only devices.

Problems in Real Conditions

Poor BLE signal. The scooter is in an underground parking lot, surrounded by 20 other scooters with the same GATT services. We do not scan all devices indiscriminately; we connect directly: bluetoothAdapter.getRemoteDevice(address) using the MAC from the server response. This is faster than scanning the environment.

Expired token. The user scanned the QR, then got distracted for 2 minutes. The token expired. When receiving GATT_SUCCESS on write, but the scooter did not unlock—we need a Notify Characteristic for the controller's response. The controller writes back: 0x01 (OK), 0x02 (token expired), 0x03 (already locked by another session).

Android 12+ Bluetooth permissions. BLUETOOTH_SCAN and BLUETOOTH_CONNECT are now runtime permissions. If the user denied and selected 'Don't ask again', shouldShowRequestPermissionRationale returns false—we lead them to Settings via Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).

UX Details That Make a Difference

Parallel launch of server and BLE: as soon as the server response with the device address is received, we start BLE connection without waiting for the final UI animation. The user sees a spinner, but the BLE handshake is already happening. Saves ~300-500 ms. Also worth caching tokens: if the scooter was previously connected, we can try to restore the connection without a repeated QR scan. This reduces average unlock time by 20-30%.

Comparison of Unlock Approaches

Characteristic BLE NFC QR + BLE
Speed 1-2 sec 0.5 sec 1-3 sec
Security HMAC token Crypto key Token + HMAC
Compatibility iOS/Android iPhone 7+, Android 5+ Almost all smartphones
Extra hardware None NFC module BLE only
Reliability in noise Medium (address connection) High High (address)

Based on research from Bluetooth SIG and Apple Core Bluetooth documentation.

Common Mistakes in BLE Unlock Implementation

Mistake Consequence Solution
Missing TRANSPORT_LE Connection error on Android Specify the parameter explicitly
Simultaneous requests from multiple devices Token conflict Reserve scooter on server
Lack of notifications after write Unable to know result Use Notify characteristic
Token without timestamp Reuse possibility HMAC with timestamp

What the Work Includes

  • QR scanning module for iOS and Android (ML Kit / AVFoundation)
  • BLE unlock command with GATT profile support
  • Backend service for authentication and reservation
  • Testing on real scooters (Nordic nRF52, ESP32)
  • Integration documentation and team training

Timelines and Cost

Development of QR scanning + BLE unlock module for a sharing platform (iOS + Android): 3-5 weeks. With complete fleet backend (reservation, billing, geofencing): 3-5 months. Cost starts from $15,000 for the unlock module alone, typically $25,000–$50,000 for full integration depending on complexity. Contact us for a free, no-obligation consultation—we'll provide a detailed quote within 1 business day.

Implementation Stages

  1. Audit of current scooter hardware (BLE module, firmware)
  2. Design of GATT profile and protocol
  3. Development of iOS module (Swift, Combine)
  4. Development of Android module (Kotlin, Coroutines)
  5. Integration with server (REST/GraphQL)
  6. Testing (unit, integration, field)
  7. Deploy to App Store and Google Play
  8. Monitoring and support after launch

With over 5 years of experience and 10+ successful projects, we guarantee a robust and secure solution. We provide a 12-month warranty on all code and full documentation. Assess your project within 1 business day. Get a consultation right now—write to us!