Android(Java)开发之获取BLE广播包(扫描后获取:广播数据+扫描应答数据+RSSI)

2023-11-01

一、安卓BLE的广播包数据从哪获取?

通常,安卓APP读写BLE设备的数据都是建立连接后通过GATT获取或修改。但是,BLE设备向外广播时本身会携带一部分有用信息,如将传感数据存放到广播包的自定义数据段,最近接触的一个iBeacon/EddyStone整合项目便是类似,因此为了提取广播包进行解析,首要问题就是安卓APP如何获取广播数据。

      其实,安卓蓝牙在扫描设备后,回调方法 onLeScan(...)中的参数 scanRecord 就是广播数据,这里同时包含广播数据扫描应答数据(均为31字节),所以长度一般就是 62 字节,BLE4.0规定,如果广播包和扫描应答包不足字节,则以0补齐。如下:

 private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
                 ...//scanRecord存放广播和扫描应答数据,rssi存放扫描获取的rssi值
        }
    };


二、如何存储广播包数据并解析?

1.目标:扫描的设备显示List中除了显示设备名、Mac地址外,还加入完整的scanRecord数据包显示和rssi的显示。

2.步骤:(基于官方BLE Demo)

(1)在ListView的适配器创建中加入RSSI和Record列表

 //ListView Adapter,用于在listview里管理扫描到的设备
    private class LeDeviceListAdapter extends BaseAdapter {
        private ArrayList<BluetoothDevice> mLeDevices;
        private ArrayList<Integer> mRSSIs;//新加
        private ArrayList<byte[]> mRecords;//新加
        private LayoutInflater mInflator;

        public LeDeviceListAdapter() {
            super();

            mLeDevices = new ArrayList<BluetoothDevice>();
            mRSSIs = new ArrayList<Integer>();//新加
            mRecords = new ArrayList<byte[]>();//新加

            mInflator = DeviceScanActivity.this.getLayoutInflater();
        }
        ...
}

(2)改写LeDeviceListAdapter适配器中的addDevice方法

        public void addDevice(BluetoothDevice device,int rssi,byte[] scanRecord) {
            if(!mLeDevices.contains(device)) {
                mLeDevices.add(device);
                mRSSIs.add(rssi);//新加
                mRecords.add(scanRecord);//新加
            }
        }


(3)BluetoothAdapter.LeScanCallback回调方法onLeScan()中调用新的addDevice方法

    // Device scan callback.
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mLeDeviceListAdapter.addDevice(device,rssi,scanRecord);
                    mLeDeviceListAdapter.notifyDataSetChanged();

                }
            });
        }
    }


(4)ViewHolder和XML布局中加入对应的TextView,并改写 LeDeviceListAdapter适配器中的getView()方法:用于支持scanRecord和rssi的列表化显示

    static class ViewHolder {
        TextView deviceName;
        TextView deviceAddress;
        TextView deviceBroadcastPack;//加入广播包数据
        TextView deviceRssi;//加入RSSI
    }

       @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            // General ListView optimization code.
            if (view == null) {
                view = mInflator.inflate(R.layout.listitem_device, null);
                viewHolder = new ViewHolder();
                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
                viewHolder.deviceBroadcastPack = (TextView) view.findViewById(R.id.device_broadcastPack);
                viewHolder.deviceRssi = (TextView) view.findViewById(R.id.device_rssi);
                
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }
            //获取设备列表、RSSI列表和广播包列表项目
            BluetoothDevice device = mLeDevices.get(i);
            int rssi = mRSSIs.get(i);
            byte[] scanRecord = mRecords.get(i);
  
            //提取信息
            final String deviceName = "设备名:" + device.getName();
            final String deviceAddr = "Mac地址:" + device.getAddress();
            final String broadcastPack ="广播包:" + bytesToHex(scanRecord);//此处调用了格式转换方法bytesToHex()将十六进制序列转String
            final String rssiString = "RSSI:" + String.valueOf(rssi) + "dB";//此处调用了String的格式转换方法valueOf()将数值类型转String
         
            //显示数据
            if (deviceName != null && deviceName.length() > 0)//显示设备名
                viewHolder.deviceName.setText(deviceName);
            else
                viewHolder.deviceName.setText(R.string.unknown_device);
            viewHolder.deviceAddress.setText(deviceAddr);//显示设备地址
            viewHolder.deviceBroadcastPack.setText(broadcastPack);//显示广播包
            viewHolder.deviceRssi.setText(rssiString);//显示RSSI
           
            return view;
        }

(5)实现scanRecord的格式转换方法:bytesToHex()---广播和扫描应答数据以十六进制格式存储在bytes[]数组中,需要转换为String后显示

    //scanRecords的格式转换
    static final char[] hexArray = "0123456789ABCDEF".toCharArray();
    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

三、效果展示

实现的基本效果如图,扫描到的设备列表加入了RSSI和完整广播包的显示


后注:获取到scanRecord后就能根据协议解析广播包了,根据需求提取对应字段。scanRecord的数据必须进行格式转换,否则列表显示会出现乱码,格式不匹配!



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android(Java)开发之获取BLE广播包(扫描后获取:广播数据+扫描应答数据+RSSI) 的相关文章

  • Android 覆盖在软件按钮之上

    我正在尝试编写一个绘制自定义鼠标指针的应用程序 我目前有一个服务 它创建一个扩展 ViewGroup 的类 并使用 WindowManager 系统服务将其显示为带有 FLAG LAYOUT IN SCREEN 设置的 TYPE SYSTE
  • EditText 中的验证允许 IP 或 Web Url 主机

    我需要对我的 EditText 进行验证 以便它允许我输入有效的 IP 地址格式 即示例 132 0 25 225 or 网址格式 www 例如 www example com 逻辑是 如果用户首先输入任何数值 则验证 IP 将执行操作 否
  • 关闭 Android 中的飞行模式

    如果 num gt 50 我想关闭飞行模式 我实现了这段代码 来自在 Android 中切换飞行模式 https stackoverflow com questions 5533881 toggle airplane mode in and
  • Android KeyBoard.Key 禁用图标 预览特殊键?

    我通过实现 KeyboardView OnKeyboardActionListener 接口来自定义自己的软键盘 按下按键时 将显示预览弹出窗口 我的问题是如何禁用 SHIFT 和 DELETE 等特殊键的预览弹出窗口 我尝试将 andro
  • 如何检测和管理来电(Android)?

    我想创建一个应用程序 可以检测来电并在一定数量的蜂鸣声 响铃 后启动我的自定义活动 我的意思是在 2 或 3 或 5 声蜂鸣声 响铃 后我的activity被触发 我该怎么做 Thanks 我认为您无法计算自来电开始以来电话响了多少次 无法
  • 如何在出现“无法解析放置符号”错误时向哈希图添加键和值

    我正在与安卓工作室 https en wikipedia org wiki Android Studio1 4 1 我刚刚创建了一个 Hashmap 并正在遵循有关如何填充和操作它的教程 Java 语言 但是 我收到 无法解析符号放置 错误
  • Android Studio:lambda 不起作用[重复]

    这个问题在这里已经有答案了 当尝试使用 lambda 表达式时 我遇到了一些 Gradle 构建错误 错误 41 100 错误 source 1 7 不支持 lambda 表达式 使用 source 8 或更高版本来启用 lambda 表达
  • 如何将 EditText 传递给另一个活动?

    Intent intent new Intent this Name class intent putExtra key et getText toString startActivity intent Intent intent getI
  • Android Lollipop prepareAsync() 需要很长时间才能返回

    在 Samsung Galaxy Note 4 上的 Android Lollipop 几周前刚刚从 4 4 4 更新 上 prepareAsync 几乎需要 20 秒来加载实时流 在 4 4 4 上 只需要 2 3 秒 并且没有错误 见下
  • 访问角落里的存储

    我能找到的与文件存储有关的最接近文档的是这个帖子 http nookdeveloper zendesk com entries 20257971 updated what are the size constraints on my app
  • Android-工具栏中的SearchView

    我只想在我的应用程序中添加 searchview 但我不想搜索任何东西 只是我想要用户输入的查询 到目前为止 我尝试了这段代码 但是当我运行我的应用程序时它崩溃了 Update 我尝试了这个 但即使我的应用程序崩溃了 main menu x
  • 获取可以共享数据的应用程序列表

    此代码显示默认共享对话框 Intent sharingIntent new Intent Intent ACTION SEND sharingIntent setType text html sharingIntent putExtra a
  • 如何从android获取应用程序安装时间

    我尝试了一些方法 但没有成功 请帮助我 PackageManager pm context getPackageManager ApplicationInfo appInfo pm getApplicationInfo app packag
  • Android 改变 ImageView / Bitmap 的颜色

    我需要找到一种方法来改变 Android 中位图的颜色 我需要在我的应用程序中平滑地替换 更改椭圆形图像的颜色 具体取决于int价值 我需要类似的东西myValue 5比改变我的图像的颜色RED and if myValue 322将颜色更
  • jar 中的 apklib 有什么优点?

    我正在关注这个问题 https stackoverflow com questions 6059502 whats the difference between apklib and jar files但它并没有完全回答我的问题 jar 中
  • Android:无法发送http post

    我一直在绞尽脑汁试图弄清楚如何在 Android 中发送 post 方法 这就是我的代码的样子 public class HomeActivity extends Activity implements OnClickListener pr
  • Android 中的 Google Places API - 适用于个人用户的 API_KEY

    我已经浏览了与在 Android 应用程序中使用 Places API 相关的 Android 文档和其他博客 到处都建议使用 API KEY 来调用 REST 服务 API KEY 在整个项目 应用程序中都是相同的 每天的请求数限制为 1
  • 通过powershell运行ADB命令

    所以我尝试通过 powershell 脚本运行一些 ADB 命令 这是我正在尝试做的一个简单示例 adb shell echo in adb shell su root echo you are now root ls cd data da
  • 具有矢量可绘制的 ImageView 的 Resources$NotFoundException

    我遇到了崩溃 Resources NotFoundException用于在活动创建时绘制的矢量 21 日前崩溃 安卓工作室2 1 支持库24 0 0 Gradle插件2 1 0 目标SDK 23 最小SDK 15 buildTools版本
  • Android ADT Eclipse 插件,parseSDKContent 失败

    我刚刚设置了我的第一个 Android 开发环境 其中包括 日食3 5 Mac OS X 10 5 适用于 x86 mac 的 Android SDK ADT Eclipse 插件 0 9 6 我已将 set PATH 设置为我的 SDK

随机推荐