Android蓝牙扫描和连接!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yanxiaosa/article/details/56667829

最近在做蓝牙签到功能时,了解了蓝牙的一部分知识,虽然不够深入,但是感觉良好,他的整体思路如下:
在指定时间内,打开蓝牙,扫描周边蓝牙信号,如果有指定的蓝牙,则由用户确认连接蓝牙,最终签到成功.
首先,我们先写一个工具类,来判断当前时间是否在指定时间之内:

/**
     * 判断时间是否在时间段内
     *
     * @param date
     *            当前时间 yyyy-MM-dd HH:mm:ss
     * @param strDateBegin
     *            开始时间 00:00:00
     * @param strDateEnd
     *            结束时间 00:05:00
     * @return
     */
    public static boolean isInDate(Date date, String strDateBegin,
                                   String strDateEnd) {
         //首先,我们使用SimpleDateFormat来设置时间格式                          
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String strDate = sdf.format(date);
        // 截取当前时间时分秒,这里所填写的数字,是将当前时间转换成指定格式后,来截取字符串,数字为截取的范围
        int strDateH = Integer.parseInt(strDate.substring(11, 13));
        int strDateM = Integer.parseInt(strDate.substring(14, 16));
        int strDateS = Integer.parseInt(strDate.substring(17, 19));
        // 截取开始时间时分秒,这里截取传入的开始时间
        int strDateBeginH = Integer.parseInt(strDateBegin.substring(0, 2));
        int strDateBeginM = Integer.parseInt(strDateBegin.substring(3, 5));
        int strDateBeginS = Integer.parseInt(strDateBegin.substring(6, 8));
        // 截取结束时间时分秒,这里截取传入的结束时间
        int strDateEndH = Integer.parseInt(strDateEnd.substring(0, 2));
        int strDateEndM = Integer.parseInt(strDateEnd.substring(3, 5));
        int strDateEndS = Integer.parseInt(strDateEnd.substring(6, 8));
        if ((strDateH >= strDateBeginH && strDateH <= strDateEndH)) {
            // 当前时间小时数在开始时间和结束时间小时数之间
            if (strDateH > strDateBeginH && strDateH < strDateEndH) {
                return true;
                // 当前时间小时数等于开始时间小时数,分钟数在开始和结束之间
            } else if (strDateH == strDateBeginH && strDateM >= strDateBeginM
                    && strDateM <= strDateEndM) {
                return true;
                // 当前时间小时数等于开始时间小时数,分钟数等于开始时间分钟数,秒数在开始和结束之间
            } else if (strDateH == strDateBeginH && strDateM == strDateBeginM
                    && strDateS >= strDateBeginS && strDateS <= strDateEndS) {
                return true;
            }
            // 当前时间小时数大等于开始时间小时数,等于结束时间小时数,分钟数小等于结束时间分钟数
            else if (strDateH >= strDateBeginH && strDateH == strDateEndH
                    && strDateM <= strDateEndM) {
                return true;
                // 当前时间小时数大等于开始时间小时数,等于结束时间小时数,分钟数等于结束时间分钟数,秒数小等于结束时间秒数
            } else if (strDateH >= strDateBeginH && strDateH == strDateEndH
                    && strDateM == strDateEndM && strDateS <= strDateEndS) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

判断时间结束后,我们来看看怎么连接和扫描蓝牙的,至于布局文件,这里就不说了,只有两个控件而已.
第一步:我们获取蓝牙适配器,来检测当前手机是否支持蓝牙:

 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(mBluetoothAdapter ==null){
            //不支持蓝牙
            Toast.makeText(this, "该设备不支持蓝牙", Toast.LENGTH_SHORT).show();
        }
  如果蓝牙适配器为空的话,说明自手机不支持蓝牙,如果不为空的话,我们获取他曾经连接过得蓝牙设备信息.
        else {
            // 获取所有已经绑定的蓝牙设备
            Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
            //遍历已绑定设备
            if (devices.size() > 0) {
                for (BluetoothDevice bluetoothDevice : devices) {
                    tvDevices.append(bluetoothDevice.getName() + ":"
                            + bluetoothDevice.getAddress() + "\n\n");
                }
            }
      这里的广播是查找蓝牙,查找完毕,和蓝牙连接状态发生改变时用于接受状态.
      //蓝牙查询,可以在reciever中接受查询到的蓝牙设备
            IntentFilter mFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
            registerReceiver(mReceiver, mFilter);
            // 注册搜索完时的receiver
            mFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
            registerReceiver(mReceiver, mFilter);
    //蓝牙连接状态发生改变时,接收状态
            mFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
            registerReceiver(mReceiver,mFilter);
        }

广播注册完成了,那么接收呢?需要创建广播接受者:

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();
            // 获得已经搜索到的蓝牙设备
            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
            //通过此方法获取搜索到的蓝牙设备
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
         // 获取搜索到的蓝牙绑定状态,看看是否是已经绑定过的蓝牙
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
        // 如果没有绑定过则将蓝牙名称和地址显示在TextView上
                    tvDevices.append(device.getName() + ":"
                            + device.getAddress() + "\n");
                    //78:02:F8:D0:C0:D1
    //如果指定地址的蓝牙和搜索到的蓝牙相同,则我们停止扫描
                    if ("38:A4:ED:77:A2:8C".equals(device.getAddress())) {
                        mBluetoothAdapter.cancelDiscovery();//这句话是停止扫描蓝牙
                        //根据蓝牙地址创建蓝牙对象
                        BluetoothDevice btDev = mBluetoothAdapter.getRemoteDevice(device.getAddress());
                        //通过反射来配对对应的蓝牙
                        try {
                //这里是调用的方法,此方法使用反射,后面解释
                            createBond(btDev.getClass(), btDev);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                // 搜索完成
            } else if (action
                    .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                setTitle("搜索蓝牙设备");
            }else if(action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
            //获取发生改变的蓝牙对象
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                        //根据不同的状态显示提示
                    switch (device.getBondState()) {
                        case BluetoothDevice.BOND_BONDING://正在配对
                            Log.d("yxs", "正在配对......");
                            break;
                        case BluetoothDevice.BOND_BONDED://配对结束
                            Log.d("yxs", "完成配对");
                            Toast.makeText(context, "签到成功", Toast.LENGTH_SHORT).show();
                            handler.sendEmptyMessageDelayed(1,2000);
                            break;
                        case BluetoothDevice.BOND_NONE://取消配对/未配对
                            Log.d("yxs", "取消配对");
                        default:
                            break;
                    }
            }
        }
    };

上面有提到是用反射来连接蓝牙:这里贴一下代码,此代码为百度所得,懂得他是什么意思,但是反射我不太懂,就不说什么了.

  /**
     * 蓝牙配对
     *
     * @param btClass
     * @param btDevice
     * @return
     * @throws Exception
     */
    public boolean createBond(Class btClass, BluetoothDevice btDevice) throws Exception {
        Method createBondMethod = btClass.getMethod("createBond");//获取蓝牙的连接方法
        Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
        return returnValue.booleanValue();//返回连接状态
    }

咱们获取了扫描的数据,也连接了蓝牙,但是,怎么开启扫描的呢?在扫描之前我们是否还要判断此时蓝牙是否已经打开了呢?
在一开始,我们已经知道了当前手机是否支持蓝牙.那么,在开启扫描时,我们来判断蓝牙是否开起来了:

  /**
     * 判断是否支持蓝牙,并打开蓝牙
     * 获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。
     * 如果没打开,需要让用户打开蓝牙:
     */
    public void checkBleDevice(Context context) {
    //通过适配器对象调用isEnabled()方法,判断蓝牙是否打开了
        if (mBluetoothAdapter.isEnabled()) {
        //如果蓝牙已经打开,判断此时蓝牙是否正在扫描,如果正在扫描,则先停止当前扫描,然后在重新扫描
             if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        // 开始搜索蓝牙设备,搜索到的蓝牙设备通过广播返回
        mBluetoothAdapter.startDiscovery();

        }else{
        //如果没有开启蓝牙,调用系统方法,让用户确认开启蓝牙
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(enableBtIntent);
        }
    }

这是用户知晓的情况下,当用户没有手动去扫描蓝牙,但是此时已经到了签到时间,我们就会用到之前判断当前时间是否在指定时间之内的方法,

 /**
     * 判断是否到了指定时间,打开蓝牙,扫描指定设备
     */
    public void currentTime(){
        if(TimeUtils.isCurrentInTimeScope(13,33,13,50)){
//如果时间已经到了,则默认自动打开蓝牙,且使用handler发出一条通知,
            mBluetoothAdapter.enable();
            handler.sendEmptyMessageDelayed(0,2000);
        }else{
        //如果没有到指定时间,我们也发出一条通知,
            handler.sendEmptyMessageDelayed(2,1000);
        }
    }

上面通过时间判断开启蓝牙发出消息,那么,我们要做什么呢,这要看你自己了,我是这么干的:,1.当时间到了之后,我接受到消息,此时自动调用checkBleDevice方法扫描蓝牙,2.如果么有到指定时间,我会依旧发出一条消息,在对应消息处理中,调用currentTime方法,判断当前时间,在currentTime方法中,无论到没到指定时间,都会发出一条消息,会继续在1和2中继续判断,循环往复,直到时间到了。

 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 0){
                checkBleDevice(MainActivity.this);
            }else if(msg.what ==1){
                BluetoothDevice btDev = mBluetoothAdapter.getRemoteDevice("38:A4:ED:77:A2:8C");
                try {
                    removeBond(btDev.getClass(),btDev);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else if(msg.what == 2){
                Toast.makeText(MainActivity.this, "检查状态", Toast.LENGTH_SHORT).show();
                handler.sendEmptyMessageDelayed(3,60000);
            }else if(msg.what == 3){
                currentTime();
            }
        }
    };

因为,蓝牙连接成功后会记住,所以签到成功后,我会移除指定的已配对的蓝牙设备,通过调用另一个使用反射完成方法”:

 /**
     * 删除指定的已配对设备
     * @param btClass
     * @param btDevice
     * @return
     * @throws Exception
     */
    public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {
        Method removeBondMethod = btClass.getMethod("removeBond");//获取移除蓝牙设备的方法
        Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);//得到操作结果
        return returnValue.booleanValue();
    }

最后由于我们注册了广播,所以,在页面销毁时,我们要解除注册:

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //解除注册
        unregisterReceiver(mReceiver);
    }
展开阅读全文

没有更多推荐了,返回首页