最近公司准备将旧系统的.NET部分翻版,项目除了有后台的还有个与设备对接的客户端用蓝牙连接的,所有这周对相关技术做了一个验证。

搜了一下Java 蓝牙相关信息,我去资料也太少了,少也就算了连bluecove库也是有问题的。经过艰难的查找,最终还是调通了。因为整个过程都是靠大家的资料去解决的,所以本着造福后人的角度我把我的经验分享一下,让后人不用想我一样满世界去找。

BlueCove框架

首先是Java SE虽然支持蓝牙但是支持的并不是很好,反而在Java ME 支持设备方面较好,但是我桌面平台也要啊,所有就有框架BlueCove了。BlueCove的API我用了感觉风格整体都和Java ME差不多,所以当你有比较复杂的需求又找不到文档的时候可以参考一下Java ME的资料

BlueCove框架最大的问题就是比较老了, 2.1.1-SNAPSHOT.63 文档最后更新是2010年,提供的jar包居然不支持64位系统!还好有解决方案的,不然我就不用开发了。这里首先参考这篇博客 Eclipse + Java + BlueCove + WIN/MAC 蓝牙开发 这篇对解决方法的介绍的比较详细,但是并没有帮我直接解决问题,因为我顺着链接去下载的jar还是不支持64位系统(也可能是我下错了包了)。不过我知道了是可以解决的,于是各种百度和谷歌终于找到了能在64位系统运行的jar包

64位系无法运行会提示:

Native Library intelbth_x64 not available
Native Library bluecove_x64 not available

官网直接下载的2.1.0版本不支持64位,下面这个支持的版本看路径也是官方的,竟然不提供!亏我找了不知道多久。
64位支持版本jar包下载地址:

http://snapshot.bluecove.org/distribution/download/2.1.1-SNAPSHOT/2.1.1-SNAPSHOT.63/

老铁们,这个地址访问不了直接看文章最后的Demo,里面有lib包

BlueCove还需要Apache的commons-io包,这个顺便下就可以的。

测试环境:

蓝牙是与网卡一体的 bcm94352

蓝牙连接:作为服务端

解决了框架问题接下去就简单了,这方面网上的例子不多但还是有的(都差不多),都是手机控制电脑,这几个而是从上面那个博客找到的(感谢上一个博客让我少走了一点弯路)。
参考以下三篇文章:
http://royal2xiaose.iteye.com/blog/1420138
http://www.eoeandroid.com/thread-264135-1-1.html
http://blog.csdn.net/pku_android/article/details/7430849

这三篇都是将PC作为一个服务端,让手机主动连接。

//本机蓝牙设备
private LocalDevice local = null;
// 流连接
private StreamConnection streamConnection = null;
// 接受数据的字节流
private byte[] acceptdByteArray = new byte[1024];
// 输入流
private DataInputStream inputStream;
//接入通知
private StreamConnectionNotifier notifier;
//线程池
private  final static ExecutorService service = Executors.newCachedThreadPool();public BuletoothService() {try {//这两步不一定要BluCatUtil.doctorDevice();                    // 驱动检查RemoteDeviceDiscovery.runDiscovery();        // 搜索附近所有的蓝牙设备System.out.println(RemoteDeviceDiscovery.getDevices());} catch (IOException | InterruptedException e1) {e1.printStackTrace();}try {local = LocalDevice.getLocalDevice();if (!local.setDiscoverable(DiscoveryAgent.GIAC))System.out.println("请将蓝牙设置为可被发现");/*** 作为服务端,被请求*/String url = "btspp://localhost:" +  new UUID(80087355).toString() + ";name=RemoteBluetooth";  notifier = (StreamConnectionNotifier)Connector.open(url);} catch (IOException e) {e.printStackTrace();}service.submit(this);
}

上面的其实就一个Connector.open(url)是重点,service.submit(this); 获取数据在新线程中。
为了能够手动停止线程,做了一些处理。

@Overridepublic void run() {try {String inStr = null;streamConnection = notifier.acceptAndOpen();             //阻塞的,等待设备连接inputStream = streamConnection.openDataInputStream();int length;while (true) {if ((inputStream.available()) <= 0) {                 //不阻塞线程if (stopFlag)                                        //UI停止后,关闭break;Thread.sleep(800);                                   //数据间隔比较长,手动堵塞线程} else {length = inputStream.read(acceptdByteArray);if(length>0) {inStr = new String(acceptdByteArray,0,length);System.out.println(inStr);}}}} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();} finally {try {if (inputStream != null)inputStream.close();if (streamConnection != null)streamConnection.close();} catch (IOException e) {e.printStackTrace();}}}

核心就是streamConnection = notifier.acceptAndOpen();获得连接这里会堵塞线程(没有作停止处理!!!)。有连接后获得输入流inputStream = streamConnection.openDataInputStream();接下来就是你自己发挥了。

蓝牙连接:作为客户端

网上关于这个的是真的几乎没有!因为需要一个服务端,现在我手头客户端是挺多的就是缺个服务端。公司的电脑都是没蓝牙的,过几天问同事借太笔记本再测试!所以下面的代码我也只是提供一个思路,具体你可以测试来告诉我。或者我测试通过再告诉你们。整体都是差不多的,先连接服务端,再获取输入流/输出流。这里写了一个工具类先查询了附近的蓝牙设备(详见本文蓝牙发现小节),因为需要 BluetoothAddress ,如果这个是已知的可以直接写。

Set<RemoteDevice> devicesDiscovered = RemoteDeviceDiscovery.getDevices();     //附近所有的蓝牙设备,必须先执行 runDiscoveryif (devicesDiscovered.iterator().hasNext()) {                                  //连接RemoteDevice first = devicesDiscovered.iterator().next();streamConnection = (StreamConnection) Connector.open("btspp://" + first.getBluetoothAddress() + ":1");}
  1. Set<RemoteDevice> devicesDiscovered = RemoteDeviceDiscovery.getDevices()附近可用的蓝牙连接
  2. streamConnection = (StreamConnection) Connector.open("btspp://" + first.getBluetoothAddress() + ":1"); 直接连接
  3. url地址 :btspp://<蓝牙设备地址>:<通道号>
  4. 有连接后获得输入流inputStream = streamConnection.openDataInputStream();一样了

有个简单参考博客:http://blog.sina.com.cn/s/blog_a861feb40102vppo.html
里面没有太多的内容,流程比较清晰。通道号我用pc连接Anrdoid手机的时候,好像不同的通道有不同的功能,有的提示要读取音频,有的提示要读取电话和联系人等。可能这个通道在PC上功能又是不一样的。

2017.8.22 PC读取蓝牙连接的电子秤数据验证通过,客户端可行。

蓝牙设备发现

搜索周边可用的蓝牙是比较方便的。

public final static Set<RemoteDevice> devicesDiscovered = new HashSet<RemoteDevice>();private static void findDevices() throws IOException, InterruptedException {final Object inquiryCompletedEvent = new Object();devicesDiscovered.clear();DiscoveryListener listener = new DiscoveryListener() {public void inquiryCompleted(int discType) {System.out.println("#" + "搜索完成");synchronized (inquiryCompletedEvent) {inquiryCompletedEvent.notifyAll();}}@Overridepublic void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {devicesDiscovered.add(remoteDevice);try {System.out.println("#发现设备" + remoteDevice.getFriendlyName(false));} catch (IOException e) {e.printStackTrace();}}@Overridepublic void servicesDiscovered(int arg0, ServiceRecord[] arg1) {System.out.println("#" + "servicesDiscovered");}@Overridepublic void serviceSearchCompleted(int arg0, int arg1) {System.out.println("#" + "serviceSearchCompleted");}};synchronized (inquiryCompletedEvent) {LocalDevice ld = LocalDevice.getLocalDevice();System.out.println("#本机蓝牙名称:" + ld.getFriendlyName());boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC,listener);if (started) {System.out.println("#" + "等待搜索完成...");inquiryCompletedEvent.wait();LocalDevice.getLocalDevice().getDiscoveryAgent().cancelInquiry(listener);System.out.println("#发现设备数量:" + devicesDiscovered.size());}}
}

可以参考Java ME的流程,核心是:
LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC,listener); (设备可被发现,搜索监听器),监听器在不同的过程节点提供了回调方法,设备发现的时候添加进集合中:

@Override
public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {devicesDiscovered.add(remoteDevice);try {System.out.println("#发现设备" + remoteDevice.getFriendlyName(false));} catch (IOException e) {e.printStackTrace();}
}

扩展参考

如果有更多的需求有以下几个文档可以参考:
官方API文档: http://snapshot.bluecove.org/
Java ME 蓝牙:http://www.oracle.com/technetwork/java/javame/tech/index-140411.html

感谢

http://blog.csdn.net/old_me_mory/article/details/18962701作者:Old_Me_Mory 提供了我总的解决思路;
还有许多的文章作者提供了解决思路!

Demo下载

没有代码总是很难解决一些问题,点击这里Demo下载

JavaSE + bluecove 蓝牙连接相关推荐

  1. 100连接蓝牙_车机蓝牙连接常见问题说明

    汽车已成为了人民生活中的必需品,大家开车过程中或多或少会碰到汽车娱乐主机使用蓝牙时的闹心问题,从而影响开车的心情,今天小编给老铁们列出几条闹心问题做下说明. 问题1:蓝牙连接时无法播放苹果手机的微信语 ...

  2. tcp连接多久会自动断开_苹果M1 Mac用户报告蓝牙连接问题:外设经常会断开

    IT之家 11 月 25 日消息 据外媒 AppleInsider 报道,一些新的 M1 MacBook Air.13 英寸 MacBook Pro 和 Mac mini 的用户正面临蓝牙连接问题,并 ...

  3. 第二篇、通过蓝牙连接外设

    简介: 很早前就像总结一下手机通过蓝牙连接外设的知识点,但是由于项目比较急,也没有时间去总结.今天刚好看到一篇别人的博客,我就结合的总结了一下. 实现的流程: 建立中心角色 扫描外设(discover ...

  4. 手机蓝牙连不上jimu机器人_蓝牙连接出现问题到解决问题,一件小事,感慨实时逆向思维的重要...

    有一个古老的哲学难题:"如果森林里的一棵树倒了,但没人听见,那么它发出声音了吗?如何回答这个问题和看待它的角度有关.然而,如果观察者和被观察者的关系是必不可少的基本关系,那么就不可能有树倒下 ...

  5. lollipods耳机蓝牙连接方法

    打开盖子,耳机在盒子里不要动,别拿出来,长按盒子背面的钮3秒,打开手机蓝牙,会同时显示 EDIFIER LolliPods R , EDIFIER LolliPods L ,随便连上1个,比如配对并连 ...

  6. 蓝牙连接不上车要hfp_科普|蓝牙耳机小知识,这些都不知道难怪你选不到好的蓝牙耳机...

    一.蓝牙耳机工作原理 首先手机会与蓝牙耳机先建立一个蓝牙传输的通道.然后手机音频编码芯片把音频文件编码成蓝牙传输可以识别的格式,并传输给蓝牙耳机.最后蓝牙耳机解码芯片把编码过的文件解码,并放大音频信号 ...

  7. android 蓝牙链接电脑,如何使从台式电脑到Android设备的测试蓝牙连接

    我正在使用具有蓝牙适配器的Ubuntu 11.10台式电脑和使用带有蓝牙的Android 2.2的Android平板电脑. (两款设备上的蓝牙版本应为2.0或2.1版本)如何使从台式电脑到Androi ...

  8. 黑苹果关机重启后蓝牙连接不上_手机要关机吗,要贴膜吗,要套壳吗?看完这条,都有答案了_政务_澎湃新闻...

    晚上习惯关机睡觉的朋友们在哪里? 举起你们的手让小布看看! 那么问题来了,你为啥要关机睡觉? 是担心手机"睡眠不足", 还是担心屏亮会让你忍不住地熬夜? 然而,有朋友认为手机应该每 ...

  9. ble连接过程建立_九点之蓝牙连接

    蓝牙连接 蓝牙连接是如何进入到连接状态呢,首先必须经历前面提到的广播阶段,主端通过扫描到从端的广播来发现这个设备,之后让主端发出连接请求来要求与从端建立连接,便可以进入到连接状态.由于蓝牙连接牵涉的点 ...

最新文章

  1. ICLR论文盲审大反转:三个“8”完美过关,又来两个“1”彻底拒绝
  2. Linux系统ssh无法启动,Linux系统上SSH无法启动
  3. WIN7下的VS2008在调试OpenCV_2.3.1的程序时报错丢失tbb_debug.dll的解决办法~
  4. Mckinsey insights!
  5. ubuntu如何编辑/etc/ld.so.conf
  6. pymysql.err.InternalError: (1130, Host '127.0.0.1' is not allowed to connect to this MySQL server)
  7. deep learning入门学习
  8. 手把手教我班小姐姐学java之方法重写与方法重载
  9. 滴滴货运公布首日战报 杭州成都订单破一万单
  10. Spark入门实战系列--6.SparkSQL(上)--SparkSQL简介
  11. 联想m7216更换墨粉流程图_联想M7216打印机更换墨后继续显示需更换
  12. python绘制缓和曲线_CAD中如何绘制缓和曲线
  13. Docker 镜像加速器
  14. android 微信小程序 gps 飘,微信小程序实现自动定位功能
  15. win10修改C盘Users底下的账号名字
  16. Matlab 校验方法
  17. css 多边形边框(八边形)
  18. tf.convert_to_tensor
  19. 基于华为鲲鹏云的c语言程序设计,华为DevRun第四讲,华为云鲲鹏云服务移植快速入门与实践...
  20. 回顾敏捷实践踩过的坑:如果重新做,我会这样做(一)

热门文章

  1. 制作stlink(烧录部分)
  2. windows配置好用的RSS
  3. idea自动排版html,idea怎么格式化代码?
  4. MFC程序的剖析及生死因果揭秘
  5. oracle gc buffur,【性能調優】Oracle AWR報告指標全解析
  6. WXP连接Vista或Win7远程桌面
  7. WXP380 电容式MEMS高性能数字气压传感器 电容式MEMS压力传感器快速代DPS310 BMP380 SLP06 HP303B “电容式”噪声超低的高精度MEMS气压传感器;
  8. 转:Windows Shell 编程 第七章_1
  9. ios mac使用mitmproxy抓包
  10. PyTorch 加载预训练权重