3、使用蓝牙之前,首先要检查当前手机是否支持蓝牙。如果支持蓝牙,检查手机蓝牙是否已开启。如果没有开启,则需要先打开蓝牙。打开手机蓝牙,有两种方式,推荐使用第二种打开方式。

private void initBluetooth() {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter == null){
            Toast.makeText(this, "当前手机设备不支持蓝牙", Toast.LENGTH_SHORT).show();
        }else{
            //手机设备支持蓝牙,判断蓝牙是否已开启
            if(bluetoothAdapter.isEnabled()){
                Toast.makeText(this, "手机蓝牙已开启", Toast.LENGTH_SHORT).show();
            }else{
                //蓝牙没有打开,去打开蓝牙。推荐使用第二种打开蓝牙方式
                //第一种方式:直接打开手机蓝牙,没有任何提示
//                bluetoothAdapter.enable();  //BLUETOOTH_ADMIN权限
                //第二种方式:友好提示用户打开蓝牙
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivity(enableBtIntent);
            }
        }
    }

4、确保手机蓝牙已打开,就可以开始搜索设备。搜索设备只需调用startDiscovery()方法,但搜索的结果是通过广播来获取的,所以,还需要定义广播来获取搜索到的设备。

(1)搜索设备

private void searchBtDevice() {
        if(bluetoothAdapter.isDiscovering()){ //当前正在搜索设备...
            return;
        }
        //开始搜索
        bluetoothAdapter.startDiscovery();
    }

(2)自定义广播接收器,接收搜索到的设备。

/**
     * 蓝牙广播接收器
     */
    private static class BtBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_STARTED)) { //开启搜索
                if (onDeviceSearchListener != null) {
                    onDeviceSearchListener.onDiscoveryStart();  //开启搜索回调
                }

            } else if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {//完成搜素
                if (onDeviceSearchListener != null) {
                    onDeviceSearchListener.onDiscoveryStop();  //完成搜素回调
                }

            } else if (TextUtils.equals(action, BluetoothDevice.ACTION_FOUND)) {  //3.0搜索到设备
                //蓝牙设备
                BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                //信号强度
                int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);

                Log.d(TAG, "扫描到设备:" + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
                if (onDeviceSearchListener != null) {
                    onDeviceSearchListener.onDeviceFound(bluetoothDevice,rssi);  //3.0搜素到设备回调
                }
            }
        }

        /**
         * 蓝牙设备搜索监听者
         * 1、开启搜索
         * 2、完成搜索
         * 3、搜索到设备
         */
        public interface OnDeviceSearchListener {
            void onDiscoveryStart();   //开启搜索
            void onDiscoveryStop();    //完成搜索
            void onDeviceFound(BluetoothDevice bluetoothDevice, int rssi);  //搜索到设备
        }

        private OnDeviceSearchListener onDeviceSearchListener;

        public void setOnDeviceSearchListener(OnDeviceSearchListener onDeviceSearchListener) {
            this.OnDeviceSearchListener= onDeviceSearchListener;
        }
    }

(3)注册广播接收器

private void initBtBroadcast() {
        //注册广播接收
        btBroadcastReceiver = new BtBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); //开始扫描
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//搜索到设备
        registerReceiver(btBroadcastReceiver,intentFilter);

    }

(4)注册过广播之后,要记得在onDestroy()中注销广播

@Override
    protected void onDestroy() {
        super.onDestroy();

        //注销广播接收
        unregisterReceiver(btBroadcastReceiver);
    }

5、搜索到目标设备之后,就可以与蓝牙设备建立连接。

(1)发起连接

 /**
     * 开始连接设备
     * @param bluetoothDevice   蓝牙设备
     * @param uuid               发起连接的UUID
     * @param conOutTime        连接超时时间
     */
    public void startConnectDevice(final BluetoothDevice bluetoothDevice, String uuid, long conOutTime){
        if(bluetoothDevice == null){
            Log.e(TAG,"startConnectDevice-->bluetoothDevice == null");
            return;
        }
        if(bluetoothAdapter == null){
            Log.e(TAG,"startConnectDevice-->bluetooth3Adapter == null");
            return;
        }
        //发起连接
        cOnnectThread= new ConnectThread(bluetoothAdapter,curBluetoothDevice,uuid);
        connectThread.setOnBluetoothConnectListener(new ConnectThread.OnBluetoothConnectListener() {
            @Override
            public void onStartConn() {
                Log.d(TAG,"startConnectDevice-->开始连接..." + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
            }


            @Override
            public void onConnSuccess(BluetoothSocket bluetoothSocket) {
                //移除连接超时
                mHandler.removeCallbacks(connectOuttimeRunnable);
                Log.d(TAG,"startConnectDevice-->移除连接超时");
                Log.w(TAG,"startConnectDevice-->连接成功");

                Message message = new Message();
                message.what = CONNECT_SUCCESS;
                mHandler.sendMessage(message);

                //标记当前连接状态为true
                curCOnnState= true;
                //管理连接,收发数据
                managerConnectSendReceiveData(bluetoothSocket);
            }

            @Override
            public void onConnFailure(String errorMsg) {
                Log.e(TAG,"startConnectDevice-->" + errorMsg);

                Message message = new Message();
                message.what = CONNECT_FAILURE;
                mHandler.sendMessage(message);

                //标记当前连接状态为false
                curCOnnState= false;

                //断开管理连接
                clearConnectedThread();
            }
        });

        connectThread.start();
        //设置连接超时时间
        mHandler.postDelayed(connectOuttimeRunnable,conOutTime);

    }

    //连接超时
    private Runnable cOnnectOuttimeRunnable= new Runnable() {
        @Override
        public void run() {
            Log.e(TAG,"startConnectDevice-->连接超时" );

            Message message = new Message();
            message.what = CONNECT_FAILURE;
            mHandler.sendMessage(message);

            //标记当前连接状态为false
            curCOnnState= false;
            //断开管理连接
            clearConnectedThread();
        }
    };

(2)管理连接,数据收发

 managerConnectSendReceiveData()方法中,connectedThread对象进行数据发送结果、接收结果监听。

/**
     * 管理已建立的连接,收发数据
     * @param bluetoothSocket   已建立的连接
     */
    public void managerConnectSendReceiveData(BluetoothSocket bluetoothSocket){
        //管理已有连接
        cOnnectedThread= new ConnectedThread(bluetoothSocket);
        connectedThread.start();
        connectedThread.setOnSendReceiveDataListener(new ConnectedThread.OnSendReceiveDataListener() {
            @Override
            public void onSendDataSuccess(byte[] data) {
                Log.w(TAG,"发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length));
                Message message = new Message();
                message.what = SEND_SUCCESS;
                message.obj = "发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length);
                mHandler.sendMessage(message);
            }

            @Override
            public void onSendDataError(byte[] data,String errorMsg) {
                Log.e(TAG,"发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length));
                Message message = new Message();
                message.what = SEND_FAILURE;
                message.obj = "发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length);
                mHandler.sendMessage(message);
            }

            @Override
            public void onReceiveDataSuccess(byte[] buffer) {
                Log.w(TAG,"成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length));
                Message message = new Message();
                message.what = RECEIVE_SUCCESS;
                message.obj = "成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length);
                mHandler.sendMessage(message);
            }

            @Override
            public void onReceiveDataError(String errorMsg) {
                Log.e(TAG,"接收数据出错:" + errorMsg);
                Message message = new Message();
                message.what = RECEIVE_FAILURE;
                message.obj = "接收数据出错:" + errorMsg;
                mHandler.sendMessage(message);
            }
        });
    }

 sendData()方法中,connectedThread对象发送数据。

 /**
     * 发送数据
     * @param data      要发送的数据 字符串
     * @param isHex     是否是16进制字符串
     * @return   true 发送成功  false 发送失败
     */
    public boolean sendData(String data,boolean isHex){
        if(cOnnectedThread== null){
            Log.e(TAG,"sendData:string -->cOnnectedThread== null");
            return false;
        }
        if(data == null || data.length() == 0){
            Log.e(TAG,"sendData:string-->要发送的数据为空");
            return false;
        }

        if(isHex){  //是16进制字符串
            data.replace(" ","");  //取消空格
            //检查16进制数据是否合法
            if(data.length() % 2 != 0){
                //不合法,最后一位自动填充0
                String lasts = "0" + data.charAt(data.length() - 1);
                data = data.substring(0,data.length() - 2) + lasts;
            }
            Log.d(TAG,"sendData:string -->准备写入:" + data);  //加空格显示
            return connectedThread.write(hexString2Bytes(data));
        }

        //普通字符串
        Log.d(TAG,"sendData:string -->准备写入:" + data);
        return connectedThread.write(data.getBytes());
    }

6、与蓝牙设备通讯结束之后,可与蓝牙设备断开连接。

/**
     * 断开已有的连接
     */
    public void clearConnectedThread(){
        Log.d(TAG,"clearConnectedThread-->即将断开");

        //connectedThread断开已有连接
        if(cOnnectedThread== null){
            Log.e(TAG,"clearConnectedThread-->cOnnectedThread== null");
            return;
        }
        connectedThread.terminalClose(connectThread);

        //等待线程运行完后再断开
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                connectedThread.cancel();  //释放连接

                cOnnectedThread= null;
            }
        },10);

        Log.w(TAG,"clearConnectedThread-->成功断开连接");
        Message message = new Message();
        message.what = DISCONNECT_SUCCESS;
        mHandler.sendMessage(message);

    }

7、项目演示

(1)扫描到设备,点击“连接”按钮, 会在“搜索”按钮下方显示连接结果 。注意经典蓝牙连接是,第一次连接时会有弹出一个配对框,这个具体配对方式是蓝牙设备开发人员设置的。

(2)手机给蓝牙设备(设备名为:BTyqy)发送数据成功之后,蓝牙设备把接收到的数据再回发送给手机。

(3)断开连接。点击“断开”按钮, 会在“搜索”按钮下方显示断开结果 。

四、Demo案例源码地址:

注意:源码中没有进行位置权限的静态声明以及动态申请,小伙伴们使用时需要自己添加,谢谢!

CSDN:https://download.csdn.net/download/qq_38950819/11615060

码云:https://gitee.com/lilium_foliage/Android-Bluetooth