Android蓝牙串口连接

转自:http://blog.csdn.NET/jason0539/article/details/17782035

最近在做蓝牙开锁的小项目,手机去连接单片机总是出现问题,和手机的连接也不稳定,看了不少蓝牙方面的文档,做了个关于蓝牙连接的小结。

在做Android蓝牙串口连接的时候一般会使用

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. BluetoothSocket tmp = null;  
  2. // Get a BluetoothSocket for a connection with the  
  3. // given BluetoothDevice  
  4. try {  
  5.          tmp = device.createRfcommSocketToServiceRecord(MY_UUID);  
  6. catch (IOException e) {  
  7.     Log.e(TAG, "create() failed", e);  
  8. }  

然后是tmp赋给BluetoothSocket,接着调用connect方法进行蓝牙设备的连接。

可是 BluetoothSocket 的connect方法本身就会报很多异常错误。

以下根据对蓝牙开发的一点研究可通过以下方法解决:

方法1.先进行蓝牙自动配对,配对成功,通过UUID获得BluetoothSocket,然后执行connect()方法。

方法2.通过UUID获得BluetoothSocket,然后先根据mDevice.getBondState()进行判断是否需要配对,最后执行connnect()方法。

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class ConnectThread extends Thread {  
  2.     String macAddress = "";  
  3.   
  4.     public ConnectThread(String mac) {  
  5.         macAddress = mac;  
  6.     }  
  7.   
  8.     public void run() {  
  9.         connecting = true;  
  10.         connected = false;  
  11.         if(mBluetoothAdapter == null){  
  12.             mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  13.         }  
  14.         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);  
  15.         mBluetoothAdapter.cancelDiscovery();  
  16.         try {  
  17.             socket = mBluetoothDevice.createRfcommSocketToServiceRecord(uuid);  
  18.               
  19.         } catch (IOException e) {  
  20.             // TODO Auto-generated catch block  
  21.             //e.printStackTrace();  
  22.             Log.e(TAG, "Socket", e);  
  23.         }               
  24.         //adapter.cancelDiscovery();  
  25.         while (!connected && connetTime <= 10) {                  
  26.             connectDevice();  
  27.         }  
  28.         // 重置ConnectThread   
  29.         //synchronized (BluetoothService.this) {  
  30.            //ConnectThread = null;  
  31.         //}  
  32.     }  
  33.   
  34.     public void cancel() {  
  35.         try {  
  36.             socket.close();  
  37.             socket = null;  
  38.         } catch (Exception e) {  
  39.             e.printStackTrace();  
  40.         } finally {  
  41.             connecting = false;  
  42.         }  
  43.     }  
  44. }  

接下来是调用的连接设备方法connectDevice():

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected void connectDevice() {    
  2.         try {    
  3.             // 连接建立之前的先配对    
  4.             if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {    
  5.                 Method creMethod = BluetoothDevice.class    
  6.                         .getMethod("createBond");    
  7.                 Log.e("TAG""开始配对");    
  8.                 creMethod.invoke(mBluetoothDevice);    
  9.             } else {    
  10.             }    
  11.         } catch (Exception e) {    
  12.             // TODO: handle exception    
  13.             //DisplayMessage("无法配对!");    
  14.             e.printStackTrace();    
  15.         }    
  16.         mBluetoothAdapter.cancelDiscovery();    
  17.         try {    
  18.             socket.connect();    
  19.             //DisplayMessage("连接成功!");   
  20.             //connetTime++;  
  21.             connected = true;  
  22.         } catch (IOException e) {    
  23.             // TODO: handle exception    
  24.             //DisplayMessage("连接失败!");  
  25.             connetTime++;  
  26.             connected = false;  
  27.             try {    
  28.                 socket.close();  
  29.                 socket = null;  
  30.             } catch (IOException e2) {    
  31.                 // TODO: handle exception    
  32.                 Log.e(TAG, "Cannot close connection when connection failed");    
  33.             }    
  34.         } finally {  
  35.             connecting = false;  
  36.         }    
  37.     }  


 

方法3.利用反射通过端口获得BluetoothSocket,然后执行connect()方法。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class ConnectThread extends Thread {  
  2.     String macAddress = "";  
  3.   
  4.     public ConnectThread(String mac) {  
  5.         macAddress = mac;  
  6.     }  
  7.   
  8.     public void run() {  
  9.         connecting = true;  
  10.         connected = false;  
  11.         if(mBluetoothAdapter == null){  
  12.             mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  13.         }  
  14.         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);  
  15.         mBluetoothAdapter.cancelDiscovery();  
  16.         initSocket();                           
  17.         //adapter.cancelDiscovery();  
  18.         while (!connected && connetTime <= 10) {  
  19.             try {  
  20.                 socket.connect();  
  21.                 connected = true;  
  22.             } catch (IOException e1) {  
  23.                 connetTime++;  
  24.                 connected = false;  
  25.                 // 关闭 socket  
  26.                 try {  
  27.                     socket.close();  
  28.                     socket = null;  
  29.                 } catch (IOException e2) {  
  30.                     //TODO: handle exception    
  31.                     Log.e(TAG, "Socket", e2);  
  32.                 }  
  33.             } finally {  
  34.                 connecting = false;  
  35.             }  
  36.             //connectDevice();  
  37.         }  
  38.         // 重置ConnectThread   
  39.         //synchronized (BluetoothService.this) {  
  40.            //ConnectThread = null;  
  41.         //}  
  42.     }  
  43.   
  44.     public void cancel() {  
  45.         try {  
  46.             socket.close();  
  47.             socket = null;  
  48.         } catch (Exception e) {  
  49.             e.printStackTrace();  
  50.         } finally {  
  51.             connecting = false;  
  52.         }  
  53.     }  
  54. }  

接下来是初始化并得到BluetoothSocket的方法

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * 取得BluetoothSocket 
  3.      */  
  4.     private void initSocket() {  
  5.         BluetoothSocket temp = null;  
  6.         try {              
  7.             Method m = mBluetoothDevice.getClass().getMethod(  
  8.                     "createRfcommSocket"new Class[] { int.class });  
  9.             temp = (BluetoothSocket) m.invoke(mBluetoothDevice, 1);//这里端口为1              
  10.         } catch (SecurityException e) {  
  11.             e.printStackTrace();  
  12.         } catch (NoSuchMethodException e) {  
  13.             e.printStackTrace();  
  14.         } catch (IllegalArgumentException e) {  
  15.             e.printStackTrace();  
  16.         } catch (IllegalAccessException e) {  
  17.             e.printStackTrace();  
  18.         } catch (InvocationTargetException e) {  
  19.             e.printStackTrace();  
  20.         }  
  21.         socket = temp;  
  22.     }  

 

要点:1.蓝牙配对和连接是两回事,不可混为一谈。

   2.蓝牙串口连接可通过端口 (1-30)和UUID两种方法进行操作。

   3.通过UUID进行蓝牙连接最好先进行配对操作。


说明:在连接蓝牙过程中总是不稳定,先配对后,情况明显好转。

另外装载作者的另外一个补充,详细过程还没有试验

http://www.aiseminar.cn/bbs/forum.PHP?mod=viewthread&tid=2369&fromuid=3

如前文“第二个Activity中onStop设置Service为第一个Activity的handler为什么不起作用?”所描述的问题,开始以为是handle出了问题:“蓝牙使用UUID进行连接,第一设备之间可以正常连接。而socket关闭后,后续连接都会出现service discovery failed错误”。


后来查阅资料发现,这是Android蓝牙连接经常遇到的问题。有人怀疑是Android系统的bug,而且提出使用反射方法解决此问题。经过AIS蓝牙对讲机的使用测试结果表明:使用Reflect方法进行蓝牙连接,可以重复连接任意多次,不会再出现上述问题。


所谓使用反射方式,就是通过Java的反射机制,取出Bluetooth的监听和创建连接socket的方法,使用反射的方法进行操作,而再使用listenUsingRfcommWithServiceRecord和createRfcommSocketToServiceRecord这样的问题函数。实现时,同样如同这样连个函数,需要将反射操作配对使用。如下:

替换listenUsingRfcommWithServiceRecord的反射操作:

  1.                 public BluetoothServerSocket listenUsingRfcommWithReflect()
  2.                 {
  3.                         BluetoothServerSocket tmp = null;
  4.                         Method m;
  5.                         try 
  6.                         {
  7.                                 m = mBTAdapter.getClass().getMethod("listenUsingRfcommOn", new Class[] { int.class });
  8.                                 try
  9.                                 {
  10.                                         tmp = (BluetoothServerSocket) m.invoke(mBTAdapter, 1); // 1为监听端口号
  11.                                 } 
  12.                                 catch (IllegalAccessException e) {
  13.                                         // TODO Auto-generated catch block
  14.                                         e.printStackTrace();
  15.                                 } 
  16.                                 catch (IllegalArgumentException e) {
  17.                                         // TODO Auto-generated catch block
  18.                                         e.printStackTrace();
  19.                                 } 
  20.                                 catch (InvocationTargetException e) {
  21.                                         // TODO Auto-generated catch block
  22.                                         e.printStackTrace();
  23.                                 }
  24.                         } 
  25.                         catch (NoSuchMethodException e) {
  26.                                 // TODO Auto-generated catch block
  27.                                 e.printStackTrace();
  28.                         }
  29.                         
  30.                         return tmp;
  31.                 }
复制代码
替换createRfcommSocketToServiceRecord的反射操作:
  1.                 public BluetoothSocket createRFcommSocketWithReflect(BluetoothDevice device)
  2.                 {
  3.                         BluetoothSocket tmp = null;
  4.                         Method reflectMethod = null;
  5.                         try 
  6.                         {
  7.                                 reflectMethod = mRemoteDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
  8.                                 try 
  9.                                 {
  10.                                         tmp = (BluetoothSocket)reflectMethod.invoke(device, Integer.valueOf(1)); // 1为监听端口号
  11.                                 } 
  12.                                 catch (IllegalAccessException e) {
  13.                                         // TODO Auto-generated catch block
  14.                                         e.printStackTrace();
  15.                                 } 
  16.                                 catch (IllegalArgumentException e) {
  17.                                         // TODO Auto-generated catch block
  18.                                         e.printStackTrace();
  19.                                 } 
  20.                                 catch (InvocationTargetException e) {
  21.                                         // TODO Auto-generated catch block
  22.                                         e.printStackTrace();
  23.                                 }
  24.                         }
  25.                         catch (NoSuchMethodException e) 
  26.                         {
  27.                         }
  28.                         
  29.                         return tmp;
  30.                 }
复制代码
上面函数中的常量1为蓝牙端口号,据说:蓝牙串口连接可通过端口号:1-30。

Referred to:
[1] 第二个Activity中onStop设置Service为第一个Activity的handler为什么不起作用? http://www.aiseminar.cn/bbs/forum.php?mod=viewthread&tid=2314&fromuid=3
[2] java.io.IOException: Service discovery failed.  http://stackoverflow.com/questions/17812222/java-io-ioexception-service-discovery-failed
[3] Android listen for connections without UUID.  http://stackoverflow.com/questions/13362774/android-listen-for-connections-without-uuid

[4] android开发之蓝牙配对连接的方法. http://blog.csdn.Net/jason0539/article/details/17782035


另外两篇关于蓝牙的文章:

蓝牙开发:http://www.cnblogs.com/wenjiang/p/3200138.html


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值