Android BLE虚拟设备端

简介

Android5.0以上的系统可以作为在BLE通信中的设备端,能够开启服务接收其他手机发送来的数据。
大致的通信过程如下:
打开蓝牙–添加服务和特征值–发送广播数据
其他手机接收到广播数据之后,便可以从中读取出服务和特征值,如果特征值可写,那么便可以往特征值里面写数据,设备端便可以接收到数据。

以下是我自己写的一个demo,增加了服务CONFIG_SERVICE和特征值CONFIG_CHARACTER,其他设备搜寻到CONFIG_CHARACTER特征值,便可以往里面写数据。
这里写图片描述

源码地址:http://download.csdn.net/detail/hbdatouerzi/9894632

开发步骤

1.初始化

这一步主要是初始化mBluetoothManager、mBluetoothAdapter和mBluetoothAdvertiser,其中mBluetoothManager和mBluetoothAdapter获取蓝牙服务,打开和关闭蓝牙等;mBluetoothAdvertiser用于发送广播。

    //初始化
    public boolean init(){
        String str = "设备不支持蓝牙低功耗通讯";
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            LogUtil.getInstance().ilog(tag,str);
            return false;
        }

        mBluetoothManager = (BluetoothManager) context.getSystemService(BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            LogUtil.getInstance().ilog(tag,str);
            return false;
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if(mBluetoothAdapter == null){
            LogUtil.getInstance().ilog(tag,str);
            return false;
        }

        mBluetoothAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        if (mBluetoothAdvertiser == null) {
            LogUtil.getInstance().ilog(tag,str);
            return false;
        }

        //打开蓝牙的套路
        if ((mBluetoothAdapter == null) || (!mBluetoothAdapter.isEnabled())) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            context.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        return true;
    }
2.设置特征值读写的回调
//连接、读写的回调
public class BluetoothCallBack extends BluetoothGattServerCallback{

    private String TAG = "BluetoothCallBack";
    private WifiviewI wifiview;

    private ResponseI response;

    private StringBuilder reciveStr;//收到的数据
    private int byteCount;//收到信息的条数

    public BluetoothCallBack(WifiviewI wifiview){
        this.wifiview = wifiview;
        reciveStr = new StringBuilder();
    }

    public void setResponse(ResponseI response){
        this.response = response;
    }

    //添加一个服务之后的回调
    public void onServiceAdded(int status, BluetoothGattService service) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            LogUtil.getInstance().ilog(TAG,"添加服务成功!服务的uuid为"+service.getUuid().toString());
        } else {
            LogUtil.getInstance().ilog(TAG, "添加服务失败!");
        }
    }

    //连接状态改变之后的回调
    public void onConnectionStateChange(android.bluetooth.BluetoothDevice device, int status,
                                        int newState) {
        LogUtil.getInstance().ilog(TAG, "连接状态为" + newState);
    }

    //当客户端来读数据时的回调
    public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device,
                                            int requestId, int offset, BluetoothGattCharacteristic characteristic) {
        LogUtil.getInstance().ilog(TAG, "客户端来读取数据");
    }

    //当有客户端来写数据时回调的回调
    @Override
    public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device,
                                             int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite,
                                             boolean responseNeeded, int offset, byte[] value) {
        final String str = new String(value);
        LogUtil.getInstance().ilog(TAG, "客户端来写数据,写的数据为"+str);
        if(response != null){
            response.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
        }
    }
}
3.添加服务和特征值

构造CONFIG_SERVICE和CONFIG_CHARACTER,并设置CONFIG_CHARACTER为可读可写,其中UUID应当事先约定好,这样手机端便可以知道哪个UUID是CONFIG_CHARACTER。

if(mGattServer == null) {
            mGattServer = mBluetoothManager.openGattServer(context, callBack);//callback对特征值进行数据读写时的回调
        }
        //构造服务和特征值
BluetoothGattService testService = new BluetoothGattService(UUID.fromString(Attributes.CONFIG_SERVICE_UUID),               BluetoothGattService.SERVICE_TYPE_PRIMARY);
//设置特征值可读可写
BluetoothGattCharacteristic fcharacter = new BluetoothGattCharacteristic(
UUID.fromString(Attributes.CONFIG_CHARACTER_UUID),
  BluetoothGattCharacteristic.PROPERTY_READ |BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_NOTIFY ,
                BluetoothGattCharacteristic.PERMISSION_READ |BluetoothGattCharacteristic.PERMISSION_WRITE);
        fcharacter.setValue("first");

testService.addCharacteristic(fcharacter);
//添加服务
if(mGattServer!=null && testService!=null)
    mGattServer.addService(testService);
4.设定发送广播的回调

发送广播的回调有两个函数,发送成功和发送失败

private AdvertiseCallback adCallBack = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            LogUtil.getInstance().ilog(tag,"广告回调 onStartSuccess");
        }

        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            LogUtil.getInstance().ilog(tag,"广告回调 onStartFailure");
        }
    };
5.发送广播

adCallBack是发送广播的回调。

try{
            mBluetoothAdvertiser.startAdvertising(createAdvSettings(true, 0), createFMPAdvertiseData(),adCallBack);
        }catch(Exception e){
            e.printStackTrace();
            LogUtil.getInstance().ilog(tag,"发送广告出现异常"+e);
        }

createAdvSettings为广告设置,createFMPAdvertiseData为广告数据

    public  AdvertiseSettings createAdvSettings(boolean connectable, int timeoutMillis) {
        AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
        //设置广播的模式,应该是跟功耗相关
        builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
        builder.setConnectable(connectable);
        builder.setTimeout(timeoutMillis);
        builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
        return builder.build();
    }

    //设置一下FMP广播数据
    public  AdvertiseData createFMPAdvertiseData() {
        AdvertiseData.Builder builder = new AdvertiseData.Builder();
        builder.setIncludeDeviceName(true);
        AdvertiseData adv = builder.build();
        return adv;
    }

这样手机端便可以扫描到设备,连接设备并发现设备的服务和特征值,如果特征值可写,便可以写数据,设备通过回调函数可以收取到写来的数据。

6.停止发送

停止发送广播,关闭服务

 if (mBluetoothAdvertiser != null) {
                    mBluetoothAdvertiser.stopAdvertising(adCallBack);
                    mBluetoothAdvertiser = null;
                }

                if(mBluetoothAdapter != null){
                    mBluetoothAdapter = null;
                }

                if (mGattServer != null) {
                    mGattServer.clearServices();
                    mGattServer.close();
                    mGattServer = null;
                }
                LogUtil.getInstance().ilog(tag,"结束服务成功");

总结

BLE连接方式相对于经典蓝牙的连接方式来说,BLE不需要配对,直接通过服务特征值的方式,便可以进行数据的传输,弄明白了它的连接流程和工作方式之后,其实编程也是很简单的。另外设备端需要获取以下权限,不要忘了添加。

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值