JavaSE + bluecove 蓝牙连接

本文详细介绍使用BlueCove框架进行Java蓝牙开发的过程,包括解决64位系统兼容性问题、实现蓝牙服务端与客户端连接及数据交换的方法,并分享了蓝牙设备发现的技巧。
AI助手已提取文章相关产品:

最近公司准备将旧系统的.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.youkuaiyun.com/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); 获取数据在新线程中。
为了能够手动停止线程,做了一些处理。

@Override
	public 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();		//附近所有的蓝牙设备,必须先执行 runDiscovery
			if (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();
			}
		}

		@Override
		public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
			devicesDiscovered.add(remoteDevice);

			try {
				System.out.println("#发现设备" + remoteDevice.getFriendlyName(false));
			} catch (IOException e) {
				e.printStackTrace();
			}
				
		}
		@Override
		public void servicesDiscovered(int arg0, ServiceRecord[] arg1) {
			System.out.println("#" + "servicesDiscovered");
		}

		@Override
		public 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.youkuaiyun.com/old_me_mory/article/details/18962701作者:Old_Me_Mory 提供了我总的解决思路;
还有许多的文章作者提供了解决思路!

Demo下载

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

您可能感兴趣的与本文相关内容

<think>嗯,用户想要结合JavaSEJavaScript的项目推荐或示例。首先,我需要理解用户的需求。他们可能是在学习这两种技术,想找一些实际项目来练习,或者想了解如何将后端Java与前端JavaScript结合起来。 JavaSEJava的标准版,主要用于桌面应用和服务器端开发,而JavaScript通常用于前端开发,运行在浏览器中。结合这两者的项目,最常见的应该是Web应用,其中Java处理后端逻辑,JavaScript处理前端交互。 接下来,我应该考虑用户可能的水平。如果是初学者,可能需要简单的项目,比如一个待办事项应用,或者简单的CRUD应用。如果有一定经验,可以推荐更复杂的项目,比如实时聊天系统或者电子商务平台。 然后,我需要参考提供的引用内容。引用[1]提到Java是编译与解释共存,而JavaScript是解释执行,可能涉及JIT优化。引用[2]和[4]讨论了Java的包和自动装箱机制,但可能对当前问题帮助不大。引用[3]涉及Java基础,如JDK、JRE、JVM,这可能对项目环境配置有帮助。 用户可能需要具体的项目类型,所以应该列举几种常见的结合方式,例如使用Java后端提供REST API,JavaScript前端通过AJAX调用这些API。或者使用Java的桌面应用内嵌JavaScript引擎,比如Rhino或Nashorn。 我应该考虑项目的可行性和资源可用性。例如,推荐使用Spring Boot作为Java后端框架,因为配置简单,适合新手。前端可以使用纯JavaScript,或者框架如React/Vue,但用户可能希望从基础开始,所以先推荐纯JS。 另外,可能需要提到JavaServlet和JSP,虽然现在较少使用,但作为传统方法仍然可行。不过REST API+前端框架更现代,更符合当前趋势。 安全问题也是一个考虑点,比如用户认证、数据校验,可以在项目中加入这些元素。同时,数据库的使用,如MySQL或H2,结合JDBC或JPA,可以增强项目的完整性。 可能需要给出具体的示例,比如学生管理系统,后端Java处理数据存储和业务逻辑,前端用JavaScript进行界面交互,通过HTTP通信。或者在线聊天室,使用WebSocket实现实时通信。 还要考虑是否需要工具链,比如Maven/Gradle构建Java项目,npm管理前端依赖,但可能对初学者复杂,所以保持简单。 最后,生成相关问题,帮助用户深入思考,比如如何设计API,如何处理跨域问题,如何优化性能等。这些能引导用户进一步学习。</think>根据JavaSEJavaScript的技术特点,以下是结合两者的项目推荐及实现思路分析: ### 一、Web应用类项目(REST API架构) 1. **学生信息管理系统** - 后端:JavaSE(Spring Boot) ```java @RestController public class StudentController { @GetMapping("/students") public List<Student> getAllStudents() { return studentService.findAll(); } } ``` - 前端:JavaScript(Fetch API) ```javascript fetch('http://localhost:8080/students') .then(response => response.json()) .then(data => renderTable(data)); ``` 2. **在线考试系统** - 关键技术点: - JavaSE处理试题存储(JDBC/Hibernate) - JavaScript实现倒计时和实时保存 - WebSocket双向通信(Java后端使用Tomcat WebSocket API) ### 二、混合执行类项目(Java内嵌JS引擎) ```java // 使用Nashorn引擎执行JavaScript ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval("function calc(x,y) { return x*y; }"); Object result = engine.eval("calc(5,3)"); System.out.println(result); // 输出15 ``` 应用场景:规则引擎、动态计算公式解析等[^1] ### 三、桌面应用类项目(JavaFX+WebView) ```java WebView webView = new WebView(); WebEngine webEngine = webView.getEngine(); webEngine.loadContent("<button onclick='callJava()'>点击调用Java</button>"); JSObject window = (JSObject) webEngine.executeScript("window"); window.setMember("javaConnector", new JavaConnector()); ``` 双向通信实现方式: - JavaScript通过`javaConnector.methodName()`调用Java方法 - Java通过`webEngine.executeScript()`调用JS函数
评论 58
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值