美文网首页
Android 蓝牙4.0入门开发

Android 蓝牙4.0入门开发

作者: 五月槐花香 | 来源:发表于2018-06-09 14:11 被阅读1349次

    本文针对一对一的蓝牙进行通讯,适合没有开发过蓝牙的同学来看,也适合大部分物联网简单开发,没有深入蓝牙的开发。对于没有开发过蓝牙的来说,我先说下逻辑。比如先拿自己手机的蓝牙来说,打开蓝牙,列出列表,包含已经配对过的和可用设备, 点击其中一个进行配对,配对完成就可以进行文件传输等通信功能了。所以对于蓝牙开发,大致以下步骤

    1.打开蓝牙

    2.蓝牙扫描,列出可用设备

    3.关闭蓝牙扫描(不关闭会一直扫描)

    4.找到目标蓝牙设备进行连接

    5.连接成功,进行通信

    6.关闭蓝牙释放资源

    接下来我们要根据上面6个步骤进行API的说明,在说明前,我先说明一下

    (1)Service蓝牙功能集合,每一个Service都有一个UUID,

    (2)Characteristic 在service中也有好多个Characteristic 独立数据项,其中也有独立UUID

    上面的两个uuid需要从硬件工程师中获取,这样你才能匹配到你要的。

    (3)BluetoothAdapter 蓝牙的打开关闭等基本操作

    (4)BluetoothDevice 蓝牙设备,扫描到的

    (5)BluetoothGatt 蓝牙连接重连断开连接等操作的类

    (6)BluetoothGattCharacteristic 数据通信操作类,读写等操作

    1.打开蓝牙

    需要权限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    

    BluetoothAdapter 这个类就是蓝牙的基本操作,比如打开关闭等

    初始化蓝牙,得到BluetoothAdapter

    private void initBlueTooth() {
        BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        if (manager != null) {
            bluetoothAdapter = manager.getAdapter();
            if (bluetoothAdapter != null) {
                //蓝牙没有打开
                if (!bluetoothAdapter.isEnabled()) {
                    openBle();
                } else {
                    Toast.makeText(MainActivity.this, "蓝牙已打开", Toast.LENGTH_SHORT).show();
                    scanLeDevice(true);
                }
            } else {
                openBle();
            }
        }
    }
    

    打开蓝牙

       private void openBle() {
       //以下两种方式 第二种方式在onActivityResult处理回调
    //        boolean enable = bluetoothAdapter.enable();//打开蓝牙'直接打开,用户不知权,用于定制系统'
    //        Toast.makeText(MainActivity.this, "正在打开蓝牙", Toast.LENGTH_SHORT).show();
    //        if (enable) {
    //            Log.e("open",enable+"");
    //            new Handler().postDelayed(new Runnable() {
    //                @Override
    //                public void run() {
    //                    scanLeDevice(true);
    //                }
    //            },2000);
    //
    //        }
    ​
            //提示用户正在打开蓝牙
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    ​
    ​
        }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && requestCode == REQUEST_ENABLE_BT) {
            scanLeDevice(true);
        }
    }
    

    2.3.打开或者停止扫描,放在同一个方法中

    /**
     * 打开或者停止扫描
     *
     * @param enable
     */
    private void scanLeDevice(final boolean enable) {
    ​
        if (enable) {
            mScanning = true;
            // 定义一个回调接口供扫描结束处理
            bluetoothAdapter.startLeScan(mLeScanCallback);
            // 预先定义停止蓝牙扫描的时间(因为蓝牙扫描需要消耗较多的电量)
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    bluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);
    ​
        } else {
            mScanning = false;
            bluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }
    

    扫描回调,回调之后得到 BluetoothDevice 的集合,可以放到列表中去

    /**
     * 扫描回调
     */
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
            if (bluetoothDevice.getName() != null) {
                if (!bluetoothDeviceArrayList.contains(bluetoothDevice)) {//去下重
                    bluetoothDeviceArrayList.add(bluetoothDevice);
                }
                Log.e(TAG, "scan--" + bluetoothDevice.getName());
            }
        }
    };
    

    4.5.进行蓝牙连接

    /**
     * 连接蓝牙 参数为目标设备
    /
    public void connectBle(BluetoothDevice bluetoothDevice) {
        mBluetoothDevice = bluetoothDevice;
        if (bluetoothDevice != null) {
            //第二个参数 是否重连
            mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, bluetoothGattCallback);
        }
    ​
    }
    

    连接回调

      /**
         * 蓝牙连接成功回调
         */
    ​
        private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
            @Override
            public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
                super.onPhyUpdate(gatt, txPhy, rxPhy, status);
            }
    ​
            @Override
            public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
                super.onPhyRead(gatt, txPhy, rxPhy, status);
            }
    ​
            //不要执行耗时操作
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                if (newState == BluetoothProfile.STATE_CONNECTED) {//连接成功
                    Log.e(TAG, "onConnectionStateChange 蓝牙连接");
                    //这里要执行以下方法,会在onServicesDiscovered这个方法中回调,如果在                        //onServicesDiscovered方法中回调成功,设备才真正连接起来,正常通信
                    gatt.discoverServices();
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    Log.e(TAG, "onConnectionStateChange 蓝牙断连");
                    if (mBluetoothDevice != null) {
                        //关闭当前新的连接
                        gatt.close();
                        characteristic = null;
                     
                    }
    ​
                }
    ​
            }
    ​
            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                super.onServicesDiscovered(gatt, status);
                //回调之后,设备之间才真正通信连接起来
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    Log.e(TAG, "onServicesDiscovered 蓝牙连接正常");
                    BluetoothGattService service = gatt.getService(UUID.fromString(BleConstantValue.serverUuid));//uuid从硬件工程师获取
                    characteristic = service.getCharacteristic(UUID.fromString(BleConstantValue.charaUuid));
                    gatt.readCharacteristic(characteristic);//执行之后,会执行下面的                onCharacteristicRead的回调方法
                    //设置通知,一般设备给手机发送数据,需要以下监听
                    setCharacteristicNotification(characteristic, true);
                    //耗时操作,如果有ui操作,需要用到handler
                    adapterFreshHandler.sendEmptyMessage(0);
                } else {
                    Log.e(TAG, "onServicesDiscovered 蓝牙连接失败");
                }
    ​
            }
    ​
            //这个方法一般用不到
            @Override
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicRead(gatt, characteristic, status);
                Log.e(TAG, "callback characteristic read status " + status
                        + " in thread " + Thread.currentThread());
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    Log.e(TAG, "read value: " + characteristic.getValue());
                }
    ​
    ​
            }
    ​
            //这个方法是写入数据时的回调,可以和你写入的数据做对比
            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicWrite(gatt, characteristic, status);
                Log.e(TAG, "write value: " + FormatUtil.bytesToHexString(characteristic.getValue()));
            }
    ​
            //设备发出通知时会调用到该接口,蓝牙设备给手机发送数据,在这个方法接收
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                super.onCharacteristicChanged(gatt, characteristic);
                Log.e(TAG, "接收:" + FormatUtil.bytesToHexString(characteristic.getValue()));//byte[]转为16进制字符串
                bleWriteReceiveCallback();
            }
        };
    
    ​
    /**
    * 设置通知
    /
    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
            if (bluetoothAdapter == null || mBluetoothGatt == null) {
                return;
            }
            mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        }
    

    参考写入指令

    /**
     * 写入命令
     */
    private void write(byte[] cmd) {
        if (characteristic != null) {
            // 发出数据
            characteristic.setValue(cmd);
            if (mBluetoothGatt.writeCharacteristic(characteristic)) {
                Log.e(TAG, "写入成功");
            } else {
                Log.e(TAG, "写入失败");
            }
        } else {
            Toast.makeText(MainActivity.this, "蓝牙未连接", Toast.LENGTH_SHORT).show();
        }
    }
    

    6.断开连接 释放资源

    /**
     * 断开蓝牙设备
     */
    public void bleDisConnectDevice(BluetoothDevice device) {
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
        }
    }
    ​
     /**
         * 释放资源 
         */
    ​
        private void releaseResource() {
            Log.e(TAG, "断开蓝牙连接,释放资源");
            if (mBluetoothGatt != null) {
                mBluetoothGatt.disconnect();
                mBluetoothGatt.close();
            }
        }
    

    最后别忘了蓝牙广播:

     /**
         * 注册蓝牙监听广播
         */
        private void registerBleListenerReceiver() {
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
            intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
            registerReceiver(bleListenerReceiver, intentFilter);
        }
    
     /**
         * 蓝牙监听广播接受者
         */
        private BroadcastReceiver bleListenerReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
            //连接的设备信息
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Log.e(TAG, "蓝牙广播" + action);
    
            if (mBluetoothDevice != null && mBluetoothDevice.equals(device)) {
                Log.e(TAG, "收到广播-->是当前连接的蓝牙设备");
    
                if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
                    Log.e(TAG,"广播 蓝牙已经连接");
    
                } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
                    Log.e(TAG,"广播 蓝牙断开连接");
                }
            } else {
                Log.e(TAG, "收到广播-->不是当前连接的蓝牙设备");
            }
    
            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                switch (state) {
                    case BluetoothAdapter.STATE_OFF:
                        Log.e(TAG, "STATE_OFF 蓝牙关闭");
                        adapter.clear();
                        releaseResource();
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        Log.e(TAG, "STATE_TURNING_OFF 蓝牙正在关闭");
                        //停止蓝牙扫描
                        scanLeDevice(false);
                        break;
                    case BluetoothAdapter.STATE_ON:
                        Log.d(TAG, "STATE_ON 蓝牙开启");
                        //扫描蓝牙设备
                        scanLeDevice(true);
                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        Log.e(TAG, "STATE_TURNING_ON 蓝牙正在开启");
                        break;
                }
            }
            }
        };
    

    所有完成,基本的蓝牙操作及通信功能,通信协议需要和蓝牙硬件厂商工程师获取。本文适合蓝牙入门开发,如有错误请指正 https://github.com/Leaderpaking/ble

    相关文章

      网友评论

          本文标题:Android 蓝牙4.0入门开发

          本文链接:https://www.haomeiwen.com/subject/gtpteftx.html