<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 10 이하 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- BLE 기능 선언 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
Android 12 (API 31) 이상부터는 BLUETOOTH_SCAN, BLUETOOTH_CONNECT 권한이 필요
/ + 런타임 권한 요청도 필수!
val bluetoothAdapter: BluetoothAdapter by lazy {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
val scanner: BluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner
val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
Log.d("BLE", "디바이스 찾음: ${device.name} - ${device.address}")
}
}
fun startScan() {
val scanFilters = listOf<ScanFilter>() // 필요시 특정 서비스 UUID 필터 가능
val settings = ScanSettings.Builder().build()
scanner.startScan(scanFilters, settings, scanCallback)
}
var bluetoothGatt: BluetoothGatt? = null
fun connectToDevice(device: BluetoothDevice, context: Context) {
bluetoothGatt = device.connectGatt(context, false, gattCallback)
}
private val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("BLE", "연결 성공, 서비스 검색 시작")
gatt.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("BLE", "연결 끊김")
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
for (service in gatt.services) {
Log.d("BLE", "서비스 발견: ${service.uuid}")
for (characteristic in service.characteristics) {
Log.d("BLE", " 특성: ${characteristic.uuid}")
}
}
}
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
val value = characteristic.value
Log.d("BLE", "특성 읽기 결과: ${value?.decodeToString()}")
}
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
val value = characteristic.value
Log.d("BLE", "특성 알림 수신: ${value?.decodeToString()}")
}
}
// 읽기
val characteristic = gatt.getService(SERVICE_UUID).getCharacteristic(CHAR_UUID)
gatt.readCharacteristic(characteristic)
// 쓰기
characteristic.value = "Hello".toByteArray()
gatt.writeCharacteristic(characteristic)
// 알림 등록
gatt.setCharacteristicNotification(characteristic, true)
GATT는 Generic Attribute Profile의 약자로,
Bluetooth Low Energy에서 데이터를 주고받는 방식을 정의한 프로토콜!
"BLE에서 데이터를 어떻게 주고받을지에 대한 통신 규칙"