实现安卓蓝牙2.0模块的通信功能
事先说明:
安卓蓝牙2.0的开发和BLE4.0的开发完全是不一样的,不过很多设备都采用双模蓝牙,所以掌握2.0也是很有必要的
安卓蓝牙需要手动申请定位权限,可参考我的博客点击打开链接
蓝牙连接过程:
1、查询用户是否开启蓝牙。
2、搜索附近的可用的蓝牙。
3、进行蓝牙配对。
4、进行蓝牙连接。
5、获取输入流和输出流。
6、发送消息。
蓝牙开发思路:
蓝牙从连接到通信整个过程都是通过接收和发送广播进行的,下面是蓝牙进行特定操作时发出来的广播图,晒上我自己画的美图
蓝牙广播内容:
ACTION_STATE_CHANGED 当你蓝牙开启或者关闭的时候发送
ACTION_FOUND 当你匹配到附近蓝牙设备时发送
ACTION_DISCOVERY_STARTED 当你开始搜索附近蓝牙设备时发送
ACTION_DISCOVERY_FINISHED 当你结束搜索附近蓝牙设备时发送
ACTION_BOND_STATE_CHANGED 当你蓝牙设备匹配状态发生变化时发送
实现需要的权限:
由于安卓4.x以上的版本使用蓝牙,需要开启定位权限才能搜索到附近的蓝牙设备
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
这里使用俩手机,实现蓝牙之间的通信,下面是Demo的效果图
(一)服务端
实现思路:
1、拿到本地蓝牙设备。
2、蓝牙之间的通讯需要一个唯一识别UUID来匹配正确的设备,使用UUID获取蓝牙的通讯Socket。
3、开启获取数据的线程
public class MainActivity extends AppCompatActivity implements View.OnClickListener { BluetoothSocket BTSocket; BluetoothAdapter BTAdapter; Button bt_start; TextView tv_msg; StringBuilder sb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_start = (Button) findViewById(R.id.bt_start); tv_msg = (TextView) findViewById(R.id.tv_msg); bt_start.setOnClickListener(this); sb = new StringBuilder(); show("服务端:检查BT"); checkBT(this); } /** * 检查蓝牙 */ public void checkBT(Context context) { BTAdapter = BluetoothAdapter.getDefaultAdapter(); if (BTAdapter != null) { if (!BTAdapter.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); // 设置蓝牙可见性,最多300秒 intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); context.startActivity(intent); } } else { show("本地设备驱动异常!"); } } /** * UI文本输出 * * @param msg */ public void show(String msg) { sb.append(msg + "\n"); runOnUiThread(new Runnable() { @Override public void run() { tv_msg.setText(sb.toString()); } }); } @Override public void onClick(View v) { //开启服务器 ServerThread startServerThread = new ServerThread(); startServerThread.start(); } /** * 开启服务器 */ private class ServerThread extends Thread { public void run() { try { BluetoothServerSocket mserverSocket = BTAdapter.listenUsingRfcommWithServiceRecord("btspp", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); show("服务端:等待连接"); BTSocket = mserverSocket.accept(); show("服务端:连接成功"); readThread mreadThread = new readThread(); mreadThread.start(); show("服务端:启动接受数据"); } catch (IOException e) { e.printStackTrace(); } } } /** * 读取数据 */ private class readThread extends Thread { public void run() { byte[] buffer = new byte[1024]; int bytes; InputStream mmInStream = null; try { mmInStream = BTSocket.getInputStream(); show("服务端:获得输入流"); } catch (IOException e1) { e1.printStackTrace(); } while (true) { try { if ((bytes = mmInStream.read(buffer)) > 0) { byte[] buf_data = new byte[bytes]; for (int i = 0; i < bytes; i++) { buf_data[i] = buffer[i]; } String s = new String(buf_data); show("服务端:读取数据了~~" + s); } } catch (IOException e) { try { mmInStream.close(); } catch (IOException e1) { e1.printStackTrace(); } break; } } } } }
(二)客户端
实现思路:
1、检查是否开启蓝牙。
2、注册一系列蓝牙的广播。
3、由于蓝牙每经过一个阶段都会发送一个广播,根据广播来实现对应的方法。
4、蓝牙配对->蓝牙连接->发送消息(UUID必须相同)
其实客户端的操作就是上面那张思路图,根据里面的步骤进行就可以完成
① 检查蓝牙
/** * 检查蓝牙 */ public void checkBT(Context context) { BTAdapter = BluetoothAdapter.getDefaultAdapter(); if (BTAdapter != null) { if (!BTAdapter.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); // 设置蓝牙可见性,最多300秒 intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); context.startActivity(intent); } } else { show("本地设备驱动异常!"); } }
/** * 注册广播 */ public void registerBTReceiver() { // 设置广播信息过滤 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); // 注册广播接收器,接收并处理搜索结果 registerReceiver(BTReceive, intentFilter); }
BTAdapter.startDiscovery();
/** * 广播接收者 */ private BroadcastReceiver BTReceive = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //打印Action,调试使用 show(action); //找到设备通知 ACTION_FOUND,设备已配对通知 ACTION_BOND_STATE_CHANGED if (BluetoothDevice.ACTION_FOUND.equals(action)) { device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); show("客户端:找到的BT名:" + device.getName()); // 如果查找到的设备符合,添加到UI上 addBT(); } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { // 获取蓝牙设备的连接状态 int connectState = device.getBondState(); // 已配对 if (connectState == BluetoothDevice.BOND_BONDED) { try { show("客户端:开始连接:"); clientThread clientConnectThread = new clientThread(); clientConnectThread.start(); } catch (Exception e) { e.printStackTrace(); } } } } }; /** * 添加找到的BT */ private void addBT() { Button bt = new Button(MainActivity.this); bt.setTag(device.getName()); bt.setText(device.getName()); ly_device.addView(bt); //处理选中BT设备,进行绑定 bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { bondBT((String) v.getTag()); } }); } /** * 绑定蓝牙 * * @param deviceName */ private void bondBT(String deviceName) { if (device.getName().equalsIgnoreCase(deviceName)) { show("客户端:配对蓝牙开始"); // 搜索蓝牙设备的过程占用资源比较多,一旦找到需要连接的设备后需要及时关闭搜索 BTAdapter.cancelDiscovery(); // 获取蓝牙设备的连接状态 int connectState = device.getBondState(); switch (connectState) { // 未配对 case BluetoothDevice.BOND_NONE: show("客户端:开始配对"); try { Method createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } break; // 已配对 case BluetoothDevice.BOND_BONDED: try { show("客户端:开始连接:"); clientThread clientConnectThread = new clientThread(); clientConnectThread.start(); } catch (Exception e) { e.printStackTrace(); } break; } } }
/** * 开启客户端 */ private class clientThread extends Thread { public void run() { try { //创建一个Socket连接:只需要服务器在注册时的UUID号 BTSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); //连接 show("客户端:开始连接..."); BTSocket.connect(); show("客户端:连接成功"); //启动接受数据 show("客户端:启动接受数据"); readThread mreadThread = new readThread(); mreadThread.start(); } catch (IOException e) { show("客户端:连接服务端异常!断开连接重新试一试"); e.printStackTrace(); } } }
/** * 读取数据 */ private class readThread extends Thread { public void run() { byte[] buffer = new byte[1024]; int bytes; InputStream is = null; try { is = BTSocket.getInputStream(); show("客户端:获得输入流"); } catch (IOException e1) { e1.printStackTrace(); } while (true) { try { if ((bytes = is.read(buffer)) > 0) { byte[] buf_data = new byte[bytes]; for (int i = 0; i < bytes; i++) { buf_data[i] = buffer[i]; } String s = new String(buf_data); show("客户端:读取数据了" + s); } } catch (IOException e) { try { is.close(); } catch (IOException e1) { e1.printStackTrace(); } break; } } } }
/** * 发送数据 */ public void sendMessage() { if (BTSocket == null) { Toast.makeText(this, "没有连接", Toast.LENGTH_SHORT).show(); return; } try { OutputStream os = BTSocket.getOutputStream(); os.write("我爱你dahsid132456@#%¥*".getBytes()); os.flush(); show("客户端:发送信息成功"); } catch (IOException e) { e.printStackTrace(); } }
蓝牙2.0比较简单,大家可以通过源码进行理解
源码下载:工具是Android Studio2.1 (建议使用Import Project导入)