传说中蓝牙4.0支持BLE技术,不过下文只是传统的蓝牙开发。在正式的开发之前,官网先向我们抛出了如下几个概念:

所有蓝牙交互的入口点,通过它,你可以发现其他蓝牙设备,访问绑定的蓝牙设备,并且可以通过MAC地址实例化一个BluetooothDevice以及创建bluetoothserversocket来监听待接入的设备。

表示一个远程的蓝牙设备,用它你可以通过来申请与远程蓝牙设备的连接,当然你也可以通过它来访问设备名称,地址,绑定状态等

表示蓝牙套接字的接口,通过InputStream和OutputStream可实现与远程蓝牙设备的数据交换

表示一个开放的服务端套接字用来监听外部的申请,为了实现两个蓝牙设备的通信,必须有一端开放服务套接字来让远程设备请求连接,当远程设备的请求被允许时,那么就会返回一个连接的BluetoothSocket

描述了一个蓝牙设备的通用特性和能力,它是一组只读的特性用来定义设备的主要和次要设备类以及它的服务

下面还有诸如BluetoothProfile,BluetoothHeadset等这样的一些概念,但是由于本应用中不涉及,故不一一介绍。好了在正式蓝牙开发步骤之前,有一点是不容忽视的,那就是蓝牙的操作权限

上面两条代码是必须要加入到AndroidManifest.xml文件中的,第一条是使用蓝牙特性的权限如:申请连接,接受连接和传输数据,而第二条则主要是用来发现周围的蓝牙设备权限。好了,这样我们便可以开始肆无忌惮的蓝牙操作了。

建立本地蓝牙

首先是通过getDefaultAdapter()来获得BluetoothAdapter,代表本地蓝牙的接收器,并且整个系统中有且只能有一个

如果设备支持蓝牙,那么接下来该是使能蓝牙设备,调用函数来判断蓝牙是否被使能(也就是打开),如果返回false那么要通过

寻找蓝牙设备

通过BluetoothAdapter就可以发现远程设备或者访问已配对的设备,这里解释一下发现远程设备和访问已配对设备的区别,所谓发现远程设备是指对附近可被发现的蓝牙设备进行搜索并获取相应信息(如名字,MAC等);而访问已配对的设备则是指表示某些蓝牙设备的信息(名字,MAC)已经被存入本地,那么如果这些蓝牙设备在范围并且打开,那么只要使用MAC地址直接与设备连接,而无需发现查找这一步骤。

因为真正发现设备步骤之前,访问已经配对的设备是有必要的,因为可能你需要的设备已经在配对列表中,Android系统中只要调用getBondedDevices()函数就可以获得一系列绑定的BluetoothDevice,而发现蓝牙设备的操作也是很简单的,调用startDiscovery(),这个函数不过是一个搜索过程的启动按钮,并且会立刻返回是否正常启动搜索信息,那么接下来将是大约12S左右的蓝牙搜索过程,这里需要注意的是我们需要在程序中注册Broadcast Receiver组件,因为系统在每搜索到一个蓝牙设备后会通过ACTION_FOUND Intent来通知。

连接蓝牙设备

因为本人应用场合是主动去连接蓝牙设备,所以这里主要是实现以客户端连接步骤, 我们已经讲到了如何找到设备并获得

现设备过程关闭,因为该过程浪费资源很多会造成连接缓慢甚至是失败,调用cancelDiscovery();连接蓝牙设备则是调

实现,如果UUID及对方设备都已接受应该就能连接成功,不过该连接函数是个阻塞函数,所以为了

避免用户窗口的阻塞,一般将其放入单独的一个线程,示例代码如下 :

tip:UUID(Universally Unique Identifier),这里主要用该参数来申请连接特殊的蓝牙服务,如我申请的蓝牙串口那么就是

device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
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) { }
}
}

管理蓝牙连接

这样一句,这其实才是真正的重点,同样作为一个单独的线程,主要负责管理蓝牙数据的收发,这里主要通过蓝牙套接字获得数据的输入输出流,然后根据相应流接口对蓝牙进行读写操作:

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=newbyte[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) { }
}
}