안드로이드 블루투스 기능에 대해 정리하였음.
Android Developer에 있는 내용과 포그라운드 서비스를 이용하여 블루투스 기능을 구현함.
1. 블루투스 권한 설정

안드로이드 12부터 새로운 블루투스 권한이 추가됨.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public void checkPermissions() {
String[] permission_list = {
Manifest.permission.BLUETOOTH_CONNECT,
};
for (String permission : permission_list) {
int check = checkCallingOrSelfPermission(permission); // 권한 혀용 여부
// 권한 거부 상태
if (check == PackageManager.PERMISSION_DENIED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permission_list, 0); // 권한 허용 여부 Dialog 출력
}
} else { // 권한 허용 상태
permission_state = 1; // 권한 허용 상태로 변경
}
}
}
|
블루투스 권한을 설정해줘야 블루투스 기능 사용 가능.
2. 앱에서 블루투스 켜기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, BT_REQUEST_ENABLE);
// 거부 또는 허용을 눌렀을 때
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case BT_REQUEST_ENABLE:
if (resultCode == RESULT_OK) {
//Toast.makeText(getApplicationContext(), "블루투스 활성화", Toast.LENGTH_LONG).show();
binding.tvBluetoothStatus.setTextColor(Color.GREEN);
binding.tvBluetoothStatus.setText("Bluetooth ON");
binding.btnSearch.setEnabled(true);
} else if (resultCode == RESULT_CANCELED) {
//Toast.makeText(getApplicationContext(), "취소", Toast.LENGTH_LONG).show();
binding.tvBluetoothStatus.setTextColor(Color.RED);
binding.tvBluetoothStatus.setText("Bluetooth OFF");
binding.btnSearch.setEnabled(false);
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
|
앱에서 블루투스를 켤 수 있도록 설정해줌.
3. 블루투스 장치 스캔

1
2
3
| // 블루투스 장치 검색 브로드캐스트 리시버 설정
IntentFilter filter_search = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver_search, filter_search);
|
1
2
3
4
5
6
7
8
9
10
| absBinding.btnSearch.setOnClickListener(new View.OnClickListener() { // 주변 블루투스 장치 검색
@Override
public void onClick(View view) {
if (!searchedBTArrayAdapter.isEmpty()) {
searchedBluetoothDevice.clear();
searchedBTArrayAdapter.notifyDataSetChanged();
}
search();
}
});
|
1
2
3
4
5
6
| public void search() {
if (bluetoothAdapter.isDiscovering()) { // 이미 검색 중인 경우
bluetoothAdapter.cancelDiscovery(); // 검색 중지
}
bluetoothAdapter.startDiscovery();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| private final BroadcastReceiver receiver_search = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) { // 블루투스 장치 검색 리시버
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@SuppressLint("MissingPermission")
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
if(deviceName != null && deviceHardwareAddress != null) { // 이름과 주소가 null이 아닌 경우에만 등록
Log.i("검색된 기기: ", deviceName);
Log.i("검색된 기기 주소", deviceHardwareAddress);
searchedHashMap = new HashMap<>();
searchedHashMap.put("name", deviceName);
searchedHashMap.put("address", deviceHardwareAddress);
searchedHashMap.put("connectState", "연결 안됨");
searchedBluetoothDevice.add(searchedHashMap);
if(pairedBluetoothDevice.size() > 0) {
for(int i=0;i<pairedBluetoothDevice.size();i++) { // 등록된 블루투스 장치들과 검색된 블루투스 장치들을 비교하여 중복된 값이 있으면 없앰
String name = pairedBluetoothDevice.get(i).get("name");
String address = pairedBluetoothDevice.get(i).get("address");
if(deviceName.equals(name) && deviceHardwareAddress.equals(address)) {
for(int j=0;j<searchedBluetoothDevice.size();j++) {
if (searchedBluetoothDevice.get(j).get("name").equals(name)) {
searchedBluetoothDevice.remove(j);
}
}
}
}
}
searchedBTArrayAdapter.notifyDataSetChanged();
}
}
}
};
|
블루투스를 켜야만 블루투스 장치 검색이 가능하도록 구현.
4. 블루투스 장치 연결


1
2
3
4
5
6
7
8
9
10
11
12
| public ConnectThread(BluetoothDevice device, int pos, int div) {
mmDevice = device;
position = pos; // 선택한 장치 포지션 구분
division = div; // 등록된 기기 또는 검색된 기기 구분
BluetoothSocket tmp = null;
try {
tmp = createBluetoothSocket(mmDevice);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public void run() {
bluetoothAdapter.cancelDiscovery(); // 블루투스 장치 검색 중지
try {
mmSocket.connect(); // 블루투스 장치 연결
} catch (IOException connectException) {
try {
mmSocket.close(); // 소켓 닫기
(BluetoothSearchActivity.context_BS).stopService(new Intent( (BluetoothSearchActivity.context_BS).getApplicationContext(), BluetoothConnectService.class)); // 백그라운드 장치 연결 서비스 중지
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// 블루투스 장치와 연결 성공 시 ConnectedThread 실행
manageConnectedSocket(mmSocket);
}
|
연결할 블루투스 장치를 누르면 포그라운드 서비스가 시작되고 장치에 연결하는 ConnectThread 실행.
5. 연결된 블루투스 장치의 데이터 수신
1
2
3
4
5
6
7
8
9
10
11
| public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| public void run() {
readBufferPosition = 0;
readBuffer = new byte[1024]; // 데이터를 수신하기 위한 버퍼 생성
while (true) {
try {
int byteAvailable = mmInStream.available(); // 데이터 수신 확인
if(byteAvailable > 0) { // 데이터가 수신된 경우
byte[] bytes = new byte[byteAvailable]; // 입력 스트림에서 바이트 단위로 읽음
mmInStream.read(bytes); // 입력 스트림 바이트를 한 바이트씩 읽음
for(int i = 0; i < byteAvailable; i++) {
byte tempByte = bytes[i]; // 개행문자를 기준으로 나눔(한줄)
if(tempByte == '\n') { // readBuffer 배열을 encodedBytes로 복사
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String text = new String(encodedBytes, "US-ASCII"); // 인코딩된 바이트 배열을 문자열로 변환
readBufferPosition = 0;
Log.i("수신받은 데이터 값 : ", text);
((MainActivity) MainActivity.context_main).runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText((MainActivity.context_main), "수신 값: " + text, Toast.LENGTH_SHORT).show();
}
});
} // 개행 문자가 아닐 경우
else {
readBuffer[readBufferPosition++] = tempByte;
}
}
}
Thread.sleep(80); // 0.08초 대기
} catch (IOException e) {
break;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
}
|
장치가 연결되어 있는 동안 ConnectedThread 실행되어 장치가 보내는 데이터 수신 가능.
6. 참고 사이트
안드로이드 블루투스 개요
bugwhale.tistory
코드는 여기서 확인 가능