JNI之Java实现蓝牙交互

news2025/1/10 20:52:02

蓝牙概述

蓝牙,是一种支持设备短距离通信(一般10m内)的无线电技术,能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间,通过蓝牙设备之间的无线通信实现数据传输,实现数据传输,音频传输,文件传输,图片传输等多种应用的无线信息交换。利用“蓝牙”技术,能够有效地简化移动通信终端设备之间的通信,也能够成功地简化设备与因特网Internet之间的通信,从而数据传输变得更加迅速高效,为无线通信拓宽道路。蓝牙技术是一种无线数据和语音通信开放的全球规范,它是基于低成本的近距离无线连接,为固定和移动设备建立通信环境的一种特殊的近距离无线技术连接。目前,越来越多的企业采用蓝牙交互技术来实现自己的产品。

Java实现蓝牙交互的优势

Java是世界上最流行的编程语言之一。Java具有平台无关性、对象化编程、简单易用、可扩展性等特点,因此目前已广泛应用于企业和互联网领域。Java还提供了很好的蓝牙接口,可以帮助企业快速开发蓝牙交互应用。Java的蓝牙接口是基于JSR-82标准实现的,这个标准允许JAVA应用程序访问蓝牙网络的API。与其他大多数蓝牙接口不同,JSR-82可以在任意实现了JSR-82标准的蓝牙设备间进行通讯,这就保证了兼容性和灵活性。

蓝牙通信的原理

蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主角色,另一为从角色,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成功后,双方即可收发数据。

蓝牙主端设备发起呼叫,首先是查找,找出周围处于可被查找的蓝牙设备。主端设备找到从端蓝牙设备后,与从端蓝牙设备进行配对,此时需要输入从端设备的PIN码,也有设备不需要输入PIN码。

配对完成后,从端蓝牙设备会记录主端设备的信任信息,此时主端即可向从端设备发起呼叫,已配对的设备在下次呼叫时,不再需要重新配对。

Java蓝牙交互应用实例

导包

<dependency>
    <groupId>net.sf.bluecove</groupId>
    <artifactId>bluecove</artifactId>
    <version>2.1.0</version>
</dependency>

BluetoothServer

public class BluetoothServer implements Runnable {
    //本机蓝牙设备
    private LocalDevice local = null;
    // 流连接
    private StreamConnection streamConnection = null;
    // 输入流
    private InputStream inputStream;
    private OutputStream outputStream;
    //接入通知
    private StreamConnectionNotifier notifier;
    //线程池
    private final static ExecutorService service = Executors.newCachedThreadPool();
    public String serverName;
    public String serverUUID;
    private OnServerListener mServerListener;
    public interface OnServerListener {
        void onConnected(InputStream inputStream, OutputStream outputStream);
        void onDisconnected();
        void onClose();
    }
    public BluetoothServer(String serverUUID, String serverName) {
        this.serverUUID = serverUUID;
        this.serverName = serverName;
    }
    public void start() {
        try {
            local = LocalDevice.getLocalDevice();
            if (!local.setDiscoverable(DiscoveryAgent.GIAC)) {
                System.out.println("请将蓝牙设置为可被发现");
            }
            /**
             * 作为服务端,被请求  ";name="+serverName;
             */
            String url = "btspp://localhost:" +  serverUUID;
            notifier = (StreamConnectionNotifier) Connector.open(url);
            service.submit(this);
        } catch (IOException e) {
            System.out.println(e.getMessage());;
        }
    }

    public OnServerListener getServerListener() {
        return mServerListener;
    }

    public void setServerListener(OnServerListener mServerListener) {
        this.mServerListener = mServerListener;
    }

    @Override
    public void run() {
        try {
            //阻塞的,等待设备连接
            streamConnection = notifier.acceptAndOpen();               
            inputStream = streamConnection.openInputStream();
            outputStream = streamConnection.openOutputStream();

            if (mServerListener != null) {
                mServerListener.onConnected(inputStream, outputStream);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}

BluetoothClient

public class BluetoothClient {
    private StreamConnection streamConnection;
    private OnDiscoverListener onDiscoverListener = null;
    private OnClientListener onClientListener = null;

    public interface OnClientListener {
        void onConnected(InputStream inputStream, OutputStream outputStream);
        void onConnectionFailed();
        void onDisconnected();
        void onClose();
    }

    public interface OnDiscoverListener {
        void onDiscover(RemoteDevice remoteDevice);
    }
    
    public BluetoothClient() {
    }

    public OnDiscoverListener getOnDiscoverListener() {
        return onDiscoverListener;
    }

    public void setOnDiscoverListener(OnDiscoverListener onDiscoverListener) {
        this.onDiscoverListener = onDiscoverListener;
    }

    public OnClientListener getClientListener() {
        return onClientListener;
    }
    
    public void setClientListener(OnClientListener onClientListener) {
        this.onClientListener = onClientListener;
    }

    public void find() throws IOException, InterruptedException {
        //附近所有的蓝牙设备,必须先执行 runDiscovery
        Set<RemoteDevice> devicesDiscovered = RemoteDeviceDiscovery.getDevices();       
        Iterator<RemoteDevice> itr = devicesDiscovered.iterator();
        //连接
        while (itr.hasNext()) {                                  
            RemoteDevice remoteDevice = itr.next();

            onDiscoverListener.onDiscover(remoteDevice);
        }
    }

    public void startClient(RemoteDevice remoteDevice, String serviceUUID) throws IOException, InterruptedException {
        String url = RemoteDeviceDiscovery.searchService(remoteDevice, serviceUUID);
        streamConnection = (StreamConnection) Connector.open(url);
        if (this.onClientListener != null) {
            this.onClientListener.onConnected(streamConnection.openInputStream(), streamConnection.openOutputStream());
        }
    }
}

RemoteDeviceDiscovery

public class RemoteDeviceDiscovery {
    public final static Set<RemoteDevice> devicesDiscovered = new HashSet<RemoteDevice>();

    public final static Vector<String> serviceFound = new Vector<String>();

    final static Object serviceSearchCompletedEvent = new Object();
    final static Object inquiryCompletedEvent = new Object();
    
    private static 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 transID, ServiceRecord[] servRecord) {
            for (int i = 0; i < servRecord.length; i++) {
                String url = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                if (url == null) {
                    continue;
                }
                serviceFound.add(url);
                DataElement serviceName = servRecord[i].getAttributeValue(0x0100);
                if (serviceName != null) {
                    System.out.println("service " + serviceName.getValue() + " found " + url);
                } else {
                    System.out.println("service found " + url);
                }
            }
            System.out.println("#" + "servicesDiscovered");
        }

        @Override
        public void serviceSearchCompleted(int arg0, int arg1) {
            System.out.println("#" + "serviceSearchCompleted");
            synchronized(serviceSearchCompletedEvent){
                serviceSearchCompletedEvent.notifyAll();
            }
        }
    };

    private static void findDevices() throws IOException, InterruptedException {
        devicesDiscovered.clear();
        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());
            }
        }
    }

    public static Set<RemoteDevice> getDevices() throws IOException, InterruptedException {
        findDevices();
        return devicesDiscovered;
    }

    public static String searchService(RemoteDevice btDevice, String serviceUUID) throws IOException, InterruptedException {
        UUID[] searchUuidSet = new UUID[] { new UUID(serviceUUID, false) };

        int[] attrIDs =  new int[] {
                // Service name
                0x0100 
        };

        synchronized(serviceSearchCompletedEvent) {
            System.out.println("search services on " + btDevice.getBluetoothAddress() + " " + btDevice.getFriendlyName(false));
            LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(attrIDs, searchUuidSet, btDevice, listener);
            serviceSearchCompletedEvent.wait();
        }

        if (serviceFound.size() > 0) {
            return serviceFound.elementAt(0);
        } else {
            return "";
        }
    }
}

测试

Bluetooth Server
@Test
public void test(){
   final String serverName = "Bluetooth Server Test";
   final String serverUUID = "1000110100001000800000805F9B34FB";  //根据需要自定义
   BluetoothServer server = new BluetoothServer(serverUUID, serverName);
   server.setServerListener(new BluetoothServer.OnServerListener() {
       @Override
       public void onConnected(InputStream inputStream, OutputStream outputStream) {
         System.out.printf("Connected");
         //添加通信代码
       }
       @Override
       public void onDisconnected() {

       }
       @Override
       public void onClose() {

       }
    });
    server.start();
}
测试结果
Connected to the target VM, address: '127.0.0.1:8442', transport: 'socket'
Native Library intelbth_x64 not available
Native Library bluecove_x64 not available
BlueCove libraries not available
Disconnected from the target VM, address: '127.0.0.1:8442', transport: 'socket'

没有找到_64的包。

看看导包的版本

下载_64版本

官网:BlueCove - BlueCove JSR-82 project

下载地址:https://sourceforge.net/projects/bluecove/files/

ps:蓝牙就到这了。

JNI,Java Native Interface,主要是通过读取其他底层语言的文件,转换成Java的类,操作设备。

另外还有连接打印机、pos机等,也是使用Java的JNI调用其他底层语言的文件,如打印机使用jacob读取dll文件、可实现无接触操作语音智能打印等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/842194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

golang代码热加载,热更新库air库实践

windows下先生成air.exe文件&#xff0c;然后移动到golang的执行目录&#xff1a; 2.简介 air是一款基于golang开发的实时热加载工具&#xff0c;通过使用该工具&#xff0c;使得开发人员能专注于coding&#xff0c;而不会被编译过程打断。 项目地址: https://github.com/cos…

【工作中问题解决实践 九】Spring中事务传播的问题排查

最近在工作中遇到了两个关于事务操作的问题&#xff0c;顺便就着这两个问题又回顾了一遍Spring的事务相关的操作&#xff0c;想着一次性把这个问题研究明白了&#xff0c;后续使用事务的时候也能踏实点&#xff0c;让事务发挥真实的作用 什么是事务&#xff1f;什么是事务管理…

【探索Linux】—— 强大的命令行工具 P.2(Linux下基本指令)

前言 前面我们讲了C语言的基础知识&#xff0c;也了解了一些数据结构&#xff0c;并且讲了有关C的一些知识&#xff0c;也相信大家都掌握的不错&#xff0c;今天博主将会新开一个Linux专题&#xff0c;带领大家继续学习有关Linux的内容。今天第一篇文章博主首先带领大家了解一下…

客服型电话呼叫中心系统,助力企业提升客户服务质量

客服型电话呼叫中心系统是企业客户服务的重要工具之一&#xff0c;它通过电话和网络等方式&#xff0c;为客户提供快速、便捷、高效的服务。客服型电话呼叫中心系统具备自动接听来电、自动路由、管理知识库、录音和监控、生成报表分析等多种功能&#xff0c;有利于企业提高客户…

IP提取器对比器

需求&#xff1a; 一个html 页面 &#xff0c;有两个输入框 第一个输入框输入文本中包含多个ip&#xff0c;输入的ip是不规则的&#xff0c;需要使用正则表达式提取出 输入文本的ip地址 &#xff0c; 然后在第二个输入框中输入内容&#xff0c;并提取出内容的ip &#xff0c;如…

实时渲染与传统渲染有啥区别?实时渲染器有哪些

您是否曾经玩过 3D 视频游戏&#xff0c;或观看过让您感觉身处真实的建筑环境&#xff1f;如果是&#xff0c;那么您已经体验过实时渲染。和传统的渲染有什么不同吗&#xff1f;在本文中了解有关实时渲染的所有信息。 什么是实时渲染&#xff1f; 为了更容易理解什么是实时渲…

jupyter文档转换成markdown

背景 上一篇文章**《如何优雅地用python生成模拟数据》**我就使用jupyter写的&#xff0c;这个真的是万能的&#xff0c;可以插入markdown格式的内容&#xff0c;也可写代码&#xff0c;关键是像ipython一样&#xff0c;可以分步执行。 我可以这样自由的写我的博客内容&#x…

Docker入门——保姆级

Docker概述 ​ —— Notes from WAX through KuangShen 准确来说&#xff0c;这是一篇学习笔记&#xff01;&#xff01;&#xff01; Docker为什么出现 一款产品&#xff1a;开发—上线 两套环境&#xff01;应用环境如何铜鼓&#xff1f; 开发 – 运维。避免“在我的电脑…

【Groups】50 Matplotlib Visualizations, Python实现,源码可复现

详情请参考博客: Top 50 matplotlib Visualizations 因编译更新问题&#xff0c;本文将稍作更改&#xff0c;以便能够顺利运行。 1 Dendrogram 树状图根据给定的距离度量将相似的点组合在一起&#xff0c;并根据点的相似性将它们组织成树状的链接。 新建文件Dendrogram.py: …

怎样在pdf上直接修改?看看这几种修改方法

怎样在pdf上直接修改&#xff1f;PDF是一种非常流行的文件格式&#xff0c;它在保持文档格式不变的同时也可以压缩文件大小&#xff0c;便于分享。尽管 PDF 文件很便捷&#xff0c;但是在 PDF 上进行修改却是一件比较困难的事情。幸运的是&#xff0c;有很多工具可以帮助你在 P…

AUTOSAR笔记2:AP主要模块

1 CM CM&#xff08;Communication Management&#xff09;组件提供独立于网络和协议的应用间通信服 务&#xff0c;支持如下功能&#xff1a; 服务发现&#xff0c;包括服务注册、服务查找等&#xff1b;应用间通信&#xff0c;支持单向数据收发&#xff08;Event&#xff0…

STM32入门——定时器

内容为江科大STM32标准库学习记录 TIM简介 TIM&#xff08;Timer&#xff09;定时器定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时&…

TFTP 的使用操作指南(轻松入门版)

(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误&#x…

springCache-缓存

SpringCache 简介&#xff1a;是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;底层可以切换不同的cache的实现&#xff0c;具体是通过CacheManager接口实现 使用springcache,根据实现的缓存技术&#xff0c;如使用的redis,需要导入redis的依赖包 基于map缓存 …

一招让你的Python爬虫事半功倍

在Python爬虫的世界里&#xff0c;你是否也被网站的IP封锁问题困扰过&#xff1f;别担心&#xff0c;我来教你一个简单而又有效的爬虫ip设置方法&#xff0c;让你的爬虫畅行无阻&#xff01;快来跟我学&#xff0c;让你的Python爬虫事半功倍&#xff0c;轻松搞定IP封锁问题&…

【室内定位】UWB TDOA定位,PDOA定位介绍

当前室内应用场景&#xff0c;最大的难点是没有基础设施&#xff0c;目前应用的场景中&#xff0c;都是基于用户的需求&#xff0c;或采用 UWB 技术&#xff0c;或采用蓝牙技术&#xff0c;并根据不同的室内环境来定制化的定制化的布设定位网络&#xff0c;并借助同技术的UWB定…

[C++项目] Boost文档 站内搜索引擎(4): 搜索的相关接口的实现、线程安全的单例index接口、cppjieba分词库的使用、综合调试...

有关Boost文档搜索引擎的项目的前三篇文章, 已经分别介绍分析了: 项目背景: &#x1fae6;[C项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍…文档解析、处理模块parser的实现: &#x1fae6;[C项目] Boost文档 站内搜索引擎(2): 文档文本解析模块…

百模大战,谁是赢家?文心3.5稳坐国内第一,综合评分超ChatGPT!

近日&#xff0c;清华大学新闻与传播学院沈阳团队发布《大语言模型综合性能评估报告》&#xff08;下文简称“报告”&#xff09;&#xff0c;报告显示百度文心一言在三大维度20项指标中综合评分国内第一&#xff0c;超越ChatGPT&#xff0c;其中中文语义理解排名第一&#xff…

取多个元素的整数部分 numpy.fix()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 取多个元素的整数部分 numpy.fix() [太阳]选择题 请问关于以下代码最后的输出结果的是&#xff1f; import numpy as np a [1.6, 2.3, -3.8, -4.2] print("【显示】a",a) print(&…

【MySQL】对表中数据的操作

本期给大家带来的是MySQL下对表中数据的增删查改操作 目录 一、对表插入数据 1.1 单行数据插入 1.2 多行数据插入 1.3 插入冲突时更新数据 1.4 替换式插入 1.5 插入查询结果 二、对表中数据进行查询 2.1 基本select 2.1.1 使用select查询表中数据 2.1.2 使用select…