Android 中的 BLE 广告

2024-01-08

我正在开发一个应用程序来在 android 中发送 BLE 广告包。我使用 AdvertiseData 和 AdverstiseSettings 类来生成广告数据包。但是当我执行 StartAdvertising 时,它总是给我一个错误代码“2”,"ADVERTISE_FAILED_TOO_MANY_ADVERTISERS", "无法启动广告,因为没有可用的广告实例。"

下面是我的 MainActivity.JAVA 代码

package rockwellcollins.blutooth_advertise;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

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

public class MainActivity extends AppCompatActivity {
    private BluetoothLeScanner mBluetoothLeScanner;
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        textView = (TextView) findViewById(R.id.txtv);
        mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();

        if( !BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported() ) {
            Toast.makeText(this, "Multiple advertisement not supported", Toast.LENGTH_SHORT).show();
        }
        advertise();
        BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner().startScan(scanCallback);
    }

    private void advertise() {
        BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();

        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY )
                .setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
                .setConnectable(false)
                .build();
        Log.i("BLE","start of advertise data after settings");
        ParcelUuid pUuid = new ParcelUuid( UUID.fromString("b161c53c-0715-11e6-b512-3e1d05defe78"));

        AdvertiseData data = new AdvertiseData.Builder()
                .setIncludeDeviceName( true )
                .setIncludeTxPowerLevel(true)
                .addServiceUuid( pUuid )
                //.addServiceData( pUuid, "Data".getBytes(Charset.forName("UTF-8") ) )
                .build();
        Log.i("BLE","before callback");
        AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
            @Override
            public void onStartSuccess(AdvertiseSettings settingsInEffect) {
                super.onStartSuccess(settingsInEffect);
                Log.i("BLE", "LE Advertise success.");

            }

            @Override
            public void onStartFailure(int errorCode) {
                Log.e("BLE", "Advertising onStartFailure: " + errorCode);
                super.onStartFailure(errorCode);
            }
        };

        advertiser.startAdvertising( settings, data, advertisingCallback );
        Log.i("BLE", "start advertising");
    }

    private final ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            printScanResult(result);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            textView.append("Received " + results.size() + " batch results:\n");
            for (ScanResult r : results) {
                printScanResult(r);
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            switch (errorCode) {
                case ScanCallback.SCAN_FAILED_ALREADY_STARTED:
                    textView.append("Scan failed: already started.\n");
                    break;
                case ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
                    textView.append("Scan failed: app registration failed.\n");
                    break;
                case ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED:
                    textView.append("Scan failed: feature unsupported.\n");
                    break;
                case ScanCallback.SCAN_FAILED_INTERNAL_ERROR:
                    textView.append("Scan failed: internal error.\n");
                    break;
            }
        }

        private void printScanResult(ScanResult result) {
            String id = result.getDevice() != null ? result.getDevice().getAddress() : "unknown";
            int tx = result.getScanRecord() != null ? result.getScanRecord().getTxPowerLevel() : 0;
            textView.append("TX: " + tx + " RX: " + result.getRssi() + " from " + id+ ".\n");
        }
    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Android Manifest.xml 的代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="rockwellcollins.blutooth_advertise">
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

您能让我知道我做错了什么以及如何解决这个错误吗?

Thanks


根据我的经验,关于 BLE 广告的 Android 设备有 4 种类型:

  1. Android 5.0 之前版本的设备 - 不支持 LE 广告
  2. 搭载 Android 5+ 且不支持 LE 广告和返回的设备null from 获取蓝牙LeAdvertiser() https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getBluetoothLeAdvertiser()。这些设备返回false from isMultipleAdvertisementSupported() https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#isMultipleAdvertisementSupported()。即使蓝牙打开,他们也会这样做(见下面的注释)。
  3. 搭载 Android 5+ 的设备返回蓝牙乐广告商对象,但每次广告尝试都以ADVERTISE_FAILED_TOO_MANY_ADVERTISERS错误(这就是你遇到的情况)。这些设备返回true from isMultipleAdvertisementSupported() https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#isMultipleAdvertisementSupported()正如你所看到的,这不是真的。到目前为止,我只见过此类手机中的一款:索尼 xperia z1 Compact,但如果有的话,还会有更多。
  4. 支持 LE 广告的 Android 5+ 设备。那些返回true from isMultipleAdvertisementSupported() https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#isMultipleAdvertisementSupported()但仅当蓝牙打开时。

注:在2.、3.和4.中蓝牙乐广告商仅当蓝牙打开时才返回对象。否则null返回,因此在启用蓝牙之前,您实际上不知道设备是否支持 LE 广告。

检查 nRF Connect 应用程序:禁用蓝牙,安装应用程序,打开并选择广告商选项卡或导航菜单 -> 设备信息。在显示状态之前,它会要求您打开蓝牙。

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

Android 中的 BLE 广告 的相关文章

  • 缺少layout_height属性堆栈跟踪?

    我正在继续挖掘市场崩溃报告 并发现了另一份我无法理解的报告 堆栈跟踪 java lang RuntimeException Binary XML file line 17 You must supply a layout height at
  • 使用服务时应用程序终止时音乐暂停

    我正在使用一个Service类在后台播放音乐 当我在顶部显示通知栏时 我的应用程序出现问题 当我终止该应用程序时 音乐停止约 1 秒 然后再次开始 我不知道出了什么问题 我正在关注this https www simplifiedcodin
  • 如何更改我的应用程序的语言[重复]

    这个问题在这里已经有答案了 可能的重复 在 Android 中以编程方式更改语言 https stackoverflow com questions 2900023 change language programatically in an
  • EditText - 在键入时更改文本

    我需要在输入时替换 EditText 内的文本 示例 如果用户按下 A 它将被存储到缓冲区中 并在 EditText 上显示 D 看起来像是按下了 D 现在我可以读取按下的字符 但无法显示 et 中的任何字符以避免 stackoverflo
  • Volley Json 请求不起作用 - 字符串无法转换为 JsonObject / JsonArray

    我正在开发一个 Android 应用程序并从服务器获取 JsonObject JsonArray 手动将 String 转换为 Json 可以正常工作 我最近切换到 Volley 来处理服务器请求 并且想使用JsonObjectReques
  • Android 应用内购买

    我正在尝试开发一个停车应用程序 用户可以在其中为停车时间付费 我浏览了这份文件应用内产品 http developer android com google play billing billing overview html produc
  • Android-无法解析符号 BaseObservable

    我正在尝试在 android 中实现数据绑定示例并使用可绑定变量创建 POJO 但我收到此错误 请帮忙 我正在关注这个教程http www vogella com tutorials AndroidDatabinding article h
  • 如何从 AccountManager.getAccounts() 获取与特定帐户关联的图标

    每个帐户的帐户设置中都会显示一个图标 对于 Google 帐户有一个图标 对于 Facebook 帐户有另一个图标 有没有办法从应用程序的代码中获取该图标 最后我解决了 private Drawable getIconForAccount
  • Android 设备上的 Facebook 分享问题

    我使用了来自的样本AndroidFacebook示例 https github com ddewaele AndroidFacebookSample它在模拟器上运行良好 但在设备上它被转移到内置的 Facebook 意图 设备上不会出现身份
  • Android:我需要关闭 Cursor 对象吗?

    在我的数据库适配器类中 我有很多这样的方法 public long getContactId final String phoneNumber throws SQLException final Cursor cur mDb rawQuer
  • 解析 android-21 的数据失败,不支持major.minor 版本 51.0

    安装 Android 5 0 SDK 21 后在 Eclipse 中出现以下错误 Loading data for Android 5 0 has encountered a problem Parsing Data for android
  • 索尼 SmartWatch 2 定制表盘自固件更新后损坏

    我知道这将是这个的重复 gt SW2 更新后如何修复 Sony SmartWatch 2 上的自定义表盘时间 https stackoverflow com questions 27536415 how to fix custom watc
  • Eclipse 说“更新 Android Developer Toolkit”

    我不知何故弄乱了我的 Eclipse 和 Android 设置 我不知道如何修复它 问题症状如下 在 首选项 gt Android 中 我尝试选择 android sdk linux 的位置 选择时出现错误 此 Android SDK 需要
  • RecyclerView 未按预期滚动

    我有一个项目 我使用水平回收器视图 并且我想将一个元素居中 我的实现有效 但并非在所有情况下都可以检查此 GIF 正如您可能注意到的 如果我从左边来 它会正确滚动 如果我从右边来 它会过度滚动很多 我不知道如何停止也不知道如何解决这个问题
  • 如何根据另一个动态下拉列表的值创建动态下拉列表?

    我有一个下拉菜单 当我选择一个选项时 它会创建一个动态下拉菜单 到目前为止 一切都很好 但我想创建另一个动态下拉列表 现在基于另一个动态下拉列表的值 我该怎么做 第一个动态下拉列表有效 我猜第二个无效 因为动态变量 div 没有静态 ID
  • 如何检测屏幕何时关闭?

    是否可以检测屏幕何时关闭并捕获它 我想在 Android 的全局设置中将计时器设置为 15 秒 我正在尝试查找一些如何捕获唤醒锁定模式的信息 只需注册您的应用程序即可执行操作Intent ACTION SCREEN OFF https de
  • 横向模式下视频视图不是全屏

    我正在使用用 xml 设计的视频视图 该视频在纵向模式下为全屏 但当切换到横向模式时 它会左对齐 并且宽度和高度都会换行 而不是全屏 我参考了这些 但仍然没有解决这个问题 全屏视频视图未居中 https stackoverflow com
  • 如何在 Jetpack Compose 中集成自动填充

    我想在我的应用程序中提供一些自动填充功能 电子邮件和密码 该功能完全使用 Jetpack compose 编写 我碰到这篇博文 https bryanherbst com 2021 04 13 compose autofill and 这个
  • 使用 Android 2.x 进行实时音频流传输

    我需要在 2 x 及更高版本的设备上播放直播 This http developer android com guide appendix media formats html声明不可能在 Android 2 x 的设备上播放直播 我在这里
  • 如何获取 EC2 实例的 CloudWatch 指标数据

    我想获取我的 EC2 实例的 Cloudmetrics 数据 以便我可以使用这些数据绘制图表并将其显示在我的 Android 设备上 我怎么做 有相同的示例程序或教程吗 提前致谢 这就是我正在做的 private static void f

随机推荐

  • ionic4/Angular7 - 类型“文件”上不存在属性“dataDirectory”

    i user 文件传输 https ionicframework com docs native file transfer 下载需要的文件文件本机 https ionicframework com docs native file还 在i
  • 处理游戏中心身份验证

    根据苹果文档 https developer apple com library ios documentation GameKit Reference GKLocalPlayer Ref Reference Reference html我
  • Apple 当前的 Reachability 类是否向后兼容 iOS 3.1?

    我正在实施苹果的可达性 http developer apple com iphone library samplecode Reachability Introduction Intro html apple ref doc uid DT
  • 用两个或多个其他元素替换列表中的单个元素,而不影响其余元素的顺序

    有没有办法用两个或更多其他元素替换列表中的单个元素而不干扰列表的其余部分 我知道您可以将一个元素替换为另一个元素 但我正在寻找要添加的多个元素 用例是我想根据特定条件将给定元素拆分为两个或多个元素 例如 假设列表包含图上从节点 A 到节点
  • CTE 会提高性能吗?

    with ini as select select ini a join ini b join ini c SQL Server引擎执行了多少次calculate结果来自ini table 我试图回答 在你的帮助下 的问题是如果with语句
  • NodeJS 是否可以动态返回 SSL 证书?

    我想在我的 NodeJS 应用程序中动态返回 ssl 证书信息 我有两个域名链接到同一个节点应用程序 我只看到创建服务器时可以指定 ssl 设置 是否可以根据请求的 url 动态返回 ssl 证书 否则 如果我必须在另一个端口上创建第二个服
  • 如何从java中的.class文件获取实例

    坦白说 我什至不知道这是否可能 但我想做的就像下面这样 我通过终端中的 javac 命令从 ClassFile java 创建了一个类文件 然后我想从 java 文件或 class 文件获取一个实例 接下来 我在eclipse中制作了另一个
  • Angular Js 和 google api client.js (gapi)

    我花了一天的时间才让它发挥作用 所以我认为我的经验可能对某人有用 也许其他一些人会发现改进 所以我两天前就开始了 angularJS 我希望它与 Google Cloud Endpoints 一起创建后端接口 我的麻烦来了 gapi 的 j
  • 如何从 Main 调用 void 函数

    在我的程序中 我试图从 Main 调用 void 函数 但我无法找出正确的方法 Main位于最底部并且void GetTicketType char Choice 是我需要调用的函数cout门票类型 Purpose This program
  • 无法加载 tsc.ps1,因为该系统上禁用了运行脚本

    在 PowerShell 上 执行时收到错误消息tsc 这以前从未发生过 我不确定是否应该混合 PowerShell 安全设置来纠正此问题 例如基于此 PowerShell 表示 此系统上禁用了脚本执行 https stackoverflo
  • 如何检查数据库中是否存在 Oracle 视图?执行查询之前

    我需要知道一种在执行查询之前从 Java 桌面应用程序检查当前数据库中是否存在 Oracle 视图的方法 否则我会遇到很多麻烦 提前致谢 您随时可以查询Oracle数据字典 就像是 SELECT COUNT FROM all views W
  • Haskell 应用变压器的示例

    www haskell org 上的 wiki 告诉我们以下有关 Applicative Transformer 的信息 那么应用变压器在哪里呢 答案是 我们不需要适用函子的特殊变压器 因为它们可以以通用方式组合 http www hask
  • 为什么 MyPage._meta.get_field("title").verbose_name 会更改 Wagtail 中所有标题的标签?

    我的 Wagtail 项目中有几个应用程序 其中之一是 新闻 其中包含新闻 页面 我想在管理中将标题的标签 标题 覆盖为 标题 News meta get field title verbose name Headline 结果 我在所有应
  • 如何使用 Ant 运行类别/套件中的所有 JUnit 测试?

    我在类似于中描述的设置中使用 JUnit 类别和 ClassPathSuite这个答案 https stackoverflow com questions 2176570 how to run all tests belonging to
  • Android - 短信广播接收器

    我一直在努力得到this https stackoverflow com questions 1944102 android sms receiver not working程序可以工作 但到目前为止还没有运气 我找不到我哪里做错了 不知道
  • Clojure 更新映射多个值的惯用方法

    这可能很简单 但我就是无法克服它 我有一个嵌套映射的数据结构 如下所示 def m 1 1 2 2 5 3 10 2 1 2 2 50 3 25 3 1 42 2 23 3 4 我需要设置每个m i i 0 这在非函数式语言中很简单 但我无
  • 将 RSA 私钥导出到 RSAPublicKey 的命令行工具

    今天我发现有两种带有 PEM 格式标头的公钥格式 例如 X 509 SubjectPublicKeyInfo PEM header BEGIN PUBLIC KEY 对应于短标头形式 BEGIN PUBLIC KEY MIIBIjANBgk
  • 我可以在绕过加载命名空间的同时加载 RData 文件吗?

    假设我的一些用户无法更改他们的 R 环境 但我需要他们能够打开 RData 文件 这些环境文件需要加载一个包 确切地说是httpuv 我们不关心包 我们不需要它的功能 我们只需要获取数据 有没有办法强制 R 在加载 RData 文件时绕过加
  • Nim 中的价值与参考模型是什么?

    NOTE 我不是在问指针和引用之间的区别 对于这个问题来说它是完全无关的 我找不到明确说明的一件事 Nim 使用什么模型 就像 C 一样 你有价值观并且与new您创建指向数据的指针 在这种情况下 变量可以保存指向指向 数据的指针的指针 或者
  • Android 中的 BLE 广告

    我正在开发一个应用程序来在 android 中发送 BLE 广告包 我使用 AdvertiseData 和 AdverstiseSettings 类来生成广告数据包 但是当我执行 StartAdvertising 时 它总是给我一个错误代码