안드로이드 블루투스 (classic bl) #2 기기검색&연결

나고수·2022년 6월 26일
0

Android

목록 보기
82/109
post-thumbnail
//blAdatper 가져오는 코드 
 fun Context.getBlAdapter(): BluetoothAdapter? {
        val bm = this.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        return bm.adapter
    }
//기기 검색하는 코드

@SuppressLint("MissingPermission") //원래를 권한을 허용했는지 체크해줘야합니다. 저는 귀찮아서 그냥 lintError를 무시해버렸습니다.
class ScanBluetooth(
    private val context: Context,
    private val fm: FragmentManager,
    private val scanFailedCallBack: (() -> Unit)
) {

    private val mainThreadHandler = HandlerCompat.createAsync(Looper.getMainLooper())
    private var receiver: BroadcastReceiver? = null //블루투스 기기를 찾으면 응답을 받을 receiver를 설정
    private val adapter by lazy { context.getBlAdapter() }
    private val scanner = adapter?.bluetoothLeScanner

    fun scanDevices() {
        if (adapter?.isEnabled == false) return //blAdatper가 없으면 블투를 지원하지 않는 기기입니다.
        setReceiver()
        adapter?.cancelDiscovery() //블루투스 기기검색 중이 아니여도 cancle 할 수 있으므로, 예방적?으로 미리 cancle 시켜줍니다.

        mainThreadHandler.postDelayed({
            disconnectBl() //1분이 지나면 기기검색을 해지합니다.
            scanFailedCallBack() //실패 콜백을 부릅니다.
        }, 1 * 60 * 1000)

        val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
        context.registerReceiver(receiver, filter)
        adapter?.startDiscovery() //기기검색을 시작합니다.
    }

    private fun setReceiver() {
        // Create a BroadcastReceiver for ACTION_FOUND.
        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
                        Timber.d("name $deviceName")

                        if (deviceHardwareAddress == Const.blMac) {
                            Const.blDevice = device
                            disconnectBl() //원하는 장치를 찾으면 receiver을 해지합니다.
                            showDialog() //원하는 기기를 찾았다는 다이어로그를 띄워줍니다.
                            return
                        }
                    }
                }
            }
        }
    }

    fun disconnectBl() {
        receiver?.let {
            context.unregisterReceiver(receiver)
            receiver = null
        }
        adapter?.cancelDiscovery()
        //주의: 기기 검색을 수행하면 블루투스 어댑터의 리소스가 많이 소모됩니다. 
        // 연결할 기기를 검색한 뒤에는 연결을 시도하기 전에 cancelDiscovery()를 사용하여 검색을 중단했는지 확인합니다. 
        // 또한 기기에 연결된 상태로 검색을 수행하면 안 됩니다. 
        // 검색 프로세스가 기존 연결에서 사용 가능한 대역폭을 대폭 감소시키기 때문입니다.
    }

    private fun showDialog() {
        PairingDialog().show(fm, null)
    }
}
//찾은 기기와 연결하겠냐고 묻는 다이어로그에서..

private lateinit var scanBluetooth: ConnectBluetooth.ConnectThread

   scanBluetooth = ConnectBluetooth(
            device = Const.blDevice!!, //기기검색 성공 후 Const에 저장해놓은 BluetoothDevice
            context = requireContext(),
            //연결 성공
            object : Handler(Looper.getMainLooper()) {
                override fun handleMessage(msg: Message) {
                    super.handleMessage(msg)
                    val message = msg.obj.toString() //thread에서 받은 msg를 토스트로 띄웁니다.
                    Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
                    //연결 성공후 todoSomething
                }
            },
            //연결 실패
            object : Handler(Looper.getMainLooper()) {
                override fun handleMessage(msg: Message) {
                    super.handleMessage(msg)
                    val message = msg.obj.toString()
                    Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
                }
            }
        ).ConnectThread()

//연결하기 버튼을 누르면
scanBluetooth.start()
//찾은 기기와 연결하는 쓰레드

@SuppressLint("MissingPermission") //원래를 권한을 허용했는지 체크해줘야합니다. 저는 귀찮아서 그냥 lintError를 무시해버렸습니다.
class ConnectBluetooth(
    private val device: BluetoothDevice,
    private val context: Context,
    private val successHandler: Handler,
    private val failHandler: Handler,
) {
    val adapter = context.getBlAdapter()

        private val blSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
        device.createInsecureRfcommSocketToServiceRecord(uuid)
    }
    private var blSocket: BluetoothSocket? = null

    inner class ConnectThread() : Thread() { //기기와 블루투스 연결하는 쓰레드
        override fun run() {
            super.run()

// 혹시 위에 blSocket으로 했을때 오류가 난다면 밑에 코드로 해보세요.
//            blSocket = device::class.java.getMethod(
//                "createRfcommSocket",
//                *arrayOf<Class<*>?>(Int::class.javaPrimitiveType)
//            ).invoke(device, 1) as BluetoothSocket

            Const.blSocket = blSocket //연결할 기기의 소켓을 Const에 저장
            adapter?.cancelDiscovery()

            try {
                blSocket?.let { socket ->
                    socket.connect() //소켓에 연결 
                }
            } catch (e: Exception) {
                e.printStackTrace()
                val ms = failHandler.obtainMessage() //실패 시 핸들러에 메세지를 보냅니다. 
                ms.obj = "블루투스에 연결 할 수 없습니다."
                ms.sendToTarget()
                return
            }
            //성공 시 핸들러에 메세지를 보냅니다. 
            val ms = successHandler.obtainMessage()
            ms.obj = "블루투스에 연결되었습니다."
            ms.sendToTarget()
        }
    }
}
profile
되고싶다

0개의 댓글

관련 채용 정보