蓝牙通信是我们日常生活中比较方便的一种通信技术,Android从2.0版本的SDK就开始支持蓝牙。对开发人员来说,应用程序中蓝牙还是一种用来创建点对点连接通信的简单而高效的方式。
蓝牙通信功能的实现的基本流程大致分为蓝牙设备搜索、蓝牙设备连接和蓝牙通信三个阶段,这里我们就先来讨论蓝牙设备搜索功能的实现。
Android模拟器还不支持蓝牙,因此要测试使用蓝牙功能,必须使用至少两台Android设备。
(1)加入权限
要操作蓝牙,需要在AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
另外,要改变蓝牙的可见性以及启用/禁用蓝牙功能,还要声明:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
(2)获取蓝牙适配器BluetoothAdapter
首先来介绍关于蓝牙开发要用到的几个重要的类:
BluetoothAdapter
蓝牙适配器,整个蓝牙通信过程都要用到这个类,BluetoothAdapter里的方法很多,常用的有以下几个:
disable() 关闭蓝牙
enable() 打开蓝牙
getAddress() 获取本地蓝牙地址
getName() 获取本地蓝牙名称
getDefaultAdapter()获取默认BluetoothAdapter实例,这是静态方法
isEnabled() 判断蓝牙是否打开
startDiscovery()启动搜索蓝牙设备
cancelDiscovery()取消搜索蓝牙设备BluetoothDevice
这是一个描述一个具体蓝牙设备的类。常用方法有:
createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket
getState() 获取蓝牙状态
getAddress() 获取蓝牙设备地址
getName() 获取蓝牙设备名称BluetoothServerSocket
蓝牙通信服务器端类,蓝牙通信过程类似于Socket,当两台蓝牙设备连接配对之后,服务器端通过accept()方法来建立BluetoothSocket,需要注意的是,accept()方法会阻塞线程,应该放在新的线程中运行。
BluetoothSocket
这是服务器和客户端通信的通道,常用的方法有:
close() 关闭
connect() 连接
getInptuStream() 获取输入流
getOutputStream() 获取输出流
getRemoteDevice() 获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备
实现蓝牙设备搜索,我们暂时只要用到前面两个类。
与一般的设备适配器相当,我们要获取BluetoothAdapter时只需使用BluetoothAdapter类提供的getDefaultAdapter()方法。
BluetoothAdapter bAdapter = BluetoothAdapter.getDefaultAdapter();
if(bAdapter == null) {
Toast.makeText(this, "Bluetooth is not supported.", Toast.LENGTH_LONG).show();
finish();
return;
}
除了检测系统蓝牙适配器状态外,我们通常还需要获取蓝牙启用情况,并在当蓝牙功能关闭时询问是否打开蓝牙功能。
if(!bAdapter.isEnabled()) { //蓝牙未打开
//弹出对话框提示用户是否打开蓝牙
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE);
//bAdapter.enable(); 不做提示,强行打开
}
else {
Toast.makeText(MainActivity.this, "Bluetooth has been turned on.", Toast.LENGTH_SHORT).show();
}
(3)搜索蓝牙设备
获取了BluetoothAdapter之后,要发起搜索蓝牙设备是使用BluetoothAdapter的startDiscovery()方法。这个方法会触发两条系统广播,具体来说是搜索过程中触发的,分别是
BluetoothDevice.ACTION_FOUND //搜索到设备广播
BluetoothAdapter.ACTION_DISCOVERY_FINISHED //搜索完成广播
首先写好广播接收器。
List<BluetoothDevice> devices = new ArrayList<>();
private BroadcastReceiver searchReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//搜索到设备
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //获取蓝牙设备信息
devices.add(dev);
}
//搜索完成
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//搜索结果列表,对话框呈现
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("搜索到的蓝牙设备列表");
final String[] item = new String[devices.size()];
int n = item.length;
//遍历搜索结果
for(int i = 0; i < n; i ++) {
item[i] = devices.get(i).getName()+"\t:\t"+devices.get(i).getAddress();
}
builder.setItems(item, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, item[which], Toast.LENGTH_SHORT).show();
}
});
builder.create().show();
}
}
};
所以在启动搜索蓝牙设备之前,应该先注册这两条广播。
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
registerSearchReceiver();
}
//注册广播
private void registerSearchReceiver() {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); //搜索到设备广播
registerReceiver(searchReceiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //搜索完成广播
registerReceiver(searchReceiver, filter);
}
之后就可以启动蓝牙设备的搜索了。最后别忘记卸载掉广播。
@Override
protected void onDestroy() {
super.onDestroy();
unregisterSearchReceiver();
}
//卸载广播
private void unregisterSearchReceiver() {
unregisterReceiver(searchReceiver);
}
至此,蓝牙通信的第一步设备搜索功能已完成。