1 Star 0 Fork 4

wjzhe / Android BLE

forked from leesonzhong / Android BLE 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

一、蓝牙BLE

  • 蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙(BLE)。
  • 蓝牙4.0标准包括传统蓝牙模块部分和低功耗蓝牙模块部分,是一个双模标准。低功耗蓝牙也是建立在传统蓝牙基础之上发展起来的,并区别于传统模块,最大的特点就是成本和功耗降低,应用于实时性要求比较高。
  • 在BLE协议中,有两个角色,周边(Periphery)和中央(Central);周边是数据提供者,中央是数据使用/处理者,一个中央可以同时连接多个周边,但是一个周边某一时刻只能连接一个中央。 首先使用蓝牙就不得不说BluetoothGatt和BluetoothGattCallback这两个类,该类继承自BluetoothProfile,BluetoothGatt作为中央来使用和处理数据,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,BluetoothGattCallback返回中央的状态和周边提供的数据。

二、开发BLE安卓应用

  • 参考网址https://www.jianshu.com/p/2dba7f067372,android蓝牙BLE(一) —— 扫描

  • 新建工程。在工程的AndroidManifest添加蓝牙权限

        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

    在Activity也要动态申请权限,添加下面代码,在启动蓝牙功能前调用initPermission方法申请权限。

        //申请多个权限
        //1、首先声明一个数组permissions,将需要的权限都放在里面
        String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};
        //2、创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中
        List<String> mPermissionList = new ArrayList<>();
        private final int mRequestCode = 200;//权限请求码
    
        //权限判断和申请
        private void initPermission() {
    
            mPermissionList.clear();//清空没有通过的权限
    
            //逐个判断你要的权限是否已经通过
            for (int i = 0; i < permissions.length; i++) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (checkSelfPermission( permissions[i]) != PackageManager.PERMISSION_GRANTED) {
                        mPermissionList.add(permissions[i]);//添加还未授予的权限
                    }
                }
            }
    
            //申请权限
            if (mPermissionList.size() > 0) {//有权限没有通过,需要申请
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    requestPermissions(permissions, mRequestCode);
                }
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) {
    
            switch (permsRequestCode) {
                case 200:{
                    initPermission();
                }break;
            }
        }
  • 获取BluetoothManager和BluetoothAdapt,BluetoothAdapt具备启动蓝牙和扫描蓝牙列表的功能。

    //首先获取BluetoothManager
    BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    //获取BluetoothAdapter
    BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
  • 判断蓝牙是否开启,蓝牙开启后开始扫描。

    if (!mBluetoothAdapter.isEnabled()) {
        boolean enable = mBluetoothAdapter.enable(); //返回值表示 是否成功打开了蓝牙功能
        if (enable){
        	return;
        }
    }
    if(android.os.Build.VERSION.SDK_INT >= 21) {
        //标记当前的为扫描状态
        mScanning = true;
        //获取5.0新添的扫描类
        if (mBLEScanner == null){
            //mBLEScanner是5.0新添加的扫描类,通过BluetoothAdapter实例获取。
            mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
        }
        //开始扫描
        //mScanCallback是ScanCallback实例。
        mBLEScanner.startScan(mScanCallback);
    } else {
        //标记当前的为扫描状态
        mScanning = true;
        //5.0以下  开始扫描
        //mLeScanCallback是BluetoothAdapter.LeScanCallback实例
        mBluetoothAdapter.startLeScan(mLeScanCallback);
    }
    //超过SCAN_TIME时间后停止搜索
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            //停止扫描设备
            if(android.os.Build.VERSION.SDK_INT >= 21) {
                //标记当前的为未扫描状态
                mScanning = false;
                mBLEScanner.stopScan(mScanCallback);
            } else {
                //标记当前的为未扫描状态
                mScanning = false;
                //5.0以下  停止扫描
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
        }
    }, SCAN_TIME);
  • 扫描的方法需要提供对应的callback,callback类里面的函数里面可以得到扫描得到的蓝牙列表。可以用个列表数组添加扫描得到的设备,记得在开始扫描蓝牙前把列表数组清空。

        /**
         * 搜索蓝牙的结果
         */
        private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                //在这里可以把搜索到的设备保存起来
                //device.getName();获取蓝牙设备名字
                //device.getAddress();获取蓝牙设备mac地址
                //这里的rssi即信号强度,即手机与设备之间的信号强度。
                if(device.getName()==null){
                    return;
                }
                for(int i=0; i<bluetoothDeviceArrayList.size(); i++){
                    if(device.getAddress().equals(bluetoothDeviceArrayList.get(i).getAddress())){
                        return;
                    }
                }
                bluetoothDeviceArrayList.add(device);
            }
        };
        private ScanCallback mScanCallback = new ScanCallback() {
            //当一个蓝牙ble广播被发现时回调
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);
                //扫描类型有开始扫描时传入的ScanSettings相关
                //对扫描到的设备进行操作。如:获取设备信息。
                BluetoothDevice device = result.getDevice();
                if(device.getName()==null){
                    return;
                }
                for(int i=0; i<bluetoothDeviceArrayList.size(); i++){
                    if(device.getAddress().equals(bluetoothDeviceArrayList.get(i).getAddress())){
                        return;
                    }
                }
                bluetoothDeviceArrayList.add(device);
            }
    
            //批量返回扫描结果
            //@param results 以前扫描到的扫描结果列表。
            @Override
            public void onBatchScanResults(List<ScanResult> results) {
                super.onBatchScanResults(results);
    
            }
    
            //当扫描不能开启时回调
            @Override
            public void onScanFailed(int errorCode) {
                super.onScanFailed(errorCode);
                //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。
                //android 7.0后不能在30秒内扫描次数超过5次
    
            }
        };
  • 得到蓝牙设备的列表数据后,一般是让用户选择好要连接的设备名称,根据对应的地址获取蓝牙设备BluetoothDevice后,调用连接connectGatt方法进行连接,并获得返回的BluetoothGatt。

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    mBluetoothGatt = device.connectGatt(getActivity(), false, mGattCallback);//真正的连接。这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接到它)
  • 连接蓝牙设备时需要提供对应的callback,callback类提供了各种连接状态和结果的回调方法。onConnectionStateChange可以得到蓝牙设备连接的状态,可以判断对应蓝牙设备是连接还是断开,连接成功后调用discoverServices方法。onServicesDiscovered可以得到发现的service和service包含的Characteristic,需要调用mBluetoothGatt.discoverServices()。蓝牙发送和接收数据是对Characteristic进行操作,如果没有确定的service和characteristic的UUID,就遍历characteristic获得可写和可读的characteristic存储起来,如果有确定的UUID就只存储对应的characteristic。onCharacteristicWrite可以知道写入到蓝牙外设的特征值是否成功,需要调用mBluetoothGatt.writeCharacteristic。onCharacteristicRead可以得到蓝牙外设发送的特征值,需要调用mBluetoothGatt.readCharacteristic。但是由于不知道蓝牙外设什么时候发送特征值,所以一般不会使用mBluetoothGatt.readCharacteristic方法,而是对Characteristic进行监听。onCharacteristicChanged可以监听到蓝牙外设有发送特征值并得到对应特征值,需要调用mBluetoothGatt.setCharacteristicNotification和mBluetoothGatt.writeDescriptor启动监听,前提是该Characteristic具有NOTIFY属性

    //定义蓝牙Gatt回调类
    public class daqiBluetoothGattCallback extends BluetoothGattCallback{
            //连接状态回调
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                // status 用于返回操作是否成功,会返回异常码。
                // newState 返回连接状态,如BluetoothProfile#STATE_DISCONNECTED、BluetoothProfile#STATE_CONNECTED
                
                //操作成功的情况下
                if (status == BluetoothGatt.GATT_SUCCESS){
                    //判断是否连接码
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                    
                    }else if(newState == BluetoothProfile.STATE_DISCONNECTED){
                        //判断是否断开连接码
                        
                    }
                }else{
                    //异常码
                    
                }
            }
            
            //服务发现回调
            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                super.onServicesDiscovered(gatt, status);
            }
    
            //特征写入回调
            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicWrite(gatt, characteristic, status);
            }
            
            //外设特征值改变回调
            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                super.onCharacteristicChanged(gatt, characteristic);
            }
            
            //描述写入回调
            @Override
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                super.onDescriptorWrite(gatt, descriptor, status);
            }
            
            //特征读取回调
            @Override
            public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicRead(gatt, characteristic, status);
            }
        }
  • 对Characteristic设置监听,当特征值改变时,接收到蓝牙外设发送的值,onCharacteristicChanged方法会回调

     for (int i=0; i<readCharacteristicArrayList.size(); i++){
         BluetoothGattCharacteristic characteristic = readCharacteristicArrayList.get(i);
         mBluetoothGatt.setCharacteristicNotification(characteristic, true);
         // enable remote notification
         List<BluetoothGattDescriptor> gattDescriptors = characteristic.getDescriptors();
         for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
       gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
         mBluetoothGatt.writeDescriptor(gattDescriptor);
         }
     }
  • 发送给蓝牙外设数据

    for (int i=0; i<writeCharacteristicArrayList.size(); i++){
        BluetoothGattCharacteristic characteristic = writeCharacteristicArrayList.get(i);
        characteristic.setValue(byteArray);
        mBluetoothGatt.writeCharacteristic(characteristic);
    }
  • 断开蓝牙外设的连接。调用disconnect()后,会触发手机会触发onConnectionStateChange()的回调。但调用完disconnect()紧接着马上调用close(),会终止BluetoothGattCallback#onConnectionStateChange()的回调

    mBluetoothGatt.disconnect();
    mBluetoothGatt.close();
  • 支持4个蓝牙设备连接并操作,比较简单,使用数组存储不同蓝牙设备的连接状态mConnectionState、蓝牙设备mBluetoothGatt、特征CharacteristicArrayList

        private boolean[] mConnectionState = new boolean[]{false,false,false,false} ;//是否正在连
        private BluetoothGatt[] mBluetoothGatt = new BluetoothGatt[4];
        private List<List<BluetoothGattCharacteristic>> fourWriteCharacteristicArrayList = new ArrayList<>();
        private List<List<BluetoothGattCharacteristic>> fourReadCharacteristicArrayList = new ArrayList<>();
        private List<List<BluetoothGattCharacteristic>> fourNotifyCharacteristicArrayList = new ArrayList<>();

空文件

简介

android平台上连接ble(蓝牙低功耗设备)的demo,包含打开、扫描蓝牙、连接、通信、断开连接各种功能。 展开 收起
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/null_446_4477/android-ble.git
git@gitee.com:null_446_4477/android-ble.git
null_446_4477
android-ble
Android BLE
master

搜索帮助