安卓经典蓝牙开发详解

作者: MrHorse1992 | 来源:发表于2018-03-10 13:01 被阅读126次

    前言

    目前比较通用的蓝牙类型主要有两种,一种为手机端使用的经典蓝牙3.0,一种是当前比较流行在穿戴设备上的低功耗蓝牙,即常说的BLE蓝牙。关于BLE蓝牙开发可以查看另外一篇文章
    安卓BLE蓝牙开发详解

    经典蓝牙采用服务器客户端模式进行通信,手机端既可以是服务端也可以是客户端。
    安卓手机经典蓝牙开发通信流程如下:

    添加权限

    <!-- 蓝牙权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    为适配安卓6.0以及以上版本需要添加一个模糊定位的权限
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    

    打开蓝牙

    // 询问打开蓝牙
    if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(
                BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, 1);
    }
        
    // 申请打开蓝牙回调
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if (resultCode == RESULT_OK) {
                Toast.makeText(this, "蓝牙已经开启", Toast.LENGTH_SHORT).show();
            } else if (resultCode == RESULT_CANCELED) {
                Toast.makeText(this, "没有蓝牙权限", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }
    

    BluetoothAdapter类封装了关于安卓系统蓝牙的操作。其获取方式为:

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
        // 设备不支持蓝牙
    }
    
    搜索蓝牙设备

    安卓对于经典蓝牙的搜索采用注册广播的方式实现。

    // 注册扫描监听器,一般写在onCreate()函数中执行
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_FOUND);
    registerReceiver(searchReceiver, filter);
    
    // 监听器监听蓝牙扫描结果
    BroadcastReceiver searchReceiver = new BroadcastReceiver() {
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            String action = intent.getAction();
            BluetoothDevice device = intent
                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    if (device.getName() == null) {     
                        return;
                    } 
                
                    if(device.getName().equals("目标设备蓝牙名")) {
                        targetDevice = device;
                    }
                }
            }
        }
    };
    //启动搜索周边设备
    if (mBluetoothAdapter.isDiscovering()) {
        mBluetoothAdapter.cancelDiscovery();
    }
    mBluetoothAdapter.startDiscovery();
    

    注:当注册广播后需要在销毁界面时调用unregisterReceiver(searchReceiver);解除注册防止内存泄露。

    连接设备

    当在广播监听结果中获取到目标设备之后,进行连接设备。安卓启动连接的方式通常需启动服务端线程作为监听,然后创建客户端线程进行连接。连接方法如下:

        //启动蓝牙连接
        public void connect(BluetoothDevice targetDevice) {
            
            this.targetDevice = targetDevice;
                    
            //启动服务端线程
            serverThread = new ServerThread();  
            serverThread.start();
            
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                
                e.printStackTrace();
            }
            //启动客户端线程
            clientThread = new ClientThread();  
            clientThread.start();
                        
        }
        
        
    // 服务端线程
    private class ServerThread extends Thread {
    
        public void run() {
            try {
                // 创建一个蓝牙服务器 参数分别:服务器名称、UUID
                mserverSocket = mBluetoothAdapter
                        .listenUsingRfcommWithServiceRecord(
                                "btspp",
                                UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    
                // 接受客户端的连接请求
                socket = mserverSocket.accept();
                
            } catch (Exception e) {
                
                e.printStackTrace();
            }
        }
        
    }
    
    // 客户端线程
    private class ClientThread extends Thread {
        
        public void run() {
            try {
    
                Thread.sleep(500);
    
                socket = targetDevice.createRfcommSocketToServiceRecord(UUID
                        .fromString("00001101-0000-1000-8000-00805F9B34FB"));
                //开始连接
                socket.connect();
                                
                //连接成功后,启动数据通信线程
                isReading = true;
                new ReadThread().start();
            } catch (Exception e) {
    
            }
        }
    }
    

    通信过程

    安卓经典蓝牙的通信采用Socket通信机制。Socket通信线程如下:

    private class ReadThread extends Thread {
        
        public void run() {
            Log.e("TAG", "开启通信线程");
            byte[] buffer = new byte[1024];
            int bytes;
            in = null;
            try {
                in  = socket.getInputStream();
                out = socket.getOutputStream();
            } catch (Exception e) {
                Log.e("TAG", "获取流出错");
            }           
            while (isReading) {
                try {
                    if ((bytes = in.read(buffer)) > 0) {
    
                        //读取到的数据值
                        byte[] rece = new byte[bytes];
                
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    try {
                        Log.e("关闭流", "");
                        in.close();
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                        
                    break;
                }
            }
            
            Log.e(TAG, "DataRead线程关闭");
        }
    }
    

    Socket通信线程在没有断开连接之前一直在Socket流中读取数据。通常在与设备通信过程中不仅要读取设备数据,同时需要向设备写入数据,发送数据的方法如下:

    //发送数据方法
    public void sendData(byte[] cmd) {
        if (out != null) {
            try {
                out.write(cmd);
            } catch (IOException e) {
                Log.e(TAG, "写入失败");
                e.printStackTrace();
            }
        }else {
            Log.e(TAG, "建立连接失败");
        }       
    }
    

    结语

    通过以上流程可以基本完成与经典蓝牙设备的通信过程。本文采用的是手机端作为服务端,周边蓝牙设备作为客户端的方式。若文章中存在错误,还请指出。

    相关文章

      网友评论

        本文标题:安卓经典蓝牙开发详解

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