蓝牙4.0 据说是超低功耗,随之而来的是智能手表、手环、同屏对战塔防等。咱也了解了解相关的技术,做技术储备。今天需要总结的是蓝牙聊天的例子,例子来源于Android的官网。我们把关键的技术理一下。
关于蓝牙开发的主题,可以参考Android官网的这个链接。
1.BluetoothAdapter
表示一个本地设备的蓝牙适配器。它可以让你执行一些基本的蓝牙任务,比如初始化扫描设备、查询已经配对的蓝牙设备列表、使用MAC地址实例化一个蓝牙设备、创建一个蓝牙服务器Socket来监听一些连接、开始扫描周围低功耗的设备。
在JELLY_BEAN_MR1及以下的版本中,使用getDefaultAdapter方法来得到BluetoothAdapter;在JELLY_BEAN_MR2及以上的版本中通过getSystemService来拿到其实例。到目前为此最新的版本是LOLLIPOP,在5.0及以后的版本中会有一些新的改变。
我们用它的打开蓝牙数据开关、扫描周围蓝牙设备等等。在扫描的时候碰到一个蓝牙设备让谁能够扫描到的问题。如图:
在测试蓝牙连接的时候,怎么都发现不了周围的蓝牙设备。后来发现原来蓝牙开关不止是说开发就能让周围的设备扫描到你,还要如上图中设置成让附近所有的蓝牙设备均可检测到。
2.BluetoothDevice
表示一个远程的蓝牙设备。我们可以用它来创建一个与远程设备的连接来查询设备的信息,如名称、地址、类别、绑定状态。这个类只是一个小小的蓝牙硬件地址的包装器。我们从BluetoothAdapter中获取BluetoothDevice对象。
3.BluetoothServerSocket
当我们拿到一个BluetoothDevice对象,就等于拿到一个远程蓝牙设备了。接下来我们需要与它发生关系。我们要连接它。那既然要连接,那它必须处于监听状态。这个时候就来到了服务器Socket。BluetoothServerSocket实际上是一个用于监听的蓝牙socket。蓝牙Socket的接口类似于TCP的Socket接口。在服务器端,使用一个BluetoothServerSocket来创建一个服务器Socket。当接受一个连接的时候,它会返回一个BluetoothSocket对象来管理这个连接。在客户端,只需要使用简单的BluetoothSocket来连接和管理与服务器的socket。
如何使用这个类?我们使用 BluetoothAdapter.listenUsingRfcommWithServiceRecord()
方法来创建一个监听。然后调用 accept()
方法来监听到来的连接请求。accept方法会被阻塞,直到有一个连接建立起来。这个时候会返回一个 BluetoothSocket
对象来管理连接。一旦 BluetoothSocket
建立起来而且只需要一对一的连接时,我们最好关掉 BluetoothServerSocket
对象,不再监听别的连接。关闭 BluetoothServerSocket
不会关闭它之前创建的 BluetoothSocket
对象。当然如果是要一对多的话那就在最后关闭应用的时候关闭 BluetoothServerSocket。
4.BluetoothSocket
表示一个已经连接或者正在连接的蓝牙Socket。最通用的蓝牙Socket类似是RFCOMM,也是Android APIs支持的类型。RFCOMM是一个基于蓝牙的面向连接的流传输类型。它也以SPP(Serial Port Profile)著称。
5.InputStream
当我们与一台蓝牙设备建立起连接之后,我们需要做的就是收发数据。我们用一个线程来收数据,这样确保对方发过来的数据能够第一时候收到。
@Override public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // Keep listening to the InputStream while connected while (true) { try { if (mSocket.isConnected()) { Log.d(TAG, "socket is Connected before read."); } // Read from the InputStream bytes = mInStream.read(buffer); Log.d(TAG, "after read bytes is " + bytes); // Send the obtained bytes to the UI Activity mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); mService.connectionLost(); // Start the service over to restart listening mode mService.start(); break; } } }其中 read()方法会阻塞,直到有一段数据过来。
6.OutputStream
当一个连接建立完成之后,我们想要在什么地方发什么都可以了。如:
/** * Write to the connected OutStream. * * @param buffer * The bytes to write */ public void write(byte[] buffer) { try { mOutStream.write(buffer); // Share the sent message back to the UI Activity mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } }只要往流里面写入字节数据就完成了发送。
源码在哪里?大家装了SDK的话,在\samples\android-19\legacy\BluetoothChat目录下面,以前的版本在samples\android-17\BluetoothChat目录下面。