Demo

首先,直接给Demo,对于只想使用的朋友,直接下载使用即可。Demo其实也是从网上爬来的,之后做了各种调试和修改。

原有Demo代码下载,可见地址。

修改后Demo效果如下。效果不太清晰,见谅。

(1)PC端

(2)Android端

细节实现

Android端

android端做为客户端要与PC通讯,需要完成以下几步。

添加蓝牙权限

    <uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

注册广播接收器

个人认为该步骤可选。但最好存在。
原因在于,虽然蓝牙适配器可以获取周围蓝牙设备的列表,但对于周围蓝牙设备的扫描比较耗时。
返回蓝牙设备列表时,可能仍处于搜索过程中。
当扫描完成时,广播接收器将受到action为ACTION_DISCOVERY_FINISHED的广播。此时,获取设备列表,将比较全面。

建议接收器监听,以下三个action。

    IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//发现设备intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描完毕intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//扫描结束registerReceiver(broadcastReceiver, intentFilter);

开启蓝牙

    if (!bluetoothAdapter.isEnabled()) {bluetoothAdapter.enable();}

开启适配器后,android将开始遍历周围可以被访问的蓝牙设备。该动作将触发广播。

当然,也可以通过触发bluetoothAdapter.startDiscovery()重新扫描。

选定目标蓝牙设备

由适配器获取设备列表,并根据PC的bluetooth MAC地址,选定目标蓝牙设备。SERVICE_ADDRESS为PC端蓝牙mac地址,格式为XX:XX:XX:XX:XX:XX

    Set<BluetoothDevice> mySet = bluetoothAdapter.getBondedDevices();for (BluetoothDevice device : mySet) {if (device.getAddress().equalsIgnoreCase(SERVICE_ADDRESS) ) {service = device;break;}}

创建RfcommSocket并建立连接

    private static final String serverUUID = "00001101-0000-1000-8000-00805F9B34FB"private BluetoothSocket bluetoothSocket;bluetoothSocket = service.createRfcommSocketToServiceRecord(UUID.fromString(serverUUID));bluetoothSocket.connect();

这里需要说明的有两点。
1.连接操作比较耗时,视具体设备不同。所以,需要将连接操作放到子线程中完成。

2.在Android端,需要使用UUID,完成与其他蓝牙设备的连接。关于UUID,之后小结会提到。

收发数据

收发数据也较为耗时,需要放在子线程实现。

    OutputStream outputStream;try {outputStream = bluetoothSocket.getOutputStream();outputStream.write("A message from android device".getBytes());showMessage("Successfully send message");} catch (IOException e) {showMessage(e.getMessage()+", during output");}InputStream inputStream;try {inputStream = bluetoothSocket.getInputStream();byte[] buffer = new byte[200];inputStream.read(buffer);showMessage("Concurrently receive message : " + new String(buffer));} catch (IOException e) {showMessage(e.getMessage()+", during get input");}

关闭RfcommSocket

bluetoothSocket.close();

PC端

设置PC蓝牙设备可见

LocalDevice.getLocalDevice().setDiscoverable(DiscoveryAgent.GIAC);

创建连接流监听器

private StreamConnectionNotifier streamConnectionNotifier;
streamConnectionNotifier = (StreamConnectionNotifier) Connector.open("btspp://localhost:" + SERVER_UUID.toString());

注意,此处使用的UUID,必须与android端的UUID一致。

开启监听

StreamConnection streamConnection = null;
streamConnection = streamConnectionNotifier.acceptAndOpen();

acceptAndOpen()方法调用后,将进入等待。

获取输入流和输出流

while (isListening) {if ((inputStream.available()) <= 0) {Thread.sleep(1000);}System.out.println("message is comming");outputStream.write("hello android BT".getBytes());inputStream.read(buffer);String message = new String(buffer);System.out.println("Receive message : " + message);if (message.contains("EXIT_APP")) {System.out.println("Listener closed");isListening = false;}
}

关闭连接

inputStream.close();
outputStream.close();
streamConnection.close();

问题

BUG

java.io.IOException: read failed, socket might closed or timeout, read ret: -1

在连接时,常会遇到该BUG。网上很多方法说,可以通过修改UUID的方式,来FIX该BUG。

但翻看createRfcommSocketToServiceRecord方法的注释,发现该UUID不能随便修改。

     * <p>Hint: If you are connecting to a Bluetooth serial board then try* using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.* However if you are connecting to an Android peer then please generate* your own unique UUID.

因此,若是采用串口通信,必须使用“00001101-0000-1000-8000-00805F9B34FB”。

造成连接失败的另一原因,可能是channel ID的问题。
在创建Socket时,createRfcommSocketToServiceRecord使用UUID作为唯一传参,而默认channel为-1。

网上建议,通过反射使用BluetoothDevice的隐藏public createRfcommSocket方法,利用传参指定的channel值,创建Socket。

channel的取值范围为1至30.

Demo中给出了工具方法。

    public BluetoothSocket cretateBluetoothSocketbyChannel(BluetoothDevice Device,int channel,boolean autoForward){BluetoothSocket socket=null;try {showMessage("Trying fallback on channel "+channel);socket =(BluetoothSocket) Device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(Device,channel);socket.connect();Log.d(TAG,"createRfcommSocket on channel "+channel);showMessage("Successfully connect");} catch (Exception e) {showMessage(e.getMessage());if(channel<30){if(autoForward){socket=cretateBluetoothSocketbyChannel(Device,channel+1,autoForward);}else {showMessage("Connect Failed");}}}return socket;}

另外,就该问题,吐槽一下适配器。适配器的性能也是参差不齐。此前摁着绿联的蓝牙适配器,试了3天。同样的代码,问题百出。后来转用奥视通(ost108),几分钟便过了。不管是添加设备时的认证过程的人性化设计,还是设备服务驱动的安装速度,天壤之别~

驱动

Demo在实现时,遇到找不到设备的情况。个人感觉是由于适配器所提供的驱动问题造成的。在卸载后,使用通用驱动可以解决该问题。

Bluecove版本

在64位OS下开发,需要使用Bluecove 64bit版本,本Demo使用为64bit。下载地址

参考文献

在开发过程中,以下文章给予了很多帮助,一并列下。

https://blog.csdn.net/tingfengzheshuo/article/details/45292201

http://royal2xiaose.iteye.com/blog/1420138

https://blog.csdn.net/old_me_mory/article/details/18962701

https://blog.csdn.net/peceoqicka/article/details/51979469(着重感谢)

结语

第一次涉及蓝牙项目,耗时较长,且深入不够,若有疏漏,还望提出。

基于蓝牙适配器的PC与Android端通讯相关推荐

  1. 基于Socket实现客户端与服务端通讯

    基于Socket实现客户端与服务端通讯 socket 概述 Socket,套接字就是两台主机之间逻辑连接的端点.TCP/IP协议是传输层协议,主要解决数据如何 在网络中传输,而HTTP是应用层协议,主 ...

  2. [转]仿91助手的PC与android手机通讯

    仿91助手的PC与android手机通讯 原文 知道91助手和豌豆莢吧? 说到这两个东西,最让人好奇的应该是就是和手机的交互了.我之前有研究过电脑和安卓的交互,基本功能已经走通了,在这里我想分享一下. ...

  3. php cannot bind port to socket,PHP基于socket实现客户端和服务端通讯功能

    本文主要介绍了PHP基于socket实现的简单客户端和服务端通讯功能,可实现服务端接收客户端发送的字符串进行翻转操作后返回客户端的功能,需要的朋友可以参考下 服务端: set_time_limit(0 ...

  4. 仿91助手的PC与android手机通讯(2) --- 检测是否是手机

    上一篇日志说了如何响应设备插入,但是设备有很多中,多媒体设备,鼠标键盘什么的都是,那如何判断是不是USB设备或者是手机插入呢? 这里就介绍一下我自己的研究结果,当然我没有去研究过苹果设备,但是按道理是 ...

  5. 仿91助手的PC与android手机通讯(4) --- 自动安装手机驱动

    上一节讲到检查驱动安装情况,那么如果遇到没安装手机驱动的话是没办法和手机进行通讯的(除非你是要直接把文件拷贝到手机目录下,好像txt,视频,音乐的话是不用考虑驱动都可以的,当然有驱动这几种文件的拷贝也 ...

  6. 仿91助手的PC与android手机通讯(5) --- 使用adb获取手机信息

    到这里,我知道的就差不多了.后面就是跟android手机的命令传递了.这些操作主要使用到android工具包---adb(android debug bridge).这个东西是google提供的,网上 ...

  7. 仿91助手的PC与android手机通讯(1) --- 检测设备插入

    知道91助手和豌豆莢吧? 说到这两个东西,最让人好奇的应该是就是和手机的交互了.我之前有研究过电脑和安卓的交互,基本功能已经走通了,在这里我想分享一下. 初初看这个问题觉得很简单,然后如果你有点计算机 ...

  8. ue4 如何让android与pc通讯,android端只显示umg,如何隐藏android的人物

    如何让android与pc通讯 让pc与Android端可以通讯,需要在项目中配置sdk与打包设置,然后再直接打包出来,点击就可以运行. 如何让android的事件在pc端也做响应呢? 其实要做的就是 ...

  9. 基于 Agora SDK 实现 Android 端的多人视频互动

    本系列教程将分为三期,分享基于 Agora SDK 在各系统平台应用中实现一对一视频通话.多人互动直播,以及结合跨平台技术进行开发.本期推送在 Android.iOS.Windows.Web.macO ...

最新文章

  1. 6名学生返校后被判定为密接,高校紧急通知!
  2. java的工厂类_深入理解Java的三种工厂模式
  3. matlab的index函数,写论文第九天:MATLAB之rsindex函数
  4. (转载)为什么Linux不需要碎片整理?
  5. 分享:RethinkDB 1.3 发布,分布式 JSON 数据库
  6. 别再说你不会ElasticSearch,都给你整理好了
  7. hook java android_Android Hook Java的的一個改進版本
  8. mysql performance tuning_MySQL Performance tuning
  9. python execfile_python中eval, exec, execfile,和compile [转载]
  10. c语言输入n打印数字菱形,打印数字菱形,急啊,帮帮小女子啊。。。
  11. sql server高可用_SQL Server始终在线可用性组采访问题与解答
  12. html中单选怎么写,在HTML中select标签怎样实现单选和多选
  13. sudo apt-get update 与upgrade的用法
  14. Webrtc之2台电脑视频聊天
  15. windows下设置tomcat自动启动的注意事项
  16. 垂直型与水平型电子商务网站的理解
  17. python小波包分解_小波包变换(Wavelet Packet Transform)的学习笔记
  18. 远比5G发展凶猛!物联网2018白皮书,国内规模已达1.2万亿
  19. 电子万年历c语言全教程,单片机c语言电子万年历完整程序-20210414061741.docx-原创力文档...
  20. :root选择器的妙用【2021.11.14】

热门文章

  1. no supported authentication method异常
  2. 我的世界服务器搭建原理,我的世界TNT大炮原理解析
  3. 微信小程序左侧竖形滑动菜单(淘宝京东)
  4. 计算机组装与维护课文,电脑组装实训心得体会文章精选.doc
  5. 三菱机器人Tool坐标系增量式运动指令
  6. 请安装 Microsoft Data Access Components(MDAC) 2.6 或更高版本。
  7. 解决ios上数字变成蓝色的问题
  8. web安全的漏洞种类
  9. 藏宝图(蓝桥杯模拟5)
  10. FreeRTOS记录(六、FreeRTOS消息队列—Enocean模块串口通讯、RAM空间不足问题分析)