블루투스 기기 찾기

BluetoothAdapter를 사용하면 기기 검색을 통해 또는 페어링된 기기 목록을 쿼리하여 원격 블루투스 기기를 찾을 수 있습니다.

블루투스 기기를 찾으려고 하기 전에 적절한 블루투스 권한이 있는지 확인하고 블루투스를 사용할 수 있도록 앱을 설정하세요.

기기 검색은 로컬 영역에서 블루투스 지원 기기가 있는지 검색하고 각 기기에 관한 일부 정보를 요청하는 검색 절차입니다. 이 프로세스는 탐색, 조회 또는 스캔이라고도 합니다. 근처 블루투스 기기는 현재 검색 가능한 방법으로 정보 요청을 수락하고 있는 경우에만 검색 요청에 응답합니다. 기기를 검색할 수 있으면 기기 이름, 클래스, 고유 MAC 주소와 같은 정보를 공유하여 검색 요청에 응답합니다. 그러면 검색 프로세스를 실행하는 기기가 이 정보를 사용하여 검색된 기기와의 연결을 시작할 수 있습니다.

검색 가능한 기기는 사용자 위치에 관한 정보를 공개할 수 있으므로 기기 검색 프로세스에 위치 액세스 권한이 필요합니다. 앱이 Android 8.0 (API 수준 26) 이상을 실행하는 기기에서 사용되는 경우 호환 기기 관리도구 API를 대신 사용해 보세요. 이 API는 앱을 대신하여 기기 검색을 실행하므로 앱에서 위치 정보 액세스 권한을 요청할 필요가 없습니다.

원격 기기와 처음으로 연결되면 페어링 요청이 자동으로 사용자에게 제공됩니다. 기기가 페어링되면 기기에 관한 기본 정보(예: 기기 이름, 클래스, MAC 주소)가 저장되며 블루투스 API를 사용하여 이를 읽을 수 있습니다. 원격 기기에 관해 알려진 MAC 주소를 사용하면 기기가 여전히 범위 내에 있다고 가정하고 검색을 실행하지 않고 언제든지 연결을 시작할 수 있습니다.

페어링된 것과 연결된 것에는 차이점이 있습니다.

  • 페어링이란 두 기기가 서로의 존재를 알고 있고, 인증에 사용할 수 있는 공유 링크 키를 보유하고, 서로 암호화된 연결을 설정할 수 있다는 의미입니다.
  • 연결된다는 것은 기기가 현재 RFCOMM 채널을 공유하고 있고 서로 데이터를 전송할 수 있음을 의미합니다. 현재 블루투스 API는 RFCOMM 연결을 설정하기 전에 기기를 페어링하도록 요구합니다. 블루투스 API와 암호화된 연결을 시작하면 페어링이 자동으로 실행됩니다.

다음 섹션에서는 페어링된 기기를 찾는 방법과 기기 검색을 사용하여 새 기기를 검색하는 방법을 설명합니다.

페어링된 기기 쿼리

기기 검색을 실행하기 전에 페어링된 기기 집합을 쿼리하여 원하는 기기가 이미 있는지 확인하는 것이 좋습니다. getBondedDevices()를 호출하면 됩니다. 이렇게 하면 페어링된 기기를 나타내는 BluetoothDevice 객체 집합이 반환됩니다. 예를 들어 다음 코드 스니펫에서 볼 수 있듯이 페어링된 모든 기기를 쿼리하고 각 기기의 이름과 MAC 주소를 가져올 수 있습니다.

Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
   val deviceName = device.name
   val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
   // There are paired devices. Get the name and address of each paired device.
   for (BluetoothDevice device : pairedDevices) {
       String deviceName = device.getName();
       String deviceHardwareAddress = device.getAddress(); // MAC address
   }
}

블루투스 기기와의 연결을 시작하려면 연결된 BluetoothDevice 객체에서 getAddress()를 호출하여 검색하는 MAC 주소만 있으면 됩니다. 연결 만들기에 관한 자세한 내용은 블루투스 기기 연결을 참고하세요.

기기 검색

기기 검색을 시작하려면 startDiscovery()를 호출합니다. 이 프로세스는 비동기식이며 검색이 성공적으로 시작되었는지 여부를 나타내는 불리언 값을 반환합니다. 검색 프로세스에는 일반적으로 약 12초의 조회 스캔이 포함되며, 이어서 블루투스 이름을 가져오기 위해 발견된 각 기기의 페이지 스캔이 포함됩니다.

검색된 각 기기에 관한 정보를 수신하려면 앱에서 ACTION_FOUND 인텐트에 BroadcastReceiver를 등록해야 합니다. 시스템이 각 기기에 대하여 이 인텐트를 브로드캐스트합니다. 인텐트에는 추가 필드 EXTRA_DEVICEEXTRA_CLASS가 포함되며, 각각 BluetoothDeviceBluetoothClass가 포함됩니다. 다음 코드 스니펫은 기기가 검색될 때 브로드캐스트를 처리하기 위해 등록하는 방법을 보여줍니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   // Register for broadcasts when a device is discovered.
   val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
   registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when(action) {
           BluetoothDevice.ACTION_FOUND -> {
               // Discovery has found a device. Get the BluetoothDevice
               // object and its info from the Intent.
               val device: BluetoothDevice =
                       intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
           }
       }
   }
}

override fun onDestroy() {
   super.onDestroy()
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...

   // Register for broadcasts when a device is discovered.
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           // Discovery has found a device. Get the BluetoothDevice
           // object and its info from the Intent.
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           String deviceName = device.getName();
           String deviceHardwareAddress = device.getAddress(); // MAC address
       }
   }
};

@Override
protected void onDestroy() {
   super.onDestroy();
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver);
}

블루투스 기기와의 연결을 시작하려면 BluetoothDevice에서 getAddress()를 호출하여 연결된 MAC 주소를 검색합니다.

검색 기능 활성화

다른 기기에서 로컬 기기를 검색할 수 있게 하려면 ACTION_REQUEST_DISCOVERABLE 인텐트를 사용하여 startActivityForResult(Intent, int)를 호출합니다. 그러면 자체 앱이 중지되는 설정 앱으로 이동할 필요 없이 시스템의 검색 가능 모드를 사용 설정하도록 요청이 전송됩니다. 기본적으로 기기는 2분 동안 검색 가능합니다. EXTRA_DISCOVERABLE_DURATION 추가 항목을 추가하여 다른 기간을 최대 1시간까지 정의할 수 있습니다.

다음 코드 스니펫은 기기를 5분 동안 검색할 수 있도록 설정합니다.

Kotlin

val requestCode = 1;
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
   putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivityForResult(discoverableIntent, requestCode)

Java

int requestCode = 1;
Intent discoverableIntent =
       new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, requestCode);


그림 2: 검색 기능 사용 설정 대화상자

그림 2와 같이 기기를 검색할 수 있도록 사용자 권한을 요청하는 대화상자가 표시됩니다. 사용자가 '허용'이라고 응답하면 기기는 지정된 시간 동안 검색 가능하게 됩니다. 그러면 활동은 onActivityResult() 콜백 호출을 수신하고, 결과 코드는 기기를 검색 가능한 기간과 동일하게 수신합니다. 사용자가 '거부'를 응답했거나 오류가 발생한 경우 결과 코드는 RESULT_CANCELED입니다.

기기는 할당된 시간 동안 자동으로 검색 가능한 모드로 유지됩니다. 검색 가능 모드가 변경되었을 때 알림을 받으려면 ACTION_SCAN_MODE_CHANGED 인텐트에 BroadcastReceiver를 등록하세요. 이 인텐트에는 각각 새 스캔 모드와 이전 스캔 모드를 제공하는 추가 필드 EXTRA_SCAN_MODEEXTRA_PREVIOUS_SCAN_MODE가 포함되어 있습니다. 각 추가 항목에 가능한 값은 다음과 같습니다.

SCAN_MODE_CONNECTABLE_DISCOVERABLE
기기가 검색 가능 모드입니다.
SCAN_MODE_CONNECTABLE
기기가 검색 가능 모드가 아니지만 연결을 수신할 수는 있습니다.
SCAN_MODE_NONE
기기가 검색 가능 모드가 아니므로 연결을 수신할 수 없습니다.

원격 기기와의 연결을 시작하는 경우 기기 검색 기능을 사용 설정할 필요가 없습니다. 검색 기능은 수신 연결을 수락하는 서버 소켓을 앱에서 호스팅하려는 경우에만 필요합니다. 원격 기기가 다른 기기와의 연결을 시작하기 전에 다른 기기를 검색할 수 있어야 하기 때문입니다.