Android蓝牙开发浅析

少年恃险若平地,独倚长剑凌清秋。这篇文章主要讲述Android蓝牙开发浅析相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/geekdonie/article/details/7487761
由于近期正在开发一个通过蓝牙进行数据传递的模块,在参考了有关资料,并详细阅读了Android的官方文档后,总结了Android中蓝牙模块的使用。
【更新】之前承诺的蓝牙通讯模块的源码已经放出,详情请点击一下链接
http://blog.csdn.net/gd920129/article/details/7552110

 
1. 使用蓝牙的响应权限
 
[html]  view plain  copy    

Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. < uses-permission  android:name="android.permission.BLUETOOTH"  />    
  2. < uses-permission  android:name="android.permission.BLUETOOTH_ADMIN"  />    
 


2. 配置本机蓝牙模块
在这里首先要了解对蓝牙操作一个核心类BluetoothAdapter
 
[java]  view plain  copy    
Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. BluetoothAdapter  adapter  =  BluetoothAdapter.getDefaultAdapter();    
  2. //直接打开系统的蓝牙设置面板   
  3. Intent  intent  =  new  Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    
  4. startActivityForResult(intent,  0x1);    
  5. //直接打开蓝牙   
  6. adapter.enable();    
  7. //关闭蓝牙   
  8. adapter.disable();    
  9. //打开本机的蓝牙发现功能(默认打开120秒,可以将时间最多延长至300秒)   
  10. Intent  discoveryIntent  =  new  Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);    
  11. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,  300); //设置持续时间(最多300秒)   
 
 
3.搜索蓝牙设备
使用BluetoothAdapter的startDiscovery()方法来搜索蓝牙设备
startDiscovery()方法是一个异步方法,调用后会立即返回。该方法会进行对其他蓝牙设备的搜索,该过程会持续12秒。该方法调用后,搜索过程实际上是在一个System Service中进行的,所以可以调用cancelDiscovery()方法来停止搜索(该方法可以在未执行discovery请求时调用)。
请求Discovery后,系统开始搜索蓝牙设备,在这个过程中,系统会发送以下三个广播:
ACTION_DISCOVERY_START:开始搜索
ACTION_DISCOVERY_FINISHED:搜索结束
ACTION_FOUND:找到设备,这个Intent中包含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,分别包含BluetooDevice和BluetoothClass。
我们可以自己注册相应的BroadcastReceiver来接收响应的广播,以便实现某些功能
 
[java]  view plain  copy    
Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. //  创建一个接收ACTION_FOUND广播的BroadcastReceiver   
  2. private  final  BroadcastReceiver  mReceiver  =  new  BroadcastReceiver()  {   
  3.         public  void  onReceive(Context  context,  Intent  intent)  {   
  4.                 String  action  =  intent.getAction();    
  5.                 //  发现设备   
  6.                 if  (BluetoothDevice.ACTION_FOUND.equals(action))  {   
  7.                         //  从Intent中获取设备对象   
  8.                         BluetoothDevice  device  =  intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);    
  9.                         //  将设备名称和地址放入array  adapter,以便在ListView中显示   
  10.                         mArrayAdapter.add(device.getName()  +  "\n"  +  device.getAddress());    
  11.                 }   
  12.         }   
  13. };    
  14. //  注册BroadcastReceiver   
  15. IntentFilter  filter  =  new  IntentFilter(BluetoothDevice.ACTION_FOUND);    
  16. registerReceiver(mReceiver,  filter);   //  不要忘了之后解除绑定   
 
 
4. 蓝牙Socket通信
如果打算建议两个蓝牙设备之间的连接,则必须实现服务器端与客户端的机制。当两个设备在同一个RFCOMM channel下分别拥有一个连接的BluetoothSocket,这两个设备才可以说是建立了连接。
服务器设备与客户端设备获取BluetoothSocket的途径是不同的。服务器设备是通过accepted一个incoming connection来获取的,而客户端设备则是通过打开一个到服务器的RFCOMM channel来获取的。
 
服务器端的实现
通过调用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法来获取BluetoothServerSocket(UUID用于客户端与服务器端之间的配对)
调用BluetoothServerSocket的accept()方法监听连接请求,如果收到请求,则返回一个BluetoothSocket实例(此方法为block方法,应置于新线程中)
如果不想在accept其他的连接,则调用BluetoothServerSocket的close()方法释放资源(调用该方法后,之前获得的BluetoothSocket实例并没有close。但由于RFCOMM一个时刻只允许在一条channel中有一个连接,则一般在accept一个连接后,便close掉BluetoothServerSocket)
 
[java]  view plain  copy    
Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. private  class  AcceptThread  extends  Thread  {   
  2.         private  final  BluetoothServerSocket  mmServerSocket;    
  3.    
  4.         public  AcceptThread()  {   
  5.                 //  Use  a  temporary  object  that  is  later  assigned  to  mmServerSocket,   
  6.                 //  because  mmServerSocket  is  final   
  7.                 BluetoothServerSocket  tmp  =  null;    
  8.                 try  {   
  9.                         //  MY_UUID  is  the  app‘s  UUID  string,  also  used  by  the  client  code   
  10.                         tmp  =  mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME,  MY_UUID);    
  11.                 }  catch  (IOException  e)  {  }   
  12.                 mmServerSocket  =  tmp;    
  13.         }   
  14.    
  15.         public  void  run()  {   
  16.                 BluetoothSocket  socket  =  null;    
  17.                 //  Keep  listening  until  exception  occurs  or  a  socket  is  returned   
  18.                 while  (true)  {   
  19.                         try  {   
  20.                                 socket  =  mmServerSocket.accept();    
  21.                         }  catch  (IOException  e)  {   
  22.                                 break;    
  23.                         }   
  24.                         //  If  a  connection  was  accepted   
  25.                         if  (socket  !=  null)  {   
  26.                                 //  Do  work  to  manage  the  connection  (in  a  separate  thread)   
  27.                                 manageConnectedSocket(socket);    
  28.                                 mmServerSocket.close();    
  29.                                 break;    
  30.                         }   
  31.                 }   
  32.         }   
  33.    
  34.         /**  Will  cancel  the  listening  socket,  and  cause  the  thread  to  finish  */   
  35.         public  void  cancel()  {   
  36.                 try  {   
  37.                         mmServerSocket.close();    
  38.                 }  catch  (IOException  e)  {  }   
  39.         }   
  40. }   
 
 

客户端的实现
通过搜索得到服务器端的BluetoothService
调用BluetoothService的listenUsingRfcommWithServiceRecord(String, UUID)方法获取BluetoothSocket(该UUID应该同于服务器端的UUID)
调用BluetoothSocket的connect()方法(该方法为block方法),如果UUID同服务器端的UUID匹配,并且连接被服务器端accept,则connect()方法返回
注意:在调用connect()方法之前,应当确定当前没有搜索设备,否则连接会变得非常慢并且容易失败
 
[java]  view plain  copy    
Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. private  class  ConnectThread  extends  Thread  {   
  2.         private  final  BluetoothSocket  mmSocket;    
  3.         private  final  BluetoothDevice  mmDevice;    
  4.    
  5.         public  ConnectThread(BluetoothDevice  device)  {   
  6.                 //  Use  a  temporary  object  that  is  later  assigned  to  mmSocket,   
  7.                 //  because  mmSocket  is  final   
  8.                 BluetoothSocket  tmp  =  null;    
  9.                 mmDevice  =  device;    
  10.    
  11.                 //  Get  a  BluetoothSocket  to  connect  with  the  given  BluetoothDevice   
  12.                 try  {   
  13.                         //  MY_UUID  is  the  app‘s  UUID  string,  also  used  by  the  server  code   
  14.                         tmp  =  device.createRfcommSocketToServiceRecord(MY_UUID);    
  15.                 }  catch  (IOException  e)  {  }   
  16.                 mmSocket  =  tmp;    
  17.         }   
  18.    
  19.         public  void  run()  {   
  20.                 //  Cancel  discovery  because  it  will  slow  down  the  connection   
  21.                 mBluetoothAdapter.cancelDiscovery();    
  22.    
  23.                 try  {   
  24.                         //  Connect  the  device  through  the  socket.  This  will  block   
  25.                         //  until  it  succeeds  or  throws  an  exception   
  26.                         mmSocket.connect();    
  27.                 }  catch  (IOException  connectException)  {   
  28.                         //  Unable  to  connect;   close  the  socket  and  get  out   
  29.                         try  {   
  30.                                 mmSocket.close();    
  31.                         }  catch  (IOException  closeException)  {  }   
  32.                         return;    
  33.                 }   
  34.    
  35.                 //  Do  work  to  manage  the  connection  (in  a  separate  thread)   
  36.                 manageConnectedSocket(mmSocket);    
  37.         }   
  38.    
  39.         /**  Will  cancel  an  in-progress  connection,  and  close  the  socket  */   
  40.         public  void  cancel()  {   
  41.                 try  {   
  42.                         mmSocket.close();    
  43.                 }  catch  (IOException  e)  {  }   
  44.         }   
  45. }   
 
 

连接管理(数据通信)
分别通过BluetoothSocket的getInputStream()和getOutputStream()方法获取InputStream和OutputStream
使用read(bytes[])和write(bytes[])方法分别进行读写操作
注意:read(bytes[])方法会一直block,知道从流中读取到信息,而write(bytes[])方法并不是经常的block(比如在另一设备没有及时read或者中间缓冲区已满的情况下,write方法会block)
 
[java]  view plain  copy    
Android蓝牙开发浅析

文章图片
Android蓝牙开发浅析

文章图片
  1. private  class  ConnectedThread  extends  Thread  {   
  2.         private  final  BluetoothSocket  mmSocket;    
  3.         private  final  InputStream  mmInStream;    
  4.         private  final  OutputStream  mmOutStream;    
  5.    
  6.         public  ConnectedThread(BluetoothSocket  socket)  {   
  7.                 mmSocket  =  socket;    
  8.                 InputStream  tmpIn  =  null;    
  9.                 OutputStream  tmpOut  =  null;    
  10.    
  11.                 //  Get  the  input  and  output  streams,  using  temp  objects  because   
  12.                 //  member  streams  are  final   
  13.                 try  {   
  14.                         tmpIn  =  socket.getInputStream();    
  15.                         tmpOut  =  socket.getOutputStream();    
  16.                 }  catch  (IOException  e)  {  }   
  17.    
  18.                 mmInStream  =  tmpIn;    
  19.                 mmOutStream  =  tmpOut;    
  20.         }   
  21.    
  22.         public  void  run()  {   
  23.                 byte[]  buffer  =  new  byte[1024];     //  buffer  store  for  the  stream   
  24.                 int  bytes;   //  bytes  returned  from  read()   
  25.    
  26.                 //  Keep  listening  to  the  InputStream  until  an  exception  occurs   
  27.                 while  (true)  {   
  28.                         try  {   
  29.                                 //  Read  from  the  InputStream   
  30.                                 bytes  =  mmInStream.read(buffer);    
  31.                                 //  Send  the  obtained  bytes  to  the  UI  Activity   
  32.                                 mHandler.obtainMessage(MESSAGE_READ,  bytes,  -1,  buffer)   
  33.                                                 .sendToTarget();    
  34.                         }  catch  (IOException  e)  {   
  35.                                 break;    
  36.                         }   
  37.                 }   
  38.         }   
  39.    
  40.         /*  Call  this  from  the  main  Activity  to  send  data  to  the  remote  device  */   
  41.         public  void  write(byte[]  bytes)  {   
  42.                 try  {   
  43.                         mmOutStream.write(bytes);    
  44.                 }  catch  (IOException  e)  {  }   
  45.         }   
  46.    
  47.         /*  Call  this  from  the  main  Activity  to  shutdown  the  connection  */   
  48.         public  void  cancel()  {   
  49.                 try  {   
  50.                         mmSocket.close();    
  51.                 }  catch  (IOException  e)  {  }   
  52.         }   
  53. }   



 
【Android蓝牙开发浅析】引用资料:Android官方SDK、《Android/OPhone完全开发讲义》

    推荐阅读