关于Android蓝牙设备的连接使用

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/dahaohan/article/details/51222335

Android Bluetooth

目前低功耗短距离传输设备蓝牙已属于智能手机标配,这里就介绍一下Android设备上Bluetooth的简单连接使用、蓝牙的自组网/蓝牙的一对多连接。

蓝牙的通信和连接,在维基百科关于蓝牙的说明:https://en.wikipedia.org/wiki/Bluetooth#Communication_and_connection

**A master Bluetooth device can communicate with a maximum of seven devices in a piconet (an ad-hoc computer network using Bluetooth technology), though not all devices reach this maximum. The devices can switch roles, by agreement, and the slave can become the master (for example, a headset initiating a connection to a phone necessarily begins as master—as initiator of the connection—but may subsequently operate as slave).
The Bluetooth Core Specification provides for the connection of two or more piconets to form a scatternet, in which certain devices simultaneously play the master role in one piconet and the slave role in another.
At any given time, data can be transferred between the master and one other device (except for the little-used broadcast mode.[citation needed]) The master chooses which slave device to address; typically, it switches rapidly from one device to another in a round-robin fashion. Since it is the master that chooses which slave to address, whereas a slave is (in theory) supposed to listen in each receive slot, being a master is a lighter burden than being a slave. Being a master of seven slaves is possible; being a slave of more than one master is difficult.[citation needed] The specification is vague as to required behavior in scatternets.**

若英文理解得不是很好,相应的度娘百科有对应的翻译:http://baike.baidu.com/view/1028.htm#3

主要提及蓝牙核心规范是支持一个蓝牙设备作为主设备(Server)能够同时与最多7个从设备(Client)建立连接,这是对蓝牙支持一对多建立基础的“星形网络”简单介绍。

Bluetooth自组网( Ad Hoc Networking)

由于博主在写实例测试过程发现,蓝牙间的连接并不像上述介绍的仅仅只是一个主设备连接7个从设备那么简单,而是蓝牙在此基础上依然可以与其它蓝牙设备建立连接,多个小型”星形网”互联形成一个”散射网络”。
故而google一些更详细的资料来了解了下蓝牙的自组网:
http://www.netlab.tkk.fi/opetus/s38030/k02/Papers/16-Jari.pdf 这篇文章是英文的但是介绍的比较详细和全面。

文章内的一幅图比较好的展示了蓝牙技术支持的自组建网络:
这里写图片描述
比较详细的技术支持限制以及相关应用等,可以静下心来好好看看这篇英文论文。

Android Bluetooth的连接使用

Android官方Bluetooth API Guides:
http://developer.android.com/guide/topics/connectivity/bluetooth.html#ManagingAConnection

  • Bluetooth Permissions
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <!-- 启动蓝牙设备发现,更改蓝牙设备设置需要BLUETOOTH_ADMIN -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  • BluetoothAdapter
    BluetoothAdapter代表了本机的蓝牙适配器设备,基本上是使用蓝牙功能的入口。

  • BluetoothDevice
    代表了远程蓝牙设备,搜索到的蓝牙设备,已连接的对端蓝牙。

  • BluetoothSocket
    类似TCP Socket,建立连接后用于传输数据的socket

  • BluetoothServerSocket
    主蓝牙设备(Server)的监听Socket,用于监听处理从设备Client发起的连接。

    PS:蓝牙设备具有一个可见性设置,出于安全考虑默认都是不可见的,即你启动搜索周围的蓝牙设备也不会发现不可见的的蓝牙设备。

    //enable蓝牙设备的可见性
    Intent discoverableIntent = new
    Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    //DISCOVERABLE_DURATION取值为0-3600秒 default=120
    discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
    startActivity(discoverableIntent);
  1. 获取Remote BluetoothDevice
        //获取本地蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if( mBluetoothAdapter == null ){
            Toast.makeText(this,"未找到蓝牙设备", Toast.LENGTH_SHORT).show();
            finish();
        } 

        if( !mBluetoothAdapter.isEnabled() ) {
            //申请打开蓝牙设备
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivity(intent);
        }

        //获取本机已配对的蓝牙设备
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
            //If there are paired devices
            if (pairedDevices.size() > 0) {
                // Loop through paired devices
                for (BluetoothDevice device : pairedDevices) {
                    // Add the name and address to an array adapter to show in a ListView
                    mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
            }
        }

        mBluetoothAdapter.startDiscovery();
        //注册广播接收,搜索查找周围的设备
        // Create a BroadcastReceiver for ACTION_FOUND
        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                // When discovery finds a device
                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    // Get the BluetoothDevice object from the Intent
                    BluetoothDevice device =     intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    // Add the name and address to an array adapter to show in a ListView
                    mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
                }
            }
        };
        // Register the BroadcastReceiver
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
  1. 作为主设备Server
    建立蓝牙连接需要有一方为主设备Server,另一方为从设备Client,而无论Server接受连接或者Client发起连接这个过程都是一个阻塞的调用,所以需要在子线程内进行接受或者发起连接。
    主设备需要通过本地的蓝牙适配器mBluetoothAdapter的listenUsingRfcommWithServiceRecord函数获得server socket 然后调用socket的accept函数来持续监听client的连接请求。
    PS:listenUsingRfcommWithServiceRecord(String, UUID)函数的第一个参数String代表这个蓝牙service的名称可以自己定义;第二个UUID则是一个128-bits通用唯一标示码,是蓝牙服务的唯一标识码,当client发起连接请求时也会包含一个uuid用于区分要连接哪一个蓝牙服务,即要保证client和server连接成功需要有同样的UUID。 UUID网上有很多生成方法,随意挑一个生成使用就行。
public class BltServerSocketThread extends Thread{


    private final BluetoothServerSocket mmServerSocket;
    private final BluetoothAdapter mBluetoothAdapter;
    private final  UUID MY_UUID;

    public BltServerSocketThread(BluetoothAdapter bluetoothAdapter) {

        mBluetoothAdapter = bluetoothAdapter;
        MY_UUID = UUID.fromString("2da12563-e314-1211-7789-" + mBluetoothAdapter.getAddress().replace(":", ""));

        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code
            //get the server socket listenning the client's connection requests.
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("MyBLTServer", 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 {
                /*Start listening for connection requests by calling accept().
                 *This is a blocking call. A connection is accepted only when a remote device has sent 
                 * a connection request with a UUID matching the one registered with this listening server socket. 
                 * When successful, accept() will return a connected BluetoothSocket.
                 */
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                System.out.println("Unable to accept; close the socket and get out");
                cancel();
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                BltConnectionThread bltConnectionThread = new BltConnectionThread(socket);
                bltConnectionThread.start();
                EventBus.getDefault().post(bltConnectionThread);
                //if you want to connect only one bluetooth device,
                //should break here, close the server socket.
                //cancle(); break;
            }
        }
    }

    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}
  1. 作为从设备Client
public class BltClientConnectionThread extends Thread {

    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    private final  UUID MY_UUID;

    public BltClientConnectionThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        mmDevice = device;
        //The same as the server's uuid.
        MY_UUID = UUID.fromString("2da12563-e314-1211-7789-" + device.getAddress().replace(":", ""));

        // 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() {
        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
            cancel();
            return;
        }

        // Do work to manage the connection (in a separate thread)
        BltConnectionThread bltConnectionThread = new BltConnectionThread(mmSocket);
        bltConnectionThread.start();
        EventBus.getDefault().post(bltConnectionThread);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
        finally {

        }
    }
}
  1. 管理蓝牙链接
    连接成功后就可以获取到一个用于蓝牙通信的BluetoothSocket,每两个蓝牙设备直接成功建立连接都会获得一个BluetoothSocket。
public class BltConnectionThread extends Thread {

    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public BltConnectionThread(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() {

        int bufferSize = 1024;
        int bytesRead = -1;
        byte[] buffer = new byte[bufferSize];

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                final StringBuilder sb = new StringBuilder();
                // Read from the InputStream
                bytesRead = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                if (bytesRead != -1) {
                    String result = "";
                    while ((bytesRead == bufferSize) && (buffer[bufferSize] != 0)) {
                        result = result + new String(buffer, 0, bytesRead);
                        bytesRead = mmInStream.read(buffer);
                    }
                    result = result + new String(buffer, 0, bytesRead);
                    sb.append(result);
                }
                EventBus.getDefault().post(new BluetoothCommunicator(sb.toString()));
            } 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) { }
    }

}

蓝牙一对多连接

基本的原理就是上述的连接和管理,蓝牙服务端Server启动一个持续的socket listening,多个client向该server发起连接请求,即可建立多个连接。
这是博主写的一个简单的蓝牙多连接示例,分为server和client,server可以启动server socket监听,然后各个client可以点击搜索设备并且与server进行连接;连接成功后server端会显示已经成功连接的client列表,点击对应设备可向client发送消息。
AndroidMultiBluetoothSample:https://github.com/lishushu/AndroidMultiBluetoothSample.git

猜你喜欢

转载自blog.csdn.net/dahaohan/article/details/51222335