Notice
Recent Posts
Recent Comments
Link
투케이2K
160. (TWOK/UTIL) [Android/Java] C_Bluetooth_Spp_Client_Module : 블루투스 SPP 통신 클라이언트 모듈 클래스 본문
투케이2K 유틸파일
160. (TWOK/UTIL) [Android/Java] C_Bluetooth_Spp_Client_Module : 블루투스 SPP 통신 클라이언트 모듈 클래스
투케이2K 2025. 2. 23. 13:02[설 명]
프로그램 : Android / Java
설 명 : C_Bluetooth_Spp_Server_Module : 블루투스 SPP 통신 서버 모듈 클래스
[소스 코드]
package com.example.javaproject.C_Module;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import com.example.javaproject.C_Util;
import com.example.javaproject.S_Log;
import org.json.JSONObject;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.UUID;
public class C_Bluetooth_Spp_Client_Module {
/**
* // --------------------------------------------------------------------------------------
* TODO [클래스 설명]
* // --------------------------------------------------------------------------------------
* 1. [설명] : 블루투스 SPP 통신 사용 모듈
* // --------------------------------------------------------------------------------------
* 2. 필요 퍼미션 : 필요 퍼미션 권한 : 위치 및 GPS 권한 , 블루투스 권한 - SCAN , ADVERTISE , CONNECT
*
* // TODO [공통]
* <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
* <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
*
* <uses-permission android:name="android.permission.BLUETOOTH"/>
* <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
* <uses-feature android:name="android.hardware.bluetooth_le" />
*
* // TODO [안드로이드 12 이상 : S 버전]
* <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
* <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
* <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
* // --------------------------------------------------------------------------------------
* */
/**
* // --------------------------------------------------------------------------------------
* TODO [빠른 로직 찾기 : 주석 로직 찾기]
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*/
// ------------------------------------------------------------------------------------------
// TODO [사용 방법]
// ------------------------------------------------------------------------------------------
/*
try {
new Thread(){
@Override
public void run(){
try {
// -------------------------------------------------
// TODO [1]. 소켓 통신 연결을 위한 Remote 기기 Mac 주소 지정
// -------------------------------------------------
// {address=38:30:F9:FA:86:8C, name=1996124, alias=1996124, state=12, type=3}
// -------------------------------------------------
C_Bluetooth_Spp_Client_Module.DEVICE_ADDRESS = "38:30:F9:FA:86:8C";
// --------------------------------------
// TODO [2]. [소켓 모듈 클래스 인스턴스 초기화]
// --------------------------------------
C_Bluetooth_Spp_Client_Module c_socket_module = C_Bluetooth_Spp_Client_Module.getInstance();
c_socket_module.setContext(A_Intro.this);
// --------------------------------------
// TODO [3]. [소켓 연결 수행]
// --------------------------------------
if(c_socket_module.connectHost(C_Bluetooth_Spp_Client_Module.DEVICE_ADDRESS) == true) { // TODO [소켓 연결 상태 확인]
// --------------------------------------
// TODO [4]. [기기 등록 요청 수행]
// --------------------------------------
HashMap<String, Object> deviceRegMap = c_socket_module.request_Device_Reg();
S_Log._W_("소켓 통신 :: 디바이스 등록 요청 수행 결과 확인", new String[]{
"SUCCESS :: " + String.valueOf(deviceRegMap.get(c_socket_module.RETURN_SUCCESS_FLAG))
});
// --------------------------------------
// TODO [5]. [소켓 연결 종료]
// --------------------------------------
c_socket_module.closeSocket();
}
else {
S_Log._E_("C_Bluetooth_Spp_Client_Module :: connectHost :: 소켓 연결 실패", null);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
catch (Exception e) {
e.printStackTrace();
}
*/
// ------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------
// TODO [전역 변수 선언]
// ------------------------------------------------------------------------------------------
private String ACTIVITY_NAME = "C_Bluetooth_Spp_Client_Module";
private Context mMainCtx; // [컨텍스트]
public static String DEVICE_ADDRESS = "00:00:00:00:00:00"; // TODO [Connection Device Bluetooth Mac]
private static final UUID UUID_ARRAY[] = {
UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"), // TODO [Client : SmartPhone / Server : SmartPhone]
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // TODO [Client : SmartPhone / Server : Device]
};
private BluetoothAdapter bluetoothAdapter; // [블루투스 어댑터]
private BluetoothSocket bluetoothSocket; // [블루투스 소켓]
private OutputStream mOutputStream; // [스트림]
private PrintWriter mPrintWriter; // [스트림]
private InputStream mInputStream; // [스트림]
private DataInputStream mDataDataInputStream; // [스트림]
public static final String RETURN_SUCCESS_FLAG = "RETURN_SUCCESS_FLAG"; // [리턴 데이터 반환 키 값]
public static final String RETURN_ERROR_MESSAGE = "RETURN_ERROR_MESSAGE"; // [리턴 데이터 반환 키 값]
// ------------------------------------------------------------------------------------------
// TODO [콘텍스트 지정]
// ------------------------------------------------------------------------------------------
public void setContext(Context ctx) {
mMainCtx = ctx;
}
// ------------------------------------------------------------------------------------------
// TODO [인스턴스 생성]
// ------------------------------------------------------------------------------------------
public static C_Bluetooth_Spp_Client_Module getInstance() { return C_Bluetooth_Spp_Client_Module.LazyHolder.INSTANCE; }
private static class LazyHolder {
private static final C_Bluetooth_Spp_Client_Module INSTANCE = new C_Bluetooth_Spp_Client_Module();
}
// ------------------------------------------------------------------------------------------
// TODO [디바이스 호스트 연결 실시]
// ------------------------------------------------------------------------------------------
/**
* @param deviceAddress : 연결한 Remote 디바이스 Mac 주소
* @return : 정상적으로 페어링 및 연결이 완료 된 경우 true , 아니면 false
*
* 참고 사항 정리 :
* 1. 사전 페어링이 되어 있지 않은 경우는 먼저, 페어링 요청 진행 후 >> Remote 쪽에서 수락 시 연결 상태 return 값 확인 가능
* 2. 사전 페어링이 되어 있는 경우, 즉시 connect 연결 시도 및 return 반환 수행
* */
// ------------------------------------------------------------------------------------------
public synchronized boolean connectHost(String deviceAddress) {
// [변수 선언]
boolean isConnection = false;
String M_LOG = "";
// [로직 처리 수행]
try {
if (mMainCtx != null){
// [블루투스 지원 가능 기기 및 활성 상태 확인]
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
M_LOG = "[Error] :: 블루투스 기능 지원 여부 확인 필요 (Bluetooth is not supported on this device)";
}
else {
if (bluetoothAdapter.isEnabled() == false){
M_LOG = "[Error] :: 블루투스 기능 활성 상태 확인 필요 (Bluetooth isEnabled False)";
}
else {
// [기능 사용에 필요한 권한 부여 상태 확인]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){ // TODO [안드로이드 12 이상]
if (ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED){
M_LOG = "[Error] :: 안드로이드 12 이상 - 블루투스 기능 사용 퍼미션 권한 확인 필요 (Permission Not Granted)";
}
}
else { // TODO [안드로이드 12 미만]
if (ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
M_LOG = "[Error] :: 안드로이드 12 미만 - 블루투스 기능 사용 퍼미션 권한 확인 필요 (Permission Not Granted)";
}
}
// TODO [에러 발생한 적이 없는 경우 : 상위에서 방어 로직 통과한 경우]
if (C_Util.stringNotNull(M_LOG) == false){
// [소켓 연결 수행]
if(this.bluetoothSocket != null) { // TODO [소켓이 널이 아닌 경우]
M_LOG = "[Error] :: 블루투스 소켓 연결 된 상태 (Socket Not Null)";
}
else { // TODO [소켓이 널인 경우]
S_Log.w("BLE_SPP", "CONNECT_MAC :: " + String.valueOf(deviceAddress));
if (C_Util.stringNotNull(deviceAddress) == true
&& String.valueOf(deviceAddress).contains(":") == true){ // [Mac 이 널이 아닌 경우]
// TODO [원격 장치 가져오기] : Ex - {address=38:30:F9:FA:86:8C, name=1996124, alias=1996124, state=12, type=3}
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
S_Log.w("BLE_SPP", "CONNECT_ING :: " + String.valueOf(device.getName()) + " / " + String.valueOf(device.getAddress()));
// TODO [BluetoothSocket 생성]
bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID_ARRAY[0]);
// TODO [연결 시도]
bluetoothSocket.connect();
S_Log.w("BLE_SPP", "CONNECT_SUCCESS :: Connected to the device :: " + String.valueOf(deviceAddress));
// TODO [입출력 스트림 열기]
this.mOutputStream = this.bluetoothSocket.getOutputStream(); // [읽기]
this.mPrintWriter = new PrintWriter(mOutputStream);
this.mInputStream = this.bluetoothSocket.getInputStream(); // [쓰기]
this.mDataDataInputStream = new DataInputStream(mInputStream);
M_LOG = "\n[Success] :: 블루투스 소켓 생성 및 호스트 연결 완료\n";
M_LOG += "\n[Input Device Mac] :: " + String.valueOf(deviceAddress) + "\n";
M_LOG += "\n[Remote Device Name] :: " + String.valueOf(device.getName()) + "\n";
M_LOG += "\n[Remote Device Mac] :: " + String.valueOf(device.getAddress()) + "\n";
M_LOG += "\n[Remote Device Type] :: " + String.valueOf(device.getType()) + "\n";
M_LOG += "\n[Remote Device Uuids] :: " + String.valueOf(device.getUuids()) + "\n";
M_LOG += "\n[Remote Device Bond State] :: " + String.valueOf(device.getBondState()) + "\n";
// TODO [연결 완료 리턴 변수 삽입]
isConnection = true;
}
else {
M_LOG = "[Error] :: 연결할 디바이스 맥 정보 확인 필요 (deviceAddress Is Null)";
}
}
}
}
}
}
else {
M_LOG = "[Error] :: mMainCtx Is Null";
}
}
catch (Exception e){
e.printStackTrace();
// [로그 삽입]
M_LOG = "[Exception] :: " + String.valueOf(e.getMessage());
// [Exception 발생 시 소켓 연결 종료]
closeSocket();
}
S_Log._W_(ACTIVITY_NAME + " :: connectHost :: 블루투스 소켓 호스트 연결 수행", new String[]{
"M_LOG :: " + M_LOG,
"RETURN :: " + isConnection
});
// [리턴 반환 수행]
return isConnection;
}
// ------------------------------------------------------------------------------------------
// TODO [소켓 연결 종료]
// ------------------------------------------------------------------------------------------
public synchronized void closeSocket() {
// [변수 선언]
String M_LOG = "";
// [로직 처리 수행]
try {
// [생성된 소켓이 있는 경우 종료 및 스트림 닫기]
if(this.bluetoothSocket != null) {
// [스트림 닫기]
this.mPrintWriter.close();
this.mDataDataInputStream.close();
this.mOutputStream.close();
this.mInputStream.close();
// [소켓 닫기]
this.bluetoothSocket.close();
this.bluetoothSocket = null;
M_LOG = "[Success] :: bluetoothSocket Closed";
}
else {
M_LOG = "[Error] :: bluetoothSocket Is Null";
}
}
catch (Exception e) {
e.printStackTrace();
M_LOG = "[Exception] :: " + String.valueOf(e.getMessage());
try { this.bluetoothSocket = null; } catch (Exception es){}
}
S_Log._E_(ACTIVITY_NAME + " :: closeSocket :: 블루투스 소켓 연결 종료 수행", new String[]{ "M_LOG :: " + String.valueOf(M_LOG) });
}
// ------------------------------------------------------------------------------------------
// TODO [SEARCH FAST] : [기기 등록 요청 실시 >> 응답 결과 확인]
// ------------------------------------------------------------------------------------------
public synchronized HashMap request_Device_Reg() {
S_Log._D_("기기 등록 요청 수행", null);
/**
* // ----------------------------------------
* TODO [REQUEST] : [APP >> DEVICE]
* // ----------------------------------------
*
* {
* "reg_name" : "TOWK"
* }
*
* // ----------------------------------------
* */
/**
* // ----------------------------------------
* TODO [RESPONSE] : [DEVICE >> APP]
* // ----------------------------------------
*
* {
* "result" : true
* }
*
* // ----------------------------------------
* */
// -----------------------------------------------
// [리턴 변수 선언]
// -----------------------------------------------
HashMap<String, Object> returnData = new HashMap<>();
// -----------------------------------------------
// [로직 처리 수행]
// -----------------------------------------------
try {
// -----------------------------------------
// TODO [1]. [디바이스 등록 요청 실시]
JSONObject reqJson = new JSONObject();
reqJson.put("process", "DP01");
reqJson.put("mode", "create");
String requestData = reqJson.toString();
S_Log._D_("[요청] :: [APP] >> [DEVICE] :: 기기 등록 요청 수행", new String[]{
"REQUEST :: " + requestData.toString()
});
mPrintWriter.write(requestData); // [데이터 전송]
mPrintWriter.flush();
// -----------------------------------------
// -----------------------------------------
// TODO [2]. [디바이스 정보 응답 확인 실시]
int len = 0;
byte[] buffer = new byte[6144];
if(mInputStream != null){
len = mInputStream.read(buffer);
}
byte[] subBuffer = new byte[len];
System.arraycopy(buffer, 0, subBuffer,0, len);
// [byte to string 변환]
String responseString = new String(subBuffer, "UTF-8");
responseString = responseString.trim();
S_Log._D_("[응답] :: [DEVICE] >> [APP] :: 기기 등록 응답 확인", new String[]{
"RESPONSE :: " + responseString.toString()
});
// [리턴 데이터 삽입]
returnData.put(RETURN_SUCCESS_FLAG, true);
returnData.put(RETURN_ERROR_MESSAGE, responseString);
// -----------------------------------------
}
catch (Exception e){
e.printStackTrace();
// [에러 발생 데이터 삽입]
returnData.put(RETURN_SUCCESS_FLAG, false);
returnData.put(RETURN_ERROR_MESSAGE, String.valueOf(e.getMessage()));
}
// [리턴 반환 실시]
return returnData;
}
} // TODO [클래스 종료]
반응형
'투케이2K 유틸파일' 카테고리의 다른 글
Comments