android 蓝牙编程

前言

最近有一些蓝牙的通信需要做,就研究了一下蓝牙连接相关

  1. 连接蓝牙电子秤
  2. 连接pos机打印

其中连接蓝牙电子秤是接收数据
pos机打印是发送数据/接收数据

流程图

蓝牙连接

流程图画的相当不专业,请自行脑补

核心类

因为这次的电子秤不是4.0的设备,所以没有使用BLE的开发,而是经典蓝牙(SPP)的连接方式
BluetoothAdapter

全局变量

protected BluetoothAdapter mAdapter;

获取的方法,在API18下的时候使用的方式和以上的不一样,其实差别不大

if (SDK_INT < 18) {
    adapter = BluetoothAdapter.getDefaultAdapter();
} else {
    BluetoothManager bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    adapter = bm.getAdapter();
}

蓝牙使用的是注册广播的方式来获取系统给我们的通知
核心有以下的几种,注册广播的方法自己去搜下吧

    BluetoothDevice.ACTION_FOUND//找到设备
    BluetoothDevice.ACTION_NAME_CHANGED//设备的名字
    BluetoothAdapter.ACTION_DISCOVERY_FINISHED//扫描结束
    BluetoothDevice.ACTION_PAIRING_REQUEST//配对请求的放弃
    BluetoothAdapter.STATE_OFF//蓝牙关闭
    BluetoothAdapter.STATE_ON//蓝牙开启

连接

一般这种连接应该是全局单例,考虑写在了service中

首先需要扫描所有的蓝牙连接,但是这里有个坑,就是如果你将广播注册在onCreate中和onDestroy,你每次都需要接收系统的广播,如果出现同名或者别的原因,这里就会一直接收广播
所以这里需要动态的将广播注册与反注册
我这里使用的方案请参照流程图

说明

这里是经典蓝牙(SPP)的连接代码,BLE的连接相关目前还没有做,后续如果有实现的时候也会再写blog

关于UUID

蓝牙连接的UUID是有一套自己的定义规范的,但是目前的厂商不知道为什么大部分习惯都使用同一个UUID,我这里蓝牙称,蓝牙打印机都用的这个

    public static final UUID _UUID = java.util.UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
扫描
    mAdapter.startDiscovery()
关于找到设备的坑

这里有一些关于设备的坑,有的设备你使用BluetoothDevice.ACTION_FOUND广播中获取蓝牙设备的名字会发现是空的,这个时候就很尴尬了,使用系统自带的蓝牙扫描也会发现,扫描到的是先MAC地址,然后过几秒更改为名字,这里有另一个广播BluetoothDevice.ACTION_NAME_CHANGED可以获取到名字更新时的光爆
当然蓝牙设备如果提前知道蓝牙的mac地址,最好还是使用mac地址连接匹配为最佳,毕竟mac地址轻易不会重复

配对
try {
        // 连接建立之前的先配对
        if (device.getBondState() == BluetoothDevice.BOND_NONE) {
            Method creMethod = BluetoothDevice.class.getMethod("createBond");
            creMethod.invoke(device);
        } else {//已配对,连接socket
            connDevice(device);
        }
    } catch (Exception e) {
        // TODO: handle exception
        //DisplayMessage("无法配对!");
        e.printStackTrace();
    }

这里如果已经配对,则直接连接,如果没有配对需要先配对,这里只是创建配对请求
ACTION_PAIRING_REQUEST这个广播用于接收配对请求的发起,然后使用

        LogUtils.d(TAG, "manualConn:" + manualConn);
                        if (manualConn) {
                            return;
                        }
                        final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                        if (device == null) {
                            return;
                        }
                        LogUtils.d(TAG, device.getName());
                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                            try {
                                //                        ClsUtils.setPin(device.getClass(), device, pwd); // 手机和蓝牙采集器配对
                                LogUtils.d(TAG, "设置pin码" + pwd);
                                ToastUtils.toast(device.getName() + "配对中");
                                boolean pinResult = device.setPin(pwd.getBytes());
    //                            handler.postDelayed(new Runnable() {
    //                                @Override
    //                                public void run() {
    //                                    try {
    //                                        ClsUtils.cancelPairingUserInput(device.getClass(), device);
    //                                    } catch (Exception e) {
    //                                    }
    //                                }
    //                            }, 1000);
                                // 一般调用不成功,前言里面讲解过了
                                LogUtils.d(TAG, "pinResult:" + pinResult);
                                if (pinResult) {
                                    connDevice(device);
                                } else {
                                    ToastUtils.toast("pin码不正确,请手动配对电子秤后点击连接");
                                    manualConn = true;
                                }
                            } catch (Exception e) {
                                ToastUtils.toast("请求连接错误...");
                            }
                        }

这里是直接贴出来了程序中的片段,也会有一些报错,替换为自己的Log/Toast的util就可以了,也可以考虑删除掉,这里注释掉的部分原本是打算关闭配对的连接框的,但是这里有一些其他的问题,不同的rom处理方式不同,有些处理时会将pin码清空导致连接失败,所以这里将这部分代码清空,不关闭了

连接

核心连接代码

socket = device.createInsecureRfcommSocketToServiceRecord(_UUID);  //不安全的
// socket = device.createRfcommSocketToServiceRecord(_UUID);  //安全
socket.connect()

关于连接方式,这里有两种.一种是使用不安全的连接方式,一种是使用安全的连接方式,这里需要根据你的蓝牙设备作为区分,
都是创建一个BluetoothSocket

一般来说,如果对方是android设备,应该是安全的,如果是外置设备(蓝牙电子秤) 一般使用不安全的方案.

这两个连接方法要求API>10

题外话
我其实现在的minSDK已经是19了,目前google自己都放弃维护低版本了,google chrome都不支持他们了,咱们也没必要继续支持低版本了

连接成功后,可以获取到一个socket连接,可以用这个socket连接获取到相关信息,不管是接收还是发出,通过这个连接就可以具体的获取相关信息

这里只是抛砖引玉

具体的实现后续有时间抽取出来形成一个开源项目再贴吧,项目毕竟是公司的,我这里不方便直接将整个代码贴出来,这个连接的相关代码非常乱

后记

这个蓝牙项目让我感受到了google深深的恶意,整个项目的坑数不胜数,这里先这样吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值