Android Ble从模式(Peripheral)开发

    ble分主模式和从模式,android从API 18(4.0)开始支持BLE功能的主模式,但是从API 21(5.0)才开始支持从模式,ble的应用越来越广泛,今天这里我们来讲讲Ble的从模式的开发。

    主模式的开发我已经讲过了,需要看到的请移步 Android蓝牙4.0Ble主模式开发

    从模式的工作流程大概是这样的:从机打开蓝牙->从机发送带有service和characteristic的广播->主机连接上从机-->主机和从机通过约定好的service下的characteristic进行通讯;

    进行ble开发的时候,我们需要有以下的权限

    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher.  -->
    <uses-feature android:name="android.hardware.location.gps" />
    <uses-feature android:name ="android.hardware.bluetooth_le" android:required ="true"/>
一、打开蓝牙

    这一步相信很多人都会了,我就直接上打开/关闭蓝牙的代码了

/**
     * 打开/关闭蓝牙
     *
     * @param context:上下文
     * @param enable:是否打开 true=打开  false=关闭
     * */
    private void changeBluetooth(Context context,boolean enable){
        //先获取BluetoothManager
        BluetoothManager bluetoothManager =
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        //通过BluetoothManager获取BluetoothAdapter  通过BluetoothAdapter才能去操作蓝牙
        BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
        if(mBluetoothAdapter != null){
            if(enable){
                toEnable(mBluetoothAdapter);
            }else{
                toDisable(mBluetoothAdapter);
            }
        }
    }


    /**
     * 打开蓝牙
     * */
    private void toEnable(BluetoothAdapter mBluetoothAdapter){
        try {
            if(mBluetoothAdapter.isEnabled()){
                return ;
            }
            //使用反射的方法开发蓝牙
            for(Method temp:Class.forName(mBluetoothAdapter.getClass().getName()).getMethods()){
                if(temp.getName().equals("enableNoAutoConnect")){
                     temp.invoke(mBluetoothAdapter);
                }
            }
        } catch (Exception e) {
            //反射调用失败就启动通过enable()启动;
            mBluetoothAdapter.enable();
            e.printStackTrace();
        }

    }

    /**
     * 关闭蓝牙
     * */
    private void toDisable(BluetoothAdapter mBluetoothAdapter){
        if(mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()){
            mBluetoothAdapter.disable();
        }
    }
二、从机发送带有service和characteristic的广播

    这一步分两步走,先开启广播,开启成功后再添加需要的service和characteristic;

    a、开启广播
   /**
     * 开启广播的结果callback
     * */
    private AdvertiseCallback callback = new AdvertiseCallback() {

        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            Log.d(TAG, "BLE advertisement added successfully");
        }

        @Override
        public void onStartFailure(int errorCode) {
            Log.e(TAG, "Failed to add BLE advertisement, reason: " + errorCode);
        }
    };

    
     /**
     *开启广播
     *
     *@param bleName:ble设备的名称
     * @param serviceData:要放到scanrecord中的数据
     *@param parcelUUID:要放到scanrecord中的UUID
     *@param mBluetoothAdapter:操作蓝牙用的BluetoothAdapter
     * */
    public void startBluetoothLeAdvertiser(String bleName,byte[] serviceData, UUID parcelUUID,BluetoothAdapter mBluetoothAdapter) {
        //广播设置
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setConnectable(true) //是否被连接
                .setTimeout(0)        //超时时间
                .build();

        //广播数据设置
        AdvertiseData advertiseData = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)    //是否在广播中携带设备的名称
                .setIncludeTxPowerLevel(true)  //是否在广播中携带信号强度
                .build();
        //扫描回应的广播设置
        AdvertiseData scanResponseData = new AdvertiseData.Builder()
                .setIncludeTxPowerLevel(true)  //是否在广播中携带设备的名称
                .addServiceData(new ParcelUuid(parcelUUID), serviceData) //在scanrecord中添加的数据
                .build();

        //设置BLE设备的名称
        mBluetoothAdapter.setName(bleName);
        //开启广播
        BluetoothLeAdvertiser bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, callback);

    }

    开启广播调用的是BluetoothLeAdvertiser的startAdvertising方法,他需要传入一个AdvertiseSettings(我们理解为从模式的系统设置)、两个AdvertiseData(我们可以理解为广播内容的配置)、一个AdvertiseCallback

    AdvertiseSettings用来设置ble的一些配置,比如说是否可以被连接(setConnectable)、超时时间(setTimeout)、模式(setAdvertiseMode)、发射功率(setTxPowerLevel)等。

    两个AdvertiseData中,advertiseData是用来配置广播中携带的信息,比如说是否携带名称(setIncludeDeviceName),如果不携带名称的话,扫描的时候就不会显示出你设置的名称。scanResponseData用来配置被扫描到的时候返回出去的信息,比如说scanrecord中的数据(addServiceData)。

    AdvertiseCallback用来返回开启广播的结果的分别有onStartSuccess(成功时调用)、onStartFailure(失败时调用,并返回错误码)。


    b、添加需要的service和characteristic

    这一步一定得是在开启广播的AdvertiseCallback的onStartSuccess被回调了才可以进行,因为添加service和characteristic需要先成功开启广播,如果onStartFailure被回调了,就根据errorCode去查下原因,解决它。

    好,先来看下代码



/**
     * setvice事件的回调
     */
    private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() {

        /**
         * 1.连接状态发生变化时
         * @param device
         * @param status
         * @param newState
         */
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));

            super.onConnectionStateChange(device, status, newState);
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);
            Log.e(TAG, String.format("onServiceAdded:status = %s", status));
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            Log.e(TAG, String.format("onCharacteristicReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));

            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
//            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
        }

        /**
         * 3. onCharacteristicWriteRequest,接收具体的字节
         * @param device
         * @param requestId
         * @param characteristic
         * @param preparedWrite
         * @param responseNeeded
         * @param offset
         * @param requestBytes
         */
        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(requestBytes)));
            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, requestBytes);
            //4.处理响应内容
            onResponseToClient(requestBytes, device, requestId, characteristic);
        }

        /**
         * 2.描述被写入时,在这里执行 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS...  收,触发 onCharacteristicWriteRequest
         * @param device
         * @param requestId
         * @param descriptor
         * @param preparedWrite
         * @param responseNeeded
         * @param offset
         * @param value
         */
        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            Log.e(TAG, String.format("2.onDescriptorWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("2.onDescriptorWriteRequest:requestId = %s, preparedWrite = %s, responseNeeded = %s, offset = %s, value = %s,", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(value)));


            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
        }

        /**
         * 5.特征被读取。当回复响应成功后,客户端会读取然后触发本方法
         * @param device
         * @param requestId
         * @param offset
         * @param descriptor
         */
        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            Log.e(TAG, String.format("onDescriptorReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("onDescriptorReadRequest:requestId = %s", requestId));

            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            Log.e(TAG, String.format("5.onNotificationSent:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("5.onNotificationSent:status = %s", status));
        }

        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            super.onMtuChanged(device, mtu);
            Log.e(TAG, String.format("onMtuChanged:mtu = %s", mtu));
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);
            Log.e(TAG, String.format("onExecuteWrite:requestId = %s", requestId));
        }
    };

    /**
     * 添加ble的service
     *
     *@param serviceInfo:需要添加服务列表
     * */
    private void addServices(BluetoothGattServiceInfo...serviceInfo) {
        BluetoothGattServer bluetoothGattServer = bluetoothManager.openGattServer(context, bluetoothGattServerCallback);

        for(BluetoothGattServiceInfo temp : serviceInfo){
            BluetoothGattService service_temp = new BluetoothGattService(temp.getUuid(), temp.getServiceType());

            for(BluetoothGattCharacteristicInfo temp_CharacteristicInfo : temp.getCharacteristicInfos()){

                BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(temp_CharacteristicInfo.getUuid(), temp_CharacteristicInfo.getProperties(), temp_CharacteristicInfo.getPermissions());
                BluetoothGattDescriptorInfo descriptorInfo = temp_CharacteristicInfo.getBluetoothGattDescriptorInfo();
                if(descriptorInfo != null){
                    if(descriptorInfo != null){
                        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(descriptorInfo.getUuid(), descriptorInfo.permissions);
                        characteristic.addDescriptor(descriptor);
                    }
                }

                service_temp.addCharacteristic(characteristic);
            }

            bluetoothGattServer.addService(service_temp);
        }
    }

    这里用到的BluetoothGattServiceInfo其实我封装好的service的一个实体类,方便添加service。

    BluetoothGattServiceInfo
import java.util.UUID;

/**
 * Created by 601042 on 2018/6/28.
 *
 * ble的service信息
 */

public class BluetoothGattServiceInfo {

    //Service的UUID
    private UUID uuid;
    //服务的类型 SERVICE_TYPE_PRIMARY /SERVICE_TYPE_SECONDARY
    private int serviceType;
    //该service下的characteristic
    private BluetoothGattCharacteristicInfo[] characteristicInfos;



    public BluetoothGattServiceInfo(){

    }
    public BluetoothGattServiceInfo(UUID uuid,int serviceType,BluetoothGattCharacteristicInfo[] characteristicInfos){
        this.uuid = uuid;
        this.serviceType = serviceType;
        this.characteristicInfos = characteristicInfos;

    }

    public UUID getUuid() {
        return uuid;
    }

    public void setUuid(UUID uuid) {
        this.uuid = uuid;
    }

    public int getServiceType() {
        return serviceType;
    }

    public void setServiceType(int serviceType) {
        this.serviceType = serviceType;
    }

    public BluetoothGattCharacteristicInfo[] getCharacteristicInfos() {
        return characteristicInfos;
    }

    public void setCharacteristicInfos(BluetoothGattCharacteristicInfo[] characteristicInfos) {
        this.characteristicInfos = characteristicInfos;
    }


}
    BluetoothGattCharacteristicInfo
import java.util.UUID;

/**
 * Created by 601042 on 2018/6/28.
 *
 * ble的service的Characteristic信息
 */

public class BluetoothGattCharacteristicInfo {

    //Characteristic的UUID
    private UUID uuid;
    //Characteristic的属性
    private int properties;
    //Characteristic的权限
    private int permissions;
    //该service下的Descriptor
    private  BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo;

    public BluetoothGattCharacteristicInfo(UUID uuid,int properties,int permissions,BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo){
        this.uuid = uuid;
        this.properties = properties;
        this.permissions = permissions;
        this.bluetoothGattDescriptorInfo = bluetoothGattDescriptorInfo;
    }

    public UUID getUuid() {
        return uuid;
    }

    public void setUuid(UUID uuid) {
        this.uuid = uuid;
    }

    public int getProperties() {
        return properties;
    }

    public void setProperties(int properties) {
        this.properties = properties;
    }

    public int getPermissions() {
        return permissions;
    }

    public void setPermissions(int permissions) {
        this.permissions = permissions;
    }

    public BluetoothGattDescriptorInfo getBluetoothGattDescriptorInfo() {
        return bluetoothGattDescriptorInfo;
    }

    public void setBluetoothGattDescriptorInfo(BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo) {
        this.bluetoothGattDescriptorInfo = bluetoothGattDescriptorInfo;
    }
}
    BluetoothGattDescriptorInfo
import java.util.UUID;

/**
 * Created by 601042 on 2018/6/28.
 *
 * ble的service的Characteristic的Descriptor信息
 */

public class BluetoothGattDescriptorInfo {

    //描述者的UUID
    private UUID uuid;
    //描述者的权限
    int permissions;

    public BluetoothGattDescriptorInfo(UUID uuid,int permissions){
        this.uuid = uuid;
        this.permissions = permissions;
    }

    public UUID getUuid() {
        return uuid;
    }

    public void setUuid(UUID uuid) {
        this.uuid = uuid;
    }

    public int getPermissions() {
        return permissions;
    }

    public void setPermissions(int permissions) {
        this.permissions = permissions;
    }
}

     characteristic是属于service里面的,所以添加service和characteristic流程是先过去gatt的服务BluetoothGattServer,获取到了之后直接实例化好要添加进去的BluetoothGattService

    实例化的时候构造方法需要传入该service的uuid(自己约定好,这个UUID实际是需要买的,但是国内大家都随便用)和类型(BluetoothGattService.SERVICE_TYPE_PRIMARY / BluetoothGattService.SERVICE_TYPE_SECONDARY   分别是主要服务和次要服务)。

    实例化完了BluetoothGattService之后就需要向其中加入characteristic即BluetoothGattCharacteristicBluetoothGattCharacteristic实例化的时候构造方法需要传入该characteristic的uuid(自己约定好)、属性(properties)和权限(permissions)。属性和权限的具体类型大家直接看API文档吧,太多就不说了,这里我们需要注意的是,属性就是表明这个characteristic是干什么的,权限就是这个characteristic有的权限,所以一般当属性设置他是一个可读的(BluetoothGattCharacteristic.PROPERTY_READ)的时候,权限也要给相应的可读的权限(BluetoothGattCharacteristic.PERMISSION_READ)给他。有一点要注意的就是:当设置的BluetoothGattCharacteristic是BluetoothGattCharacteristic.PROPERTY_NOTIFY是,需要给BluetoothGattCharacteristic添加一个描述者BluetoothGattDescriptor,描述者同样需要知道UUID和权限,调用BluetoothGattCharacteristic的addDescriptor方法添加进入,描述者的UUID现在都在用"00002902-0000-1000-8000-00805f9b34fb".

    实例化完了BluetoothGattCharacteristic之后就调用BluetoothGattService的addCharacteristic方法添加到BluetoothGattCharacteristic。实例化完了BluetoothGattService之后就调用BluetoothGattServer的addService方法添加到BluetoothGattServer。

    这就完成了添加service和characteristic,现在其他的主机就可以扫描到你的设备了,且设备里面有你添加好的service和characteristic,可以使用这些characteristic进行通讯了。

三、主机和从机通过约定好的service下的characteristic进行通讯

    ble的通讯方式是通过characteristic来进行的, characteristic的属性有三种:可读、可写、可通知。一个characteristic可以同时具备多种属性。现在从机一般都是通过可通知的characteristic,发送数据给主机,这样的好处就是不用主机一直读可读的characteristic。

    还记得前面添加service的使用到的BluetoothGattServerCallback吗,当设备状态发送变化时,会回调其中特征的方法,比如说当有主机连接上从机之后,就会调用onConnectionStateChange(BluetoothDevice device, int status, int newState) 这个方法

 /**
         * 1.连接状态发生变化时
         * @param device :连接的设备
         * @param status :操作状态(0是成功,其他值为失败)
         * @param newState :当前连接状态(2是已连接 0是已断开)
         */
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));

            super.onConnectionStateChange(device, status, newState);
        }

    当主机通过可写的characteristic向从机写出数据的时,会调用onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) 

  /**
         * 3. onCharacteristicWriteRequest,接收具体的字节
         * @param device :连接的设备
         * @param requestId :请求的ID(也可以理解为流水号)
         * @param characteristic :发送消息使用的characteristic
         * @param preparedWrite :是否需要等待后续操作
         * @param responseNeeded :是否需要回复
         * @param offset : 数据内容偏移
         * @param requestBytes :数据内容
         */
        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(requestBytes)));

        }
    从机通过通知的方式写数据给主机也很简单,先将需要的发送的通过BluetoothGattCharacteristic的setValue装进BluetoothGattCharacteristic里,然后再调用BluetoothGattServer的notifyCharacteristicChanged方法就能发送出去了。其中

notifyCharacteristicChanged有三个参数,第一个device是要发送的目标主机,第二个characteristic是用来通知用的可通知的characteristic,第三个confirm是要不要等回复确认。

/**
     * 发送通知给主机
     *
     * @param device :发送的目标设备
     * @param characteristic :用来通知的characteristic
     * @param data :通知的内容
     */
    public boolean notify( BluetoothDevice device,BluetoothGattCharacteristic characteristic,byte[] data) {
        if(device != null && characteristic != null && data != null){
            //设置写操作的类型 WRITE_TYPE_DEFAULT的情况选  底层会自动分包 不用人为分包
            characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
            //把要设置的数据装进characteristic
            characteristic.setValue(data);
            //发送出去
            return bluetoothGattServer.notifyCharacteristicChanged(device,characteristic,false);
        }else{
            return false;
        }

    }

    好了,ble的从模式基本就讲完了。我把这些操作封装成了一个,方便以后其他地方复用

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.os.ParcelUuid;
import android.util.Log;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by 601042 on 2018/6/28.
 * <p>
 * 封装好Ble Peripheral模式的工具类
 */

public class BlePeripheralUtils {
    private static final String TAG = "BlePeripheralUtils";

    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothManager bluetoothManager;
    private Context context;
    private BluetoothLeAdvertiser bluetoothLeAdvertiser;
    private BluetoothGattServer bluetoothGattServer;

    //连接上的设备
    private ArrayList<BluetoothDevice> deviceArrayList = new ArrayList<BluetoothDevice>();
    //ble的状态callback
    private BlePeripheralCallback blePeripheralCallback;

    /**
     * 开启广播的结果callback
     */
    private AdvertiseCallback callback = new AdvertiseCallback() {

        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            Log.d(TAG, "BLE advertisement added successfully");
        }

        @Override
        public void onStartFailure(int errorCode) {
            Log.e(TAG, "Failed to add BLE advertisement, reason: " + errorCode);
        }
    };

    public BlePeripheralUtils(Context context) {
        this.context = context;
    }

    /**
     * 服务事件的回调
     */
    private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() {

        /**
         * 1.连接状态发生变化时
         * @param device :连接的设备
         * @param status :操作状态(0是成功,其他值为失败)
         * @param newState :当前连接状态(2是已连接 0是已断开)
         */
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));

            if (newState == 2) {
                //连接成功后保存当前的设备
                deviceArrayList.add(device);
            } else {
                //断开后从连接的列表里删除设备
                int index = 0;
                for (int i = 0; i < deviceArrayList.size(); i++) {
                    if (deviceArrayList.get(i).getAddress().equals(device.getAddress())) {
                        index = i;
                        break;
                    }
                }
                deviceArrayList.remove(index);
            }
            //通过回调发送出去
            if (blePeripheralCallback != null) {
                blePeripheralCallback.onConnectionStateChange(device, status, newState);
            }
            super.onConnectionStateChange(device, status, newState);
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);
            Log.e(TAG, String.format("onServiceAdded:status = %s", status));
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            Log.e(TAG, String.format("onCharacteristicReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));

            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
//            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
        }

        /**
         * 3. onCharacteristicWriteRequest,接收具体的字节
         * @param device :连接的设备
         * @param requestId :请求的ID(也可以理解为流水号)
         * @param characteristic :发送消息使用的characteristic
         * @param preparedWrite :是否需要等待后续操作
         * @param responseNeeded :是否需要回复
         * @param offset : 数据内容偏移
         * @param requestBytes :数据内容
         */
        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, new String(requestBytes)));
            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
            //通过回调发送出去
            if (blePeripheralCallback != null) {
                blePeripheralCallback.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, requestBytes);
            }
        }

        /**
         * 2.描述被写入时,在这里执行 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS...  收,触发 onCharacteristicWriteRequest
         * @param device
         * @param requestId
         * @param descriptor
         * @param preparedWrite
         * @param responseNeeded
         * @param offset
         * @param value
         */
        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            Log.e(TAG, String.format("2.onDescriptorWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("2.onDescriptorWriteRequest:requestId = %s, preparedWrite = %s, responseNeeded = %s, offset = %s, value = %s,", requestId, preparedWrite, responseNeeded, offset, new String(value)));

            // now tell the connected device that this was all successfull
            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
        }

        /**
         * 5.特征被读取。当回复响应成功后,客户端会读取然后触发本方法
         * @param device
         * @param requestId
         * @param offset
         * @param descriptor
         */
        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            Log.e(TAG, String.format("onDescriptorReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("onDescriptorReadRequest:requestId = %s", requestId));
//            super.onDescriptorReadRequest(device, requestId, offset, descriptor);
            bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            Log.e(TAG, String.format("5.onNotificationSent:device name = %s, address = %s", device.getName(), device.getAddress()));
            Log.e(TAG, String.format("5.onNotificationSent:status = %s", status));
        }

        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            super.onMtuChanged(device, mtu);
            Log.e(TAG, String.format("onMtuChanged:mtu = %s", mtu));
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);
            Log.e(TAG, String.format("onExecuteWrite:requestId = %s", requestId));
        }
    };


    /**
     * 初始化
     */
    public void init() {
        bluetoothManager =
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        // Ensures Bluetooth is available on the device and it is enabled.  If not,
        // displays a dialog requesting user permission to enable Bluetooth.
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            toEnable();
        }
    }


    /**
     * 打开蓝牙
     */
    private boolean toEnable() {

        boolean result = false;
        try {
            if (mBluetoothAdapter == null) {
                return false;
            }
            for (Method temp : Class.forName(mBluetoothAdapter.getClass().getName()).getMethods()) {
                if (temp.getName().equals("enableNoAutoConnect")) {
                    result = (boolean) temp.invoke(mBluetoothAdapter);
                }
            }
        } catch (Exception e) {
            //反射调用失败就启动通过enable()启动;
            result = mBluetoothAdapter.enable();
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 关闭蓝牙
     */
    private void toDisable() {
        if (mBluetoothAdapter != null) {
            mBluetoothAdapter.disable();
        }
    }

    /**
     * 开启广播
     *
     * @param bleName:ble设备的名称
     * @param serviceData:要放到scanrecord中的数据
     * @param parcelUUID:要放到scanrecord中的UUID
     */
    public void startBluetoothLeAdvertiser(String bleName, byte[] serviceData, UUID parcelUUID) {
        //广播设置
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setConnectable(true) //是否被连接
                .setTimeout(0)        //超时时间
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)  //广播模式
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)   //发射功率
                .build();

        //广播数据设置
        AdvertiseData advertiseData = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)    //是否在广播中携带设备的名称
                .setIncludeTxPowerLevel(true)  //是否在广播中携带信号强度
                .build();
        //扫描回应的广播设置
        AdvertiseData scanResponseData = new AdvertiseData.Builder()
                .setIncludeTxPowerLevel(true)  //是否在广播中携带设备的名称
                .addServiceData(new ParcelUuid(parcelUUID), serviceData) //在scanrecord中添加的数据
                .build();

        //设置BLE设备的名称
        mBluetoothAdapter.setName(bleName);
        //开启广播
        BluetoothLeAdvertiser bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, callback);

    }

    /**
     * 停止广播
     */
    public void stopBluetoothLeAdvertiser() {
        bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        bluetoothLeAdvertiser.stopAdvertising(callback);
    }

    /**
     * 添加ble的service
     *
     * @param serviceInfo:需要添加服务列表
     */
    public void addServices(BluetoothGattServiceInfo... serviceInfo) {
        //先获取GattServer
        bluetoothGattServer = bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
        //循环添加需要添加的service
        for (BluetoothGattServiceInfo temp : serviceInfo) {
            //实例化一个service
            BluetoothGattService service_temp = new BluetoothGattService(temp.getUuid(), temp.getServiceType());
            //添加其中需要的Characteristic
            for (BluetoothGattCharacteristicInfo temp_CharacteristicInfo : temp.getCharacteristicInfos()) {
                //实例化需要的characteristic
                BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(temp_CharacteristicInfo.getUuid(), temp_CharacteristicInfo.getProperties(), temp_CharacteristicInfo.getPermissions());
                //看看需不需要添加descriptor
                BluetoothGattDescriptorInfo descriptorInfo = temp_CharacteristicInfo.getBluetoothGattDescriptorInfo();
                if (descriptorInfo != null) {
                    //需要就先实例化descriptor
                    BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(descriptorInfo.getUuid(), descriptorInfo.permissions);
                    //添加到characteristic里
                    characteristic.addDescriptor(descriptor);

                }
                //把characteristic添加到service
                service_temp.addCharacteristic(characteristic);
            }
            //把service添加到GattServer
            bluetoothGattServer.addService(service_temp);
        }
    }

    /**
     * 发送通知给主机
     *
     * @param device         :发送的目标设备
     * @param characteristic :用来通知的characteristic
     * @param data           :通知的内容
     */
    public boolean notify(BluetoothDevice device, BluetoothGattCharacteristic characteristic, byte[] data) {
        if (device != null && characteristic != null && data != null) {
            //设置写操作的类型 WRITE_TYPE_DEFAULT的情况选  底层会自动分包 不用人为分包
            characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
            //把要设置的数据装进characteristic
            characteristic.setValue(data);
            //发送出去
            return bluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
        } else {
            return false;
        }

    }

    /**
     * 获取service下的所有Characteristic
     *
     * @param serviceUuid :service的UUID
     */
    public List<BluetoothGattCharacteristic> getCharacteristicList(UUID serviceUuid) {
        //根据UUID获取service
        BluetoothGattService service = bluetoothGattServer.getService(serviceUuid);
        //获取到了service则获取其中所有的BluetoothGattCharacteristic列表并返回出去
        if (service != null) {
            return service.getCharacteristics();
        } else {
            return null;
        }
    }

    /**
     * 获取service下的所有Characteristic
     *
     * @param serviceUuid        :service的UUID
     * @param characteristicUuid : Characteristic的UUID
     */
    public BluetoothGattCharacteristic getCharacteristic(UUID serviceUuid, UUID characteristicUuid) {
        //根据UUID获取service
        BluetoothGattService service = bluetoothGattServer.getService(serviceUuid);
        //获取到了service则根据Characteristic的UUID获取Characteristic
        if (service != null) {
            return service.getCharacteristic(characteristicUuid);
        } else {
            return null;
        }
    }


    public ArrayList<BluetoothDevice> getDeviceArrayList() {
        return deviceArrayList;
    }

    public BlePeripheralCallback getBlePeripheralCallback() {
        return blePeripheralCallback;
    }

    public void setBlePeripheralCallback(BlePeripheralCallback blePeripheralCallback) {
        this.blePeripheralCallback = blePeripheralCallback;
    }
}
    BlePeripheralCallback
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;

/**
 * Created by 601042 on 2018/6/28.
 */

public interface BlePeripheralCallback {
     void onConnectionStateChange(BluetoothDevice device, int status, int newState);
     void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes);
}

    调用也很简单,下面是demo中的调用方式

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;

import android.bluetooth.BluetoothGattService;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";


    public final static UUID UUID_SERVER = UUID.fromString("0000181C-0000-1000-8000-00805F9B34FB");
    public final static UUID UUID_SERVER1 = UUID.fromString("0000181C-0000-1000-8000-00805F9B34FA");
    public final static UUID UUID_CHARREAD = UUID.fromString("0000C101-0000-1000-8000-00805F9B3401");
    public final static UUID UUID_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    public final static UUID UUID_CHARWRITE = UUID.fromString("0000C101-0000-1000-8000-00805F9B3402");
    public final static UUID UUID_WRITE = UUID.fromString("0000C101-0000-1000-8000-00805F9B3403");

    BluetoothGattCharacteristic characteristicnotify;


    BlePeripheralUtils blePeripheralUtils;


    BlePeripheralCallback callback = new BlePeripheralCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {

        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {

        }
    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        blePeripheralUtils = new BlePeripheralUtils(MainActivity.this);
        blePeripheralUtils.init();
        blePeripheralUtils.setBlePeripheralCallback(callback);

        Button open = (Button) findViewById(R.id.open);
        Button send = (Button) findViewById(R.id.send);
        final byte[] serviceData = "1111111".getBytes();

        open.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                blePeripheralUtils.startBluetoothLeAdvertiser("xuge", serviceData, UUID_SERVER1);
                BluetoothGattCharacteristicInfo[] bluetoothGattCharacteristicInfos = new BluetoothGattCharacteristicInfo[3];
                BluetoothGattDescriptorInfo descriptorInfo = new BluetoothGattDescriptorInfo(UUID_DESCRIPTOR, BluetoothGattCharacteristic.PERMISSION_WRITE);
                bluetoothGattCharacteristicInfos[0] = new BluetoothGattCharacteristicInfo(UUID_CHARREAD, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ,null);
                bluetoothGattCharacteristicInfos[1] = new BluetoothGattCharacteristicInfo(UUID_WRITE, BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE,null);
                bluetoothGattCharacteristicInfos[2] = new BluetoothGattCharacteristicInfo(UUID_CHARWRITE, BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PROPERTY_NOTIFY,descriptorInfo);
                BluetoothGattServiceInfo bluetoothGattServiceInfo1 = new BluetoothGattServiceInfo(UUID_SERVER,BluetoothGattService.SERVICE_TYPE_PRIMARY,bluetoothGattCharacteristicInfos);
                blePeripheralUtils.addServices(bluetoothGattServiceInfo1);
            }
        });
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(characteristicnotify == null){
                    characteristicnotify = blePeripheralUtils.getCharacteristic(UUID_SERVER,UUID_CHARWRITE);
                }

                blePeripheralUtils.notify(blePeripheralUtils.getDeviceArrayList().get(0),characteristicnotify,"11111".getBytes());
            }
        });

    }



    @Override
    protected void onDestroy() {
        super.onDestroy();
        blePeripheralUtils.stopBluetoothLeAdvertiser();
    }
}
    最后附上 demo


猜你喜欢

转载自blog.csdn.net/a287574014/article/details/80843584
今日推荐