Android 蓝牙开发初学

    最近工作中用到了蓝牙方面的知识,所以写此博客记录一下。

一、蓝牙开发需要用到的API都在 android.bluetooth包下   

BluetoothAdapter

表示本地蓝牙适配器(蓝牙无线装置)。 BluetoothAdapter 是所有蓝牙交互的入口点。 利用它可以发现其他蓝牙设备,查询绑定(配对)设备的列表,使用已知的 MAC 地址实例化 BluetoothDevice,以及创建 BluetoothServerSocket 以侦听来自其他设备的通信。

BluetoothDevice

表示远程蓝牙设备。利用它可以通过 BluetoothSocket 请求与某个远程设备建立连接,或查询有关该设备的信息,例如设备的名称、地址、类和绑定状态等。

BluetoothSocket

表示蓝牙套接字接口(与 TCP Socket 相似)。这是允许应用通过 InputStream 和 OutputStream 与其他蓝牙设备交换数据的连接点。

BluetoothServerSocket

表示用于侦听传入请求的开放服务器套接字(类似于 TCP ServerSocket)。 要连接两台 Android 设备,其中一台设备必须使用此类开放一个服务器套接字。 当一台远程蓝牙设备向此设备发出连接请求时,BluetoothServerSocket 将会在接受连接后返回已连接的 BluetoothSocket

BluetoothClass

描述蓝牙设备的一般特征和功能。 这是一组只读属性,用于定义设备的主要和次要设备类及其服务。 不过,它不能可靠地描述设备支持的所有蓝牙配置文件和服务,而是适合作为设备类型提示。

BluetoothProfile

表示蓝牙配置文件的接口。 蓝牙配置文件是适用于设备间蓝牙通信的无线接口规范。

BluetoothHeadset

提供蓝牙耳机支持,以便与手机配合使用。

BluetoothA2dp

定义高质量音频如何通过蓝牙连接和流式传输,从一台设备传输到另一台设备。“A2DP”代表高级音频分发配置文件。

BluetoothHealth

表示用于控制蓝牙服务的健康设备配置文件代理。

BluetoothHealthCallback

用于实现 BluetoothHealth 回调的抽象类。您必须扩展此类并实现回调方法,以接收关于应用注册状态和蓝牙通道状态变化的更新内容。

BluetoothHealthAppConfiguration

表示第三方蓝牙健康应用注册的应用配置,以便与远程蓝牙健康设备通信。

BluetoothProfile.ServiceListener

在 BluetoothProfile IPC 客户端连接到服务(即,运行特定配置文件的内部服务)或断开服务连接时向其发送通知的接口

官方文档地址:https://developer.android.com/guide/topics/connectivity/bluetooth,有兴趣可以去看看,上面说的很详细。

二 、要用到的权限

6.0以下

<!-- 使用蓝牙的权限 -->

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

<!-- 扫描蓝牙设备或者操作蓝牙设置 -->

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

6.0以上

<!-- 使用蓝牙的权限 -->

<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" />

<!--精准定位权限,仅作用于6.0+-->

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

三、开发工作

1. 流程:动态权限检查---->获取蓝牙适配器---->启用蓝牙---->查找设备---->配对与连接

流程大概就是这样,权限检查就不说了,应该都会,不会可以自己找找相关博客看下。

2. 首先打开蓝牙,打开蓝牙大概有两种方式

  • 2.1 提示用户跳转到设置界面打开
if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
  • 2.2  不提示静默打开
if (mBluetoothAdapter.isEnabled ()){
            mBluetoothAdapter.enable ();    
   }
  • 2.3 查询已配对的蓝牙
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
}
  • 2.4 扫描设备
/**
     * 开始蓝牙扫描
     *
     * @return
     */
    public boolean startScan() {
        if (!isBlueEnable()) {
            Log.e(TAG, "Bluetooth not enable!");
            return false;
        }
        //当前是否在扫描,如果是就取消当前的扫描,重新扫描
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        //此方法是个异步操作,一般搜索12秒
        return mBluetoothAdapter.startDiscovery();
    }

注册广播,通过广播接收蓝牙信息,我这里是有一个回调接口

 /**
     * 注册广播
     */
    public void registerReceiver() {
        IntentFilter filter1=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        IntentFilter filter2=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        IntentFilter filter3=new IntentFilter (BluetoothDevice.ACTION_FOUND);
        registerReceiver (scanBlueReceiver, filter1);
        registerReceiver (scanBlueReceiver, filter2);
        registerReceiver (scanBlueReceiver, filter3);
    }
public class ScanBlueReceiver extends BroadcastReceiver {
    private static final String TAG = ScanBlueReceiver.class.getName();
    private ScanBlueCallBack callBack;

    public ScanBlueReceiver(ScanBlueCallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action:" + action);
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        switch (action) {
            case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                Log.d(TAG, "开始扫描...");
                callBack.onScanStarted();
                break;
            case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                Log.d(TAG, "结束扫描...");
                callBack.onScanFinished();
                break;
            case BluetoothDevice.ACTION_FOUND:
                Log.d(TAG, "发现设备...");
                callBack.onScanning(device);
                break;
        }
    }
}

2.5 蓝牙配对

首先需要用到 ClsUtils 类,这个网上都有,我就不贴出来了,感谢大神们的奉献。

蓝牙配对需要和目标设备建立连接,这里需要用到上文说的BluetoothSocket

/**
 * 蓝牙连接线程
 */
public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {

    private static final String TAG = ConnectBlueTask.class.getName();
    private BluetoothDevice bluetoothDevice;
    private ConnectBlueCallBack callBack;

    public ConnectBlueTask(ConnectBlueCallBack callBack){
        this.callBack = callBack;
    }
    UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
    @Override
    protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
        bluetoothDevice = bluetoothDevices[0];
        Log.e (TAG, "doInBackground: "+bluetoothDevice.getAddress ());
        BluetoothSocket socket = null;
        try{
            Log.d(TAG,"开始连接socket,uuid:" );
            socket = bluetoothDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
            if (socket != null && !socket.isConnected()){
                socket.connect();
            }
        }catch (IOException e){
            Log.e(TAG,"socket连接失败");
            try {
                socket =(BluetoothSocket) bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(bluetoothDevice,1);
                socket.connect();
               // socket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace ();
            } catch (InvocationTargetException e1) {
                e1.printStackTrace ();
            } catch (NoSuchMethodException e1) {
                e1.printStackTrace ();
            }
        }
        return socket;
    }
    @Override
    protected void onPreExecute() {
        Log.d(TAG,"开始连接");
        if (callBack != null) callBack.onStartConnect();
    }

    @Override
    protected void onPostExecute(BluetoothSocket bluetoothSocket) {
        if (bluetoothSocket != null && bluetoothSocket.isConnected()){
            Log.d(TAG,"连接成功");
            if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
        }else {
            Log.d(TAG,"连接失败");
            if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败");
        }
    }
}

同样需要注册相应广播,用来获取配对状态

public void pinRegisterReceiver() {
        IntentFilter filter4=new IntentFilter (BluetoothDevice.ACTION_PAIRING_REQUEST);
        IntentFilter filter5=new IntentFilter (BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver (pinBlueReceiver, filter4);
        registerReceiver (pinBlueReceiver, filter5);
    }
 private String pin="0000";  // 此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
    private static final String TAG=PinBlueReceiver.class.getName ();
    private PinBlueCallBack callBack;

    public PinBlueReceiver(PinBlueCallBack callBack) {
        this.callBack=callBack;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action=intent.getAction ();
        Log.d (TAG, "action:" + action);
        BluetoothDevice device=intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals (action)) {
            try {
                callBack.onBondRequest ();
                // 开始配对
                boolean ret=ClsUtils.setPin (device.getClass (), device, pin);
                abortBroadcast ();// 将广播终止,否则会出现一个一闪而过的配对框。
                //Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
                //Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace ();
            }
        } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals (action)) {
            switch (device.getBondState ()) {
                case BluetoothDevice.BOND_NONE:
                    Log.d (TAG, "取消配对");
                    callBack.onBondFail (device);
                    break;
                case BluetoothDevice.BOND_BONDING:
                    Log.d (TAG, "配对中");
                    callBack.onBonding (device);
                    break;
                case BluetoothDevice.BOND_BONDED:
                    Log.d (TAG, "配对成功");
                    callBack.onBondSuccess (device);
                    break;
            }
        }
    }

大概就是这样。。

参考:https://blog.csdn.net/zqf_888/article/details/81060606 这篇文章写得很好,建议观看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章