Android에서 Bluetooth 통신을 사용하는 방법
Bluetooth는 스마트폰과 차량용 기기, 센서, 블랙박스, 이어폰처럼 가까운 장치끼리 무선으로 데이터를 주고받을 때 사용하는 기능입니다. Android에서는 기기 검색부터 연결, 데이터 송수신까지 API로 처리할 수 있습니다. 이번 글에서는 Bluetooth 통신을 시작할 때 알아두면 좋은 개념과 권한, 그리고 간단한 연결 예제를 정리해 보겠습니다.
목차
- Bluetooth 통신을 만들기 전 고려할 점
- Bluetooth Classic과 BLE의 차이
- Android 버전별 Bluetooth 권한
- Bluetooth 통신 흐름
- 연결 및 데이터 전송 샘플 코드
1. Bluetooth 통신을 만들기 전 고려할 점
Bluetooth는 가까운 거리에서 편리하게 통신할 수 있지만, 항상 연결되어 있다고 가정하면 안 됩니다. 기기 전원이 꺼지거나 통신 범위를 벗어나면 연결이 끊길 수 있고, 페어링 여부나 장치별 지원 프로파일도 다를 수 있습니다.
- 기기에 Bluetooth 기능이 있는지 확인합니다.
- 사용자가 Bluetooth를 꺼 둔 경우, 켜도록 안내합니다.
- 연결·데이터 수신 작업은 메인 스레드가 아닌 별도 스레드에서 처리합니다.
- 연결 실패와 연결 해제 상황을 항상 처리합니다.
- 기기마다 통신 규격과 UUID, 데이터 형식이 다를 수 있음을 고려합니다.
2. Bluetooth Classic과 BLE의 차이
Bluetooth는 크게 Bluetooth Classic과 Bluetooth Low Energy(BLE)로 나눌 수 있습니다. 이름은 비슷하지만 통신 방식과 잘 맞는 사용 사례가 다릅니다.

| 구분 | Bluetooth Classic | BLE |
|---|---|---|
| 특징 | 지속적인 데이터 전송에 적합 | 낮은 전력 사용에 초점 |
| 주요 사례 | 차량 기기, 오디오, 시리얼 통신, 파일 전송 | 센서, 심박계, 비콘, 소형 IoT 기기 |
| 통신 방식 | 주로 RFCOMM 소켓 기반 | GATT 서비스와 Characteristic 기반 |
| 배터리 사용량 | 상대적으로 큼 | 상대적으로 적음 |
예를 들어 차량 장치와 지속적으로 메시지를 주고받거나 데이터를 전송해야 한다면 Classic Bluetooth가 잘 맞습니다. 반대로 짧은 센서 값을 주기적으로 읽어야 한다면 BLE가 더 적합합니다.
3. Android 버전별 Bluetooth 권한
Bluetooth 권한은 Android 12(API 31)를 기준으로 크게 바뀌었습니다. Android 12 이상에서는 주변 기기 권한을 사용하고, 이전 버전에서는 기존 Bluetooth 및 위치 권한을 함께 고려해야 합니다.
<!-- Android 11(API 30) 이하용 기존 권한 -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- Android 12(API 31) 이상: 주변 기기 검색 -->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN" />
<!-- Android 12(API 31) 이상: 연결 및 페어링된 기기 조회 -->
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Android 11 이하에서 주변 기기를 검색할 때 필요할 수 있음 -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
- Android 11 이하: 기기 검색 시 위치 권한이 필요할 수 있습니다.
-
Android 12 이상:
BLUETOOTH_SCAN,BLUETOOTH_CONNECT권한을 실행 중에 요청해야 합니다. -
BLE 광고 기능: 기기가 직접 광고를 송출한다면
BLUETOOTH_ADVERTISE권한도 필요합니다.
4. Bluetooth 통신 흐름
- 기기에 Bluetooth 어댑터가 있는지 확인합니다.
- Bluetooth가 꺼져 있다면 사용자에게 활성화를 요청합니다.
- 이미 페어링된 기기를 조회하거나 주변 기기를 검색합니다.
- 선택한 기기와 연결합니다.
- 연결된 소켓 또는 BLE GATT를 통해 데이터를 송수신합니다.
- 통신이 끝나면 연결과 리소스를 해제합니다.
Bluetooth Classic은 연결 후 InputStream과
OutputStream으로 데이터를 읽고 쓸 수 있어, 네트워크 소켓 통신과
비슷하게 이해하면 편합니다.
5. 연결 및 데이터 전송 샘플 코드
아래 코드는 이미 페어링된 Bluetooth Classic 기기 중 이름이 일치하는 기기를 찾고,
RFCOMM 소켓으로 연결한 뒤 문자열을 전송하는 예제입니다.
DEVICE_NAME과 UUID는 실제 연결하려는 장치 사양에 맞게 변경해야 합니다.
public class BluetoothHelper {
private static final String DEVICE_NAME = "SampleDevice";
// 기기 제조사가 제공하는 Bluetooth SPP UUID를 사용해야 합니다.
private static final UUID SERVICE_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final BluetoothAdapter bluetoothAdapter;
public BluetoothHelper(Context context) {
BluetoothManager manager =
(BluetoothManager) context.getSystemService(
Context.BLUETOOTH_SERVICE
);
bluetoothAdapter = manager.getAdapter();
}
public void connectAndSend() {
if (bluetoothAdapter == null) {
Log.e("BT", "이 기기는 Bluetooth를 지원하지 않습니다.");
return;
}
if (!bluetoothAdapter.isEnabled()) {
Log.e("BT", "Bluetooth가 꺼져 있습니다.");
return;
}
BluetoothDevice targetDevice = null;
for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) {
if (DEVICE_NAME.equals(device.getName())) {
targetDevice = device;
break;
}
}
if (targetDevice == null) {
Log.e("BT", "페어링된 기기를 찾지 못했습니다.");
return;
}
BluetoothDevice device = targetDevice;
new Thread(() -> {
BluetoothSocket socket = null;
try {
// 검색 중이면 연결 속도가 느려질 수 있으므로 취소합니다.
bluetoothAdapter.cancelDiscovery();
socket = device.createRfcommSocketToServiceRecord(
SERVICE_UUID
);
socket.connect();
OutputStream outputStream = socket.getOutputStream();
outputStream.write("HELLO\n".getBytes(StandardCharsets.UTF_8));
outputStream.flush();
Log.d("BT", "메시지 전송 완료");
} catch (IOException e) {
Log.e("BT", "Bluetooth 연결 또는 전송 실패", e);
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
}).start();
}
}
Android 12 이상에서는 위 코드를 실행하기 전에
BLUETOOTH_CONNECT 권한이 허용되었는지 확인해야 합니다.
또한 실제 서비스에서는 연결 후 소켓을 바로 닫기보다, 수신용 스레드를 유지하면서
InputStream으로 장치 응답을 읽는 구조를 사용합니다.
Bluetooth 통신에서 가장 중요한 것은 “연결되면 끝”이라고 생각하지 않는 것입니다. 권한 거부, 연결 실패, 통신 끊김을 모두 정상적인 상황으로 보고 처리해야 사용자 입장에서 안정적인 기능이 됩니다.
참고: Android Bluetooth 공식 문서 , Android Bluetooth 권한 문서 , Android BLE 공식 문서
댓글
댓글 쓰기