做者:BruceZhangandroid
出处:http://blog.csdn.net/dlutbrucezhang/article/details/8955104web
一般状况下,咱们对蓝牙的操做主要有:开启和关闭蓝牙、搜索周边设备、能被周边设备所发现、获取配对设备、蓝牙设备间的数据传输。编程
蓝牙设备主要分为两部分,一部分为本地设备,另外一部分为远程设备。服务器
它所包含的方法和BluetoothAdapter同样,再也不累述。网络
// 获取本地的蓝牙适配器实例 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if(adapter!=null) { if(!adapter.isEnabled()) { //经过这个方法来请求打开咱们的蓝牙设备 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(intent); } } else { System.out.println("本地设备驱动异常!"); }
对于Android查找发现蓝牙设备使用BluetoothAdapter类的startDiscovery()方法就能够执行一个异步方式获取周边的蓝牙设备,由于是一个异步的方法因此咱们不须要考虑线程被阻塞问题,整个过程大约须要12秒时间,这时咱们能够注册一个 BroadcastReceiver 对象来接收查找到的蓝牙设备信息,咱们经过Filter来过滤ACTION_FOUND这个 Intent动做以获取每一个远程设备的详细信息,经过Intent字段EXTRA_DEVICE 和 EXTRA_CLASS能够得到包含了每一个BluetoothDevice 对象和对象的该设备类型 BluetoothClass。多线程
实现一个本身的BroadCastReceiver类,并注册这个类。app
private class BluetoothReciever extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); System.out.println(device.getAddress()); } } }
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND); bluetoothReceive = new BluetoothReciever(); registerReceiver(bluetoothReceive, intentFilter);
由于在注册一个Receiver后,程序并不知道该什么时候去回收它,因此须要咱们本身重写Activity类的onDestroy()方法。异步
protected void onDestroy() { // TODO Auto-generated method stub unregisterReceiver(bluetoothReceive); super.onDestroy(); }
若是须要用户确认操做,不须要获取底层蓝牙服务实例,能够经过一个Intent来传递ACTION_REQUEST_DISCOVERABLE参数, 这里经过startActivity来请求开启。socket
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //50这个参数表明的是蓝牙设备能在多少秒内被发现 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50); startActivity(discoverableIntent);
配对操做呢,通常都是发现设备后,由咱们人工来进行选择后系统自动去配对。咱们能够经过下面的方法来得到配对的设备:ide
//经过getBondedDevices方法来获取已经与本设备配对的设备 Set<BluetoothDevice> device= adapter.getBondedDevices(); if(device.size()>0) { for(Iterator iterator=device.iterator();iterator.hasNext();) { BluetoothDevice bluetoothDevice=(BluetoothDevice)iterator.next(); System.out.println(bluetoothDevice.getAddress()); } }
在看过前面的启动、发现/搜索、配对这些操做后,下面来讲说数据传输的问题。
在Android系统中,蓝牙设备间的数据传输问题和咱们在PC上的网络编程颇为相似,有一端做为Server端监听Client端的链接请求,在两者创建了链接后,就可使用普通的数据传输方式进行数据交换操做了。在这个过程当中,我须要使用到BluetoothServerSocket和BluetoothSocket两个类来创建Server端和Client端,还须要使用到一些关于流(Stream)的知识。
能够看到,Accept方法是一个阻塞方法,因此在进行开发的时候,通常都须要用到多线程的知识。JAVA的多线程知识,能够在JAVA的JDK帮助文档中查看,就单纯的应用来讲仍是比较简单的。
在了解了这两个类后,能够着手来创建咱们本身的Server端和Client端了。
若是一个设备须要和两个或多个设备链接时,就须要做为一个server来传输,服务器端套接字在接受(accepted) 一个客户发来的BluetoothSocket链接请求时做出相应的响应。服务器socket将监听进入的链接请求,一旦链接被接受,将产生一个BluetoothSocket。
使用BluetoothAdapter类的listenUsingRfcommWithServiceRecord方法来新建一个ServerSocket。在listenUsingRfcommWithServiceRecord中有一个参数叫作UUID,UUID(Universally Unique Identifier)是一个128位的字符串ID,被用于惟一标识咱们的蓝牙服务。你可使用web上的任何一款UUID产生器为你的程序获取一个UUID,而后使用fromString(String)初始化一个UUID。
使用ServerSocket实例的accept方法进行监听,当监听到带有咱们初始化的UUID参数的链接请求后做出响应,链接成功后返回一个BluetoothSocket对象。链接完成后,调用close方法关闭该Socket监听。
// Bluetooth的ServerSocket包装类 class BluetoothServer { public BluetoothServer() throws IOException { } // 要创建一个ServerSocket对象,须要使用adapter.listenUsingRfcommWithServiceRecord方法 // UUID能够在网上去申请 private BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myServerSocket", UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04")); BluetoothSocket socket = serverSocket.accept(); void m() throws IOException { if (socket != null) { InputStream inputStream = socket.getInputStream(); int read = -1; final byte[] bytes = new byte[1024]; for (; (read = inputStream.read(bytes)) > -1;) { final int count = read; Thread _start = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { if (i > 0) { sb.append(' '); } String _s = Integer.toHexString(bytes[i] & 0xFF); if (_s.length() < 2) { sb.append('0'); } sb.append(_s); } System.out.println(sb.toString()); } }); _start.start(); } } } }
建立一个Client端,首先须要咱们使用BluetoothDevice的实例的createRfcommSocketToServiceRecord方法来建立一个BluetoothSocket实例。在建立的时候,须要给createRfcommSocketToServiceRecord方法传入咱们服务端的UUID值。而后使用BluetoothSocket实例的Connect方法对Server端进行链接请求,当链接成功后,Client端和Server端的传输通道就被打开。最后在链接完成后使用该实例的close方法来关闭这个链接。
class BluetoothClient { BluetoothDevice device = null; //经过构造函数来传入一个BluetoothDevice实例 public BluetoothClient(BluetoothDevice device) { this.device = device; } BluetoothSocket socket = null; void connetServer() throws IOException { Thread _clientThread = new Thread(new Runnable() { public void run() { try { //经过BluetoothDevice实例的createRfcommSocketToServiceRecord方法能够返回一个带有UUID的BluetoothSocket实例 socket = device.createRfcommSocketToServiceRecord(UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04")); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { socket.connect(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (socket != null) { try { socket.close(); } catch (Exception e) { // TODO: handle exception } } } }); _clientThread.start(); }
getInputStream()——得到一个可读的流,该流在链接不成功的状况下依旧能够得到,可是对其操做的话就会报IOException的异常。须要从外部获取的数据都从该流中获取。
getOutputStrem()——得到一个可写的流,该流在链接不成功的状况下依旧能够得到,可是对其操做的话就会报IOException的异常。须要往外部传输的数据均可以写到该流中传输出去。
数据传输的大体流程以下:
还要补充一点,因为蓝牙设备是系统设备,因此须要有相应的权限支持。在AndroidManifest.xml文件中添加上权限。
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>