In depth analysis of Android bluetooth development

  • 2020-05-17 06:31:08
  • OfStack

1. Use the response permission of bluetooth


<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

2. Configure the native bluetooth module

The first step here is to understand the operation of bluetooth 1 core class BluetoothAdapter


BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
// Directly open the system's bluetooth Settings panel 
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 0x1);
// Turn on bluetooth directly 
adapter.enable();
// Close the bluetooth 
adapter.disable();
// Turn on bluetooth discovery on the device (enabled by default) 120 Second, can be extended to the maximum time 300 A second) 
Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);// Set the duration (maximum) 300 A second) 

3. Search for bluetooth devices

Search for bluetooth devices using the startDiscovery() method of BluetoothAdapter

The startDiscovery() method is an asynchronous method that returns immediately after the call. The method searches for other bluetooth devices for 12 seconds. After this method is called, the search is actually done in an System Service, so you can call the cancelDiscovery() method to stop the search (which can be called when an discovery request is not executed).

After requesting Discovery, the system searches for the bluetooth device. During this process, the system sends the following three broadcasts:

ACTION_DISCOVERY_START: start the search

ACTION_DISCOVERY_FINISHED: end of search

ACTION_FOUND: find the device, this Intent contains two extra fields: EXTRA_DEVICE and EXTRA_CLASS, BluetooDevice and BluetoothClass, respectively.

We can register the corresponding BroadcastReceiver to receive the broadcast response, so as to achieve certain functions


//  create 1 A receiving ACTION_FOUND The radio BroadcastReceiver
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        //  Find equipment 
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            //  from Intent Gets the device object in 
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //  Put the device name and address in array adapter In order to ListView Shown in the 
            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
        }
    }
};
//  registered BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); //  Don't forget to unbind later 

4. Bluetooth Socket communication

If you intend to suggest a connection between two bluetooth devices, you must implement a server-side and client-side mechanism. When two devices have one BluetoothSocket connected under the same RFCOMM channel, the two devices can be said to have established a connection.

The way the server device and the client device get BluetoothSocket is different. The server device is obtained by accepted1 incoming connection, while the client device is obtained by opening 1 RFCOMM channel to the server.

Server-side implementation

Get BluetoothServerSocket (UUID for matching between client and server) by calling the listenUsingRfcommWithServiceRecord(String, UUID) method of BluetoothAdapter

Call BluetoothServerSocket's accept() method to listen for connection requests, and if a request is received, return an instance of BluetoothSocket (this method is the block method and should be placed in a new thread)

If you do not want another connection in accept, call BluetoothServerSocket's close() method to free up the resource (after calling this method, the previously obtained BluetoothSocket instance does not have close. However, since RFCOMM1 only allows 1 connection in 1 channel at a time, close will drop BluetoothServerSocket after 1 connection in accept1.)


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 = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException 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) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                manageConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }
    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}

Client implementation
Search for BluetoothService on the server side

Call BluetoothService's listenUsingRfcommWithServiceRecord(String, UUID) method to get BluetoothSocket (this UUID should be the same as UUID on the server side)

Call the connect() method of BluetoothSocket, which is the block method. If UUID matches UUID on the server side and the connection is made to accept on the server side, the connect() method returns

Note: before calling the connect() method, make sure there is no current search device, or the connection will become very slow and fail easily


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;
        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }
    public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();
        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }
        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }
    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

Connection management (data communication)
InputStream and OutputStream were obtained by getInputStream() and getOutputStream() methods of BluetoothSocket, respectively

Read and write operations are performed using the read(bytes[]) and write(bytes[]) methods, respectively

Note: the read(bytes[]) method will direct block until information is read from the stream, while the write(bytes[]) method will not often block (e.g., write will block if another device fails to read in time or the intermediate buffer is full).


private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }
    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()
        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }
    /* Call this from the main Activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }
    /* Call this from the main Activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

Official Android SDK, Android/OPhone notes for full development


Related articles: