The following builds on the original Windows development workflow and adds guidance and steps for Android development with transparent transmission devices that support both SPP (Classic Bluetooth) and BLE (Bluetooth Low Energy), helping you implement the related functionality on Android. Adjust according to your technology stack (Java/Kotlin, development tools, API level, etc.) and project requirements.
I. Android Platform Overview
Bluetooth development on Android falls into two main areas:
- Classic Bluetooth (BR/EDR), commonly known as SPP (Serial Port Profile).
- Supported on nearly all Android versions from 2.0 onward, with native SPP stack support.
- Implemented in Android using classes such as BluetoothAdapter, BluetoothDevice, and BluetoothSocket.
- Bluetooth Low Energy (BLE), using the GATT protocol for characteristic read/write and notification/indication subscription.
- BLE is supported from Android 4.3 onward (API Level 18+).
- Typically implemented using BluetoothLeScanner, BluetoothGatt, BluetoothGattService, BluetoothGattCharacteristic, and related APIs.
Important notes:
- From Android 6.0 (API 23), Bluetooth scanning requires location permission.
- From Android 10 (API 29), permissions are further restricted; precise location permission is required to scan BLE devices.
- From Android 12 (API 31), new Bluetooth permissions (BLUETOOTH_SCAN, BLUETOOTH_CONNECT, etc.) must be declared in the Manifest and requested at runtime.
II. SPP (Classic Bluetooth) Development Workflow
-
Enable Bluetooth and obtain permissions
- Check and enable Bluetooth:
- Use BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- Verify adapter is not null (device supports Bluetooth) and check adapter.isEnabled() to decide whether to prompt the user to enable Bluetooth.
- Request runtime permissions (Android 12+ requires BLUETOOTH_CONNECT and related permissions), and enable location permission when needed (Android 10 and earlier).
- Check and enable Bluetooth:
-
Device discovery and pairing (optional)
- If the device is not paired, use startDiscovery() to search for nearby Classic Bluetooth devices, or navigate to the system Bluetooth settings for the user to complete pairing.
- Call createBond() to initiate pairing (some devices may pair automatically without a manual call).
- After successful pairing, the device appears in system settings and can be retrieved via BluetoothAdapter.getBondedDevices().
-
Connect to the device using SPP
- From a paired device object: BluetoothDevice device = …
- Obtain the Bluetooth serial port channel using a UUID—typically the standard SPP UUID (00001101-0000-1000-8000-00805F9B34FB), or a custom UUID provided by the device.
- Call device.createRfcommSocketToServiceRecord(uuid) to obtain a BluetoothSocket, then call connect().
- After a successful connection, obtain input and output streams:
- InputStream is = bluetoothSocket.getInputStream();
- OutputStream os = bluetoothSocket.getOutputStream();
-
Data transmission and parsing
- Read data returned by the device through InputStream and parse it according to the protocol.
- Send data to the device through OutputStream (transparent transmission protocols typically accept binary or text directly).
- Handle threading: perform send/receive operations in a separate thread or async task to avoid blocking the UI.
-
Disconnect and release resources
- When leaving the page or when the Bluetooth connection is no longer needed, call bluetoothSocket.close() to release resources.
- Handle exceptions and implement disconnect/reconnect logic.
III. BLE (Bluetooth Low Energy) Development Workflow
-
Enable Bluetooth and check permissions
- Verify that BluetoothAdapter is available, declare required permissions in AndroidManifest.xml (Android 12+ needs BLUETOOTH_SCAN, BLUETOOTH_CONNECT, etc.; older versions also need precise location permission).
- Request the appropriate permissions at runtime to ensure BLE scanning and connection are allowed.
-
Device scanning
- Obtain BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
- Use scanner.startScan(…) to start scanning and receive nearby BLE devices in the onScanResult() callback.
- If you only need to connect to a known device MAC address, use bluetoothAdapter.getRemoteDevice(mac) to obtain the BluetoothDevice object directly, then initiate a connection.
-
Initiate GATT connection
- BluetoothDevice device = …
- BluetoothGatt bluetoothGatt = device.connectGatt(context, false, gattCallback);
- context: typically the current Activity or application context
- false means do not use automatic reconnection (set to true if needed)
- gattCallback: callback for connection and data communication
-
Discover services and characteristics
- Handle connection success or failure in onConnectionStateChange(). After a successful connection, call bluetoothGatt.discoverServices() to start service discovery.
- In the onServicesDiscovered() callback, obtain available services via bluetoothGatt.getServices().
- Locate the corresponding Service UUID and Characteristic UUID according to the device protocol or documentation.
-
Characteristic read, write, and notifications
-
Write data
- After obtaining the target characteristic instance:
BluetoothGattCharacteristic characteristic = …
characteristic.setValue(byteArrayToSend);
bluetoothGatt.writeCharacteristic(characteristic); - Check the write result in the onCharacteristicWrite() callback.
- After obtaining the target characteristic instance:
-
Read data
- bluetoothGatt.readCharacteristic(characteristic);
- Handle the read value in the onCharacteristicRead() callback.
-
Subscribe to notifications (or indications)
- First enable notifications:
bluetoothGatt.setCharacteristicNotification(characteristic, true); - Write to the descriptor (UUID 0x2902) to enable notifications, for example:
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(appropriateUuid);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor); - When the device pushes data proactively, real-time data is received in the onCharacteristicChanged() callback.
- First enable notifications:
-
-
Data parsing and processing
- In transparent transmission mode, BLE typically supports direct binary stream send and receive.
- Pack, unpack, and verify data according to the protocol agreed with the device.
-
Disconnect and release resources
- When no longer needed, call bluetoothGatt.close() to disconnect and release resources.
- Handle errors, timeouts, and exceptions correctly in callbacks and implement a reconnection strategy.
IV. Common Debugging Methods and Notes
-
Debugging tools
- For SPP, use Android serial debug apps (or third-party debuggers) to test send/receive; desktop tools can also be used to validate with hardware first.
- For BLE, use apps such as “nRF Connect” or “BLE Scanner”; they list device GATT services and characteristics and support manual read, write, and subscription.
-
Permissions and compatibility
- From Android 6.0, Bluetooth scanning requires location permission; from Android 10 (API 29), precise location permission is required.
- From Android 12 (API 31), BLUETOOTH_SCAN, BLUETOOTH_CONNECT, and related permissions must be declared and requested separately.
- Request permissions at runtime, not only in the Manifest, to ensure authorization before actual use.
-
Scan and connection timeout strategy
- Prolonged BLE scanning consumes power and may trigger system limits; control scan duration appropriately.
- After connecting, implement timeout or retry mechanisms to avoid hanging in a connecting state or waiting for unhandled callbacks.
-
Disconnect and reconnect
- Whether SPP or BLE, disconnections are common in mobile environments; monitor connection state in callbacks and attempt reconnection.
- Clean up resources and avoid holding duplicate BluetoothSocket or BluetoothGatt instances without calling close().
-
Performance and power consumption
- BLE is designed for low power; minimize unnecessary scanning, connections, and sustained high-volume transfers.
- For SPP, if sustained high-volume communication is required, focus on speed and stability (some devices may have bandwidth and latency limits).
V. Reference Links
-
Official documentation
- Android Classic Bluetooth:
https://developer.android.com/guide/topics/connectivity/bluetooth - Android BLE:
https://developer.android.com/guide/topics/connectivity/bluetooth-le
- Android Classic Bluetooth:
-
Third-party tools/libraries
- nRF Connect (Nordic)
- BLE Scanner
- RxAndroidBle (if you prefer RxJava for BLE workflows)
Summary
- In SPP (Classic Bluetooth) mode, Android development is relatively straightforward and similar to traditional serial port usage, with data sent and received via BluetoothSocket; pairing is required first.
- In BLE mode, service and characteristic discovery, read/write, and notification subscription are required—more flexible but more complex; pay attention to permissions, callback handling, and disconnect/reconnect.
- As with Windows development, you need a solid understanding of the hardware and protocol, use the appropriate APIs for communication, and implement proper exception handling and permission management.
- Validate device and data link feasibility with third-party apps or debug tools before implementing business logic in your own project.
Following the steps above, you can implement the basic transparent communication workflow on Android for Bluetooth devices that support both SPP and BLE. Together with the earlier Windows section, you can complete pairing, connection, data read/write, and subsequent device management and exception handling on both platforms. Happy developing!