Para criar uma conexão entre dois dispositivos, você deve implementar o
mecanismos do lado do servidor e do cliente, porque um dispositivo deve abrir um servidor
e o outro deve iniciar a conexão usando o
endereço MAC. O dispositivo do servidor e o dispositivo do cliente recebem as solicitações
BluetoothSocket
em diferentes
de várias formas. O servidor recebe informações do soquete quando uma conexão de entrada é
aceita. O cliente fornece informações do soquete quando abre um canal RFCOMM
ao servidor.
O servidor e o cliente são considerados conectados entre si quando cada um tem
um BluetoothSocket
conectado no mesmo canal RFCOMM. Neste ponto, cada
dispositivo pode receber fluxos de entrada e saída, e a transferência de dados pode começar, o que
é discutido na seção sobre como transferir o Bluetooth
dados. Esta seção
descreve como iniciar a conexão entre dois dispositivos.
Verifique se você tem Permissões de Bluetooth e configure o app para Bluetooth antes tentando encontrar dispositivos Bluetooth.
Técnicas de conexão
Uma técnica de implementação é preparar automaticamente cada dispositivo como servidor para que cada dispositivo tenha um soquete de servidor aberto e detectando conexões. Em neste caso, qualquer um dos dispositivos pode iniciar uma conexão com o outro e se tornar o para o cliente. Como alternativa, um dispositivo pode hospedar explicitamente a conexão e abrir um soquete do servidor de anúncios sob demanda, e o outro dispositivo inicia a conexão.
Figura 1. Caixa de diálogo de pareamento do Bluetooth.
Conectar como servidor
Para conectar dois dispositivos, um deve atuar como servidor segurando uma
abrem
BluetoothServerSocket
O objetivo do soquete do servidor é detectar as solicitações de conexão de entrada
e forneça um BluetoothSocket
conectado depois que uma solicitação for aceita. Quando o
O BluetoothSocket
é adquirido do BluetoothServerSocket
, o
BluetoothServerSocket
pode e deve ser descartado, a menos que você queira
o dispositivo aceite mais conexões.
Para configurar um soquete de servidor e aceitar uma conexão, faça o seguinte sequência de etapas:
Para receber um
BluetoothServerSocket
, faça uma chamadalistenUsingRfcommWithServiceRecord(String, UUID)
.A string é um nome identificável do seu serviço, que o sistema grava automaticamente em uma nova entrada de banco de dados do Service Discovery Protocol (SDP) no dispositivo. O nome é arbitrário e pode ser simplesmente o nome do seu app. O identificador universal exclusivo (UUID) também está incluído na entrada SDP e forma a base para o acordo de conexão com o dispositivo cliente. Isso quando o cliente tenta se conectar a esse dispositivo, ele carrega um UUID que identifica de forma exclusiva o serviço ao qual deseja se conectar. Esses Os UUIDs precisam corresponder para que a conexão seja aceita.
Um UUID é um formato padronizado de 128 bits para um ID de string usado para e identificar informações. Um UUID é usado para identificar informações que precisam ser único em um sistema ou rede, porque a probabilidade de um UUID ser repetidos é efetivamente zero. Ele é gerado de modo independente, sem o uso de uma autoridade centralizada. Nesse caso, ele é usado para identificar exclusivamente seu para o serviço Bluetooth desse app. Para receber um UUID para uso com seu app, use um das muitas opções aleatórias
UUID
na Web e, em seguida, inicialize um UUID comfromString(String)
Para começar a detectar solicitações de conexão, chame
accept()
Essa é uma chamada de bloqueio. Ela é retornada quando uma conexão aceito ou que tenha ocorrido uma exceção. Uma conexão é aceita somente quando um dispositivo remoto enviou uma solicitação de conexão contendo um UUID que corresponde aquele registrado nesse soquete do servidor de detecção. Quando bem-sucedido,
accept()
retorna umBluetoothSocket
conectado.A menos que você queira aceitar outras conexões, chame
close()
Essa chamada de método libera o soquete do servidor e todos os seus recursos, mas não fecha o
BluetoothSocket
conectado retornado peloaccept()
. Ao contrário do TCP/IP, o RFCOMM permite apenas um cliente conectado por canal por vez. Por isso, na maioria dos casos, faz sentido chamarclose()
noBluetoothServerSocket
imediatamente após aceitar um soquete conectado.
Como a chamada accept()
é de bloqueio, não a execute na instância principal
linha de execução de interface de atividade. A execução em outra linha de execução garante que seu app possa
ainda respondem a outras interações do usuário. Geralmente faz sentido fazer todo o trabalho
que envolve um BluetoothServerSocket
ou BluetoothSocket
em uma nova linha de execução
gerenciados pelo seu app. Para cancelar uma chamada bloqueada, como accept()
, chame close()
.
na BluetoothServerSocket
ou BluetoothSocket
de outra linha de execução. Observação
que todos os métodos em uma BluetoothServerSocket
ou BluetoothSocket
seguro para linhas de execução.
Exemplo
Veja a seguir um thread simplificado para o componente do servidor que aceita conexões de entrada:
Kotlin
private inner class AcceptThread : Thread() { private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) { bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID) } override fun run() { // Keep listening until exception occurs or a socket is returned. var shouldLoop = true while (shouldLoop) { val socket: BluetoothSocket? = try { mmServerSocket?.accept() } catch (e: IOException) { Log.e(TAG, "Socket's accept() method failed", e) shouldLoop = false null } socket?.also { manageMyConnectedSocket(it) mmServerSocket?.close() shouldLoop = false } } } // Closes the connect socket and causes the thread to finish. fun cancel() { try { mmServerSocket?.close() } catch (e: IOException) { Log.e(TAG, "Could not close the connect socket", e) } } }
Java
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket // because mmServerSocket is final. BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code. tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { Log.e(TAG, "Socket's listen() method failed", e); } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned. while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "Socket's accept() method failed", e); break; } if (socket != null) { // A connection was accepted. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(socket); mmServerSocket.close(); break; } } } // Closes the connect socket and causes the thread to finish. public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close the connect socket", e); } } }
Neste exemplo, é desejada apenas uma conexão de entrada, portanto,
a conexão for aceita e o BluetoothSocket
for adquirido, o app vai transmitir o
Adquiriu BluetoothSocket
para uma linha de execução separada, fecha o
BluetoothServerSocket
e sai da repetição.
Quando accept()
retornar o BluetoothSocket
, o soquete já estará
conectados. Portanto, não chame
connect()
, da mesma forma que você
do lado do cliente.
O método manageMyConnectedSocket()
específico do app foi projetado para iniciar a
de transferência de dados, que é discutido no tópico sobre
transferindo Bluetooth
dados.
Normalmente, é necessário fechar o BluetoothServerSocket
ao terminar
para detectar conexões de entrada. Neste exemplo, close()
é chamado assim que
quando o BluetoothSocket
é adquirido. Você também pode fornecer um
na linha de execução que pode fechar o BluetoothSocket
particular no caso de
que você precisa parar de detectar no soquete do servidor.
Conectar como cliente
Para iniciar uma conexão com um dispositivo remoto que está aceitando
conexões em um soquete de servidor aberto, é preciso primeiro conseguir um BluetoothDevice
que representa o dispositivo remoto. Para aprender a criar um
BluetoothDevice
, consulte Encontrar o Bluetooth
dispositivos. Você deve
Em seguida, use o BluetoothDevice
para adquirir um BluetoothSocket
e iniciar o
uma conexão com a Internet.
Este é o procedimento básico:
Usando o
BluetoothDevice
, receba umBluetoothSocket
chamandocreateRfcommSocketToServiceRecord(UUID)
.Esse método inicializa um objeto
BluetoothSocket
que permite ao cliente conectar a umBluetoothDevice
. O UUID transmitido aqui precisa corresponder ao UUID usado pelo dispositivo do servidor quando chamoulistenUsingRfcommWithServiceRecord(String, UUID)
para abrir oBluetoothServerSocket
. Para usar um UUID correspondente, codifique o string UUID no seu app e referencie-a no servidor e o código do cliente.Inicie a conexão chamando
connect()
. Esse método é uma chamada de bloqueio.Depois que um cliente chama esse método, o sistema realiza uma pesquisa SDP para encontrar o dispositivo remoto com o UUID correspondente. Se a pesquisa for bem-sucedida e o dispositivo remoto aceita a conexão, compartilha o canal RFCOMM para uso durante a conexão, e o método
connect()
é retornado. Se a conexão falhar, ou se o métodoconnect()
expirar (após cerca de 12 segundos), o método gera umaIOException
.
Como connect()
é uma chamada de bloqueio, sempre realize essa ação
procedimento de conexão em uma linha de execução separada da atividade principal (IU)
fio
Exemplo
Este é um exemplo básico de um thread de cliente que inicia uma solicitação conexão:
Kotlin
private inner class ConnectThread(device: BluetoothDevice) : Thread() { private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) { device.createRfcommSocketToServiceRecord(MY_UUID) } public override fun run() { // Cancel discovery because it otherwise slows down the connection. bluetoothAdapter?.cancelDiscovery() mmSocket?.let { socket -> // Connect to the remote device through the socket. This call blocks // until it succeeds or throws an exception. socket.connect() // The connection attempt succeeded. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(socket) } } // Closes the client socket and causes the thread to finish. fun cancel() { try { mmSocket?.close() } catch (e: IOException) { Log.e(TAG, "Could not close the client socket", e) } } }
Java
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket // because mmSocket is final. BluetoothSocket tmp = null; mmDevice = device; try { // Get a BluetoothSocket to connect with the given BluetoothDevice. // MY_UUID is the app's UUID string, also used in the server code. tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, "Socket's create() method failed", e); } mmSocket = tmp; } public void run() { // Cancel discovery because it otherwise slows down the connection. bluetoothAdapter.cancelDiscovery(); try { // Connect to the remote device through the socket. This call blocks // until it succeeds or throws an exception. mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and return. try { mmSocket.close(); } catch (IOException closeException) { Log.e(TAG, "Could not close the client socket", closeException); } return; } // The connection attempt succeeded. Perform work associated with // the connection in a separate thread. manageMyConnectedSocket(mmSocket); } // Closes the client socket and causes the thread to finish. public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "Could not close the client socket", e); } } }
Neste snippet, o método cancelDiscovery()
é chamado antes da conexão
após uma tentativa de ataque. Sempre chame cancelDiscovery()
antes de connect()
.
especialmente porque cancelDiscovery()
funciona, independentemente de o dispositivo
a descoberta está em andamento. Caso seu app precise determinar se
a descoberta de dispositivos está em andamento. Você pode verificar isso usando
isDiscovering()
O método manageMyConnectedSocket()
específico do app foi projetado para iniciar a
para transferir dados, que é discutido na seção sobre
transferência de dados Bluetooth.
Quando terminar de usar o BluetoothSocket
, sempre chame close()
. Ao fazer isso
fecha imediatamente o soquete conectado e libera todas as informações internas
do Google Cloud.