androidBLE蓝牙

参考资料:

Android BLE 蓝牙开发入门 - 简书     //  部分方法过时

android蓝牙BLE(一) —— 扫描 - 简书   //分四部讲解  比较详细  推荐

demo1下载链接:service后台读取数据通知广播更新界面

图:

 

 demo2下载链接:BlueTooth_Test.zip-Android文档类资源-CSDN下载

添加权限

    <!--    使用蓝牙所需要的权限-->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <!--    使用扫描和设置蓝牙的权限(申明这一个权限必须申明上面一个权限)-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <!--    gps-->
    <uses-feature android:name="android.hardware.location.gps" />
    <!-- 模糊定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <!-- 精准定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

蓝牙扫描需要开启位置权限:

targetSdkVersion 28以前需要动态申请开启模糊定位,targetSdkVersion 大于28需要开启精准定位,否则扫描不到蓝牙设备。

main_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <Button
                android:id="@+id/btn_open_bluetooth"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="扫描蓝牙" />

            <Button
                android:id="@+id/btn_stop_LeScan_bluetooth"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="得到的数据" />
        </LinearLayout>

        <TextView
            android:id="@+id/btn_Riis"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center" />

    </LinearLayout>


    <ListView
        android:id="@+id/lv_ble_table"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

MainActivity:

package youli.com.example.administrator.bluetooth_servise_bread;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private TextView text_data;
    private TextView text_rssi;

    private final int REQUEST_ENABLE_BT = 1;
    private BleService bleService;
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothLeScanner bluetoothLeScanner;
    private BluetoothManager bluetoothManager; //蓝牙管理类

    private List<BluetoothDevice> mBluetoothDeviceList;
    private List<String> mRssiList;
    private RecyclerView mRvDeviceList;
    private Button mBtnScan;
    private DeviceListAdapter mDeviceListAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLOCATION();
        initView();
        initBle();
    }


    private void initView() {
        text_data = findViewById(R.id.text_data);
        text_rssi = findViewById(R.id.text_rssi);

        mRvDeviceList = (RecyclerView) findViewById(R.id.rv_device_list);
        mBtnScan = (Button) findViewById(R.id.btn_scan);
        mBtnScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                scanBleDevice();
            }
        });

        // 蓝牙设备列表
        mBluetoothDeviceList = new ArrayList<>();
        // 蓝牙设备RSSI列表
        mRssiList = new ArrayList<>();
        mDeviceListAdapter = new DeviceListAdapter(mBluetoothDeviceList, mRssiList);
        mRvDeviceList.setLayoutManager(new LinearLayoutManager(this));
        mRvDeviceList.setAdapter(mDeviceListAdapter);

        // 连接蓝牙设备
        mDeviceListAdapter.setOnItemClickListener(new DeviceListAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, "开始连接", Toast.LENGTH_SHORT).show();
                bluetoothLeScanner.stopScan(scanCallback);

                bleService.connect(bluetoothAdapter, mBluetoothDeviceList.get(position).getAddress());
            }
        });

        // 绑定服务
        Intent intent = new Intent(MainActivity.this, BleService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);


        //注册广播
        IntentFilter filter = new IntentFilter();
        filter.addAction(BleService.ACTION_GATT_CONNECTED);
        filter.addAction(BleService.ACTION_GATT_DISCONNECTED);
        filter.addAction(BleService.ACTION_GATT_SERVICES_DISCOVERED);
        filter.addAction(BleService.ACTION_DATA_AVAILABLE);
        filter.addAction(BleService.ACTION_CONNECTING_FAIL);
        filter.addAction(BleService.EXTRA_RSSI_DATA);
        BleReceiver bleReceiver = new BleReceiver();
        registerReceiver(bleReceiver, filter);

    }

    /**
     * 初始化数据
     */
    private void initBle() {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
//        bluetoothAdapter = bluetoothManager.getAdapter();
        if (bluetoothAdapter == null) {
            Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, REQUEST_ENABLE_BT);
            return;
        }
        scanBleDevice();
    }

    /**
     * 搜索蓝牙设备
     */
    private void scanBleDevice() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {

            bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
            bluetoothLeScanner.stopScan(scanCallback);
            bluetoothLeScanner.startScan(scanCallback);

            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    bluetoothLeScanner.stopScan(scanCallback);
                }
            }, 10000);
        }
    }

    /**
     * 搜索蓝牙设备回调
     */
    ScanCallback scanCallback = new ScanCallback() {
        @Override//扫描结果
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);

            BluetoothDevice bluetoothDevice = result.getDevice();
            int rssi = result.getRssi();

            if (!TextUtils.isEmpty(bluetoothDevice.getName())) {
                if (!mBluetoothDeviceList.contains(bluetoothDevice)) {
                    mBluetoothDeviceList.add(bluetoothDevice);
                    mRssiList.add(String.valueOf(rssi));
                    mDeviceListAdapter.notifyDataSetChanged();
                }
            }
        }

        @Override//批量返回扫描结果
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
        }

        @Override //扫描失败
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    };


    ServiceConnection serviceConnection = new ServiceConnection() {

        @Override //在线服务连接
        public void onServiceConnected(ComponentName name, IBinder service) {
//            BleService.LocalBinder localBinder= (BleService.LocalBinder) service;
            bleService = ((BleService.LocalBinder) service).getService();

        }

        @Override//OnService断开连接
        public void onServiceDisconnected(ComponentName name) {
            bleService = null;
        }
    };


    private List<Object> mlist = new ArrayList<>();//存储蓝牙传递的最终数据值

    /**
     * 广播
     */
    private class BleReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (TextUtils.isEmpty(action)) {
                return;
            }
            switch (action) {
                case BleService.ACTION_GATT_CONNECTED:
                    Toast.makeText(MainActivity.this, "蓝牙已连接", Toast.LENGTH_SHORT).show();
                    break;

                case BleService.ACTION_GATT_DISCONNECTED:
                    Toast.makeText(MainActivity.this, "蓝牙已断开", Toast.LENGTH_SHORT).show();
                    bleService.release();
                    break;

                case BleService.ACTION_CONNECTING_FAIL:
                    Toast.makeText(MainActivity.this, "蓝牙已断开", Toast.LENGTH_SHORT).show();
                    bleService.disconnect();
                    break;

                case BleService.ACTION_DATA_AVAILABLE:

                    Log.i("蓝牙", "收到的数据:");
                    byte[] characteristic = intent.getByteArrayExtra(BleService.ACTION_DATA_AVAILABLE);
                    if (characteristic[0] == -86) {
                        mlist.clear();
                        for (int i = 0; i < characteristic.length; i++) {
                            mlist.add(characteristic[i]);
                        }
                    } else if (characteristic[0] != -86 && mlist.size() > 0) {
                        for (int i = 0; i < characteristic.length; i++) {
                            mlist.add(characteristic[i]);
                        }
                    }

                    if (mlist.size() == 4) {
                        String values = ByteUtils.byte2HexStr(mlist);
                        values = values.substring(2, 6);
                        Integer ble_value = Integer.parseInt(values, 16);
                        Log.i("TAG", "最终值" + values + ":最终值转换16进制:" + ble_value + "毫米");
                        text_data.setText("距离障碍物:" + ble_value + "  毫米");
                        mlist.clear();
                    }

                    break;

                case BleService.EXTRA_RSSI_DATA:
                    int rssi = intent.getIntExtra(BleService.EXTRA_RSSI_DATA, 0);
                    Log.i("蓝牙", "收到的信号值:" + rssi);
                    text_rssi.setText("当前蓝牙RSSI:" + rssi);
                    break;
                default:
                    Log.i("TAG", "当前当前当前当前当前当前当前当前");
                    break;

            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode != Activity.RESULT_OK) {
            return;
        }

        if (resultCode == REQUEST_ENABLE_BT) {
            // 搜索蓝牙设备
            scanBleDevice();
        }
    }


    /**
     * 6.0以上需要动态开启位置权限,否则无法扫描蓝牙设备
     */
    private void getLOCATION() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            }
        }
    }
}

daqiBluetoothGattCallback:
package youli.com.example.administrator.bluetooth_test;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.os.Build;
import android.util.Log;

import androidx.annotation.RequiresApi;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class daqiBluetoothGattCallback extends BluetoothGattCallback {

    private BluetoothGatt   bluetoothGatt;

    private Refresh refresh;

    public daqiBluetoothGattCallback(Refresh refresh) {
        this.refresh = refresh;
    }

    interface Refresh {
        void OnClick_Connected(); //连接成功回调

        void OnClick_Disconnect();//断开连接回调

        void OnClick_Riis(int value);      //型号强度回调

        void OnClick_Refresh(int value);  //更新数据回调
    }

    //定义重连次数
    private int reConnectionNum = 0;
    //最多重连次数
    private int maxConnectionNum = 3;

    private List mlist_bleValue = new ArrayList();

    /**
     * UUID设置不对,不会调用onCharacteristicChanged
     */
    //定义需要进行通信的ServiceUUID
    private UUID mServiceUUID = UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb");
    //定义需要进行通信的CharacteristicUUID特征标识(读取数据)
    private UUID mCharacteristicUUID = UUID.fromString("0000fee1-0000-1000-8000-00805f9b34fb");
    //定义需要进行通信的ServiceUUID特征标识(发送数据时用到)
    private UUID CHARACTERISTIC_WRITE_UUID = UUID.fromString("0000fee1-0000-1000-8000-00805f9b34fb");
    //定义需要进行通信的DescriptorUUID
    private UUID mDescriptorUUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    //64:CF:D9:0A:F7:81


    @Override//连接状态回调
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

        if (status == BluetoothGatt.GATT_SUCCESS) {  //正在执行连接操作

            if (newState == BluetoothProfile.STATE_CONNECTED) {  //设备已连接
                //连接后的操作 发现蓝牙服务,也就是 Service
                Log.i("TAG", "设备已连接");
                gatt.discoverServices();  //发现服务成功后,会触发BluetoothGattCallback#onServicesDiscovered()回调
                if (refresh != null) {
                    refresh.OnClick_Connected();
                }
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { //断开连接
                Log.i("TAG", "断开连接");

                if (refresh != null) {
                    refresh.OnClick_Disconnect();
                }
            }
        } else {//连接出错  执行重连
            /**
             * 异常码
             *  133 :连接超时或未找到设备。
             *  8 : 设备超出范围
             *  22 :表示本地设备终止了连接
             */

            //重连次数不大于最大重连次数
            if (reConnectionNum < maxConnectionNum) {
                //重连次数自增
                reConnectionNum++;
                //重新连接设备
                boolean a = gatt.connect();
            } else {
                //断开连接,返回连接失败回调
                Log.i("TAG", "设备重连失败");
            }
        }
    }


    @Override  //服务发现回调
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {


        if (status == BluetoothGatt.GATT_SUCCESS) { // 发现蓝牙服务成功

//            //        获取UUID
//            List<BluetoothGattService> gattServicesList = gatt.getServices();  //全部服务
//            for (int i = 0; i < gattServicesList.size(); i++) {
//                Log.d("TAG1", " 服务  UUID=" + gattServicesList.get(i).getUuid());
//                List<BluetoothGattCharacteristic> characteristics = gattServicesList.get(i).getCharacteristics();//全部特征
//                for (int j = 0; j < characteristics.size(); j++) {
//                    Log.d("TAG1", " 特征  UUID=" + characteristics.get(j).getUuid());
//
//                    List<BluetoothGattDescriptor> descriptors = characteristics.get(j).getDescriptors();//全部描述符
//                    for (int a = 0; a < descriptors.size(); a++) {
//                        Log.d("TAG1", " 描述符  UUID=" + descriptors.get(a).getUuid());
//                    }
//                }
//            }
//            //上面代码得到的全部uuid   至于用那个需要试过才知道
//            服务  UUID=00001800-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a00-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a01-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a02-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a03-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a04-0000-1000-8000-00805f9b34fb
//            服务  UUID=00001801-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a05-0000-1000-8000-00805f9b34fb
//            描述符  UUID=00002902-0000-1000-8000-00805f9b34fb  使用
//            服务  UUID=0000fee0-0000-1000-8000-00805f9b34fb    使用
//            特征  UUID=0000fee1-0000-1000-8000-00805f9b34fb    使用
//            描述符  UUID=00002902-0000-1000-8000-00805f9b34fb
//            服务  UUID=0000180a-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a23-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a24-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a25-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a26-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a27-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a28-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a29-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a2a-0000-1000-8000-00805f9b34fb
//            特征  UUID=00002a50-0000-1000-8000-00805f9b34fb


            BluetoothGattService gattServicesList = gatt.getService(mServiceUUID);
            if (gattServicesList != null) {
                BluetoothGattCharacteristic gattCharacteristic = gattServicesList.getCharacteristic(mCharacteristicUUID);
                if (gattCharacteristic != null) {


                    //获取其对应的通知Descriptor
                    BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(mDescriptorUUID);
                    if (descriptor != null) {
                        //开启 Android 端接收通知的开关,还需要往 Characteristic 的 Descriptor 属性写入开启通知的数据开关使得当硬件的数据改变时,主动往手机发送数据。
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);//开启 Android 端接收通知
                        boolean descriptorResult = gatt.writeDescriptor(descriptor);

                        /**
                         * readCharacteristic单向通讯
                         * setCharacteristicNotification双向通讯
                         */
//                    boolean a = gatt.readCharacteristic(gattCharacteristic);   //当成功读取特征值时,会触发BluetoothGattCallback#onCharacteristicRead()回调。
                        boolean b = gatt.setCharacteristicNotification(gattCharacteristic, true);//当成功读取特征值时,会触发BluetoothGattCallback#onCharacteristicRead()回调。


                    }
                }
            } else {
                Log.e("onServicesDiscovered", "获取服务失败:" + status);
            }
        }
    }

    @Override  //读取到特征值回调
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            byte[] _b = characteristic.getValue();
            Log.i("TAG", "6: " + _b);
            Log.i("TAG", "7: " + byte2HexStr(_b));
            //获取写入到外设的特征值
            byte[] value = characteristic.getValue();
            String a = byte2HexStr(value);
            Log.i("TAG", "5:" + gatt.getDevice().getName() + " 读取成功 " + characteristic.getValue() + ":转换16进制:" + a);
        }
    }


    @Override//特征写入回调
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
    }


    @Override //外设特征值改变回调
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        byte[] value = characteristic.getValue();
        String a = byte2HexStr(value);
        Log.i("TAG", a + ":值");


        if (value[0] == -86) {   //此处-86  打印出-86  转换后得到 AA   ,获取到完整数据 AA001FBB,取中间四位 转换16 进制
            mlist_bleValue.clear();
            for (int i = 0; i < value.length; i++) {
                mlist_bleValue.add(value[i]);
            }
        } else if (value[0] != -86 && mlist_bleValue.size() > 0) {
            for (int i = 0; i < value.length; i++) {
                mlist_bleValue.add(value[i]);
            }
        }

        if (mlist_bleValue.size() == 4) {
            String values = byte2HexStr(mlist_bleValue);
            values = values.substring(2, 6);
            Integer ble_value = Integer.parseInt(values, 16);
            Log.i("TAG", "最终值" + values + ":最终值转换16进制:" + ble_value + "毫米");

            if (refresh != null) {
                refresh.OnClick_Refresh(ble_value);
            }

            mlist_bleValue.clear();

            //实时显示信号强度
            gatt.readRemoteRssi();    //信号强弱回调触发BluetoothGattCallback. onReadRemoteRssi()回调

        }
    }


    @Override //描述写入回调
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
    }

    @Override  //设备信号强度回调
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {

//        Log.i("TAG", "信号强度"+rssi);

        if (refresh != null) {
            refresh.OnClick_Riis(rssi);
        }
    }


    /**
     * 转换成16进制大写字符串
     *
     * @param b
     * @return
     */
    public static String byte2HexStr(byte[] b) {
        String stmp;
        StringBuilder sb = new StringBuilder();
        for (int n = 0; n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }
        return sb.toString().toUpperCase().trim();
    }

    /**
     * List集合转换成16进制大写字符串
     *
     * @param b
     * @return
     */
    public static String byte2HexStr(List b) {
        String stmp = "";
        StringBuilder sb = new StringBuilder();
        for (int n = 0; n < b.size(); n++) {
            byte bb = (byte) b.get(n);
            stmp = Integer.toHexString(bb & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }
        return sb.toString().toUpperCase().trim();
    }


}

继承

extends BluetoothGattCallback:

BluetoothGattCallback是连接后进行的一系列操作的回调,例如连接和断开连接的回调,发现服务的回调,成功写入数据,成功读取数据,信号值的回调等等。

注释都比较详细

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值