我正在开发一种蓝牙传感器设备,我需要对其进行一对多的数据广播.根据规范,外设可能只有一个主机,由于我正在设计的芯片和堆栈的限制,主机只能有三个从机.据我所知,Android无论如何都不能成为BLE奴隶,因此将我的设备作为主人不是一种选择.
BT4规范和制造商文档都讨论了另一种操作模式,称为广播模式.在广播模式中,从不进行连接,并且应用数据作为广告包的一部分被发送.这完全符合我的需求,因为许多Android/iOS手机可以同时扫描每个数据包.广告数据包以突发方式多次传输,因此我怀疑数据接收最可靠.如果数据包在此处丢失,则可以容忍.
这有趣的是,我希望这些数据包携带实时传感器数据,以10-20Hz的速率更新.从我在网上找到的例子来看,这种模式下的BLE主要用于"iBeacon"类型的实现,它们在那里广播静态数据.我找不到有关如何在Android堆栈中过滤广告数据包的任何信息.它可能是每个蓝牙硬件地址返回一个结果,或者它可能是地址和数据的唯一组合.第二个选项适用于此应用程序.如果启动和停止扫描重置过滤器,我也可以做一些工作.
Android文档没有提及扫描方法中的设备过滤如何工作.我已经能够在网上找到一个试图解决同样问题的帖子,它有一个未解决的响应:BLE:在扫描期间多次发现相同的外设.在iOS中,我的同事通知我,有一个参数可以传递给扫描功能,使其成为可能.
我试图从Android源代码中的startLeScan()调用回溯代码,但是代码非常复杂,并且使用抽象使得很难识别包含它的对象的实现.我得到的最远的是从BluetoothManagerService类方法getBluetoothGatt()返回的IBluetoothGatt对象.该对象接收开始扫描的请求.它正在当前版本的github上的BluetoothManagerService.java的第790行进行实例化.该对象是从消息的结果转换而来的,所以我怀疑结果可能是电话/驱动程序特定的.能够进一步追踪它是我的专长.
我想解决的另一个问题是如何快速打开和关闭扫描.扫描是一项功耗密集型操作,但数据广播将在相当精确的实时计时器上定期进行.因此,如果可以打开和关闭扫描,这将是一个很好的优化,使得广播和扫描同步,扫描仪关闭其他90%以上的时间.这可能需要通过实验进行测试.
我还在进行可行性研究,看看我们的Android配件是否可行.我现在的手机还没有运行4.3版,所以我无法通过实验测试/黑客攻击.
android android-sensors bluetooth-lowenergy android-bluetooth
是否可以通过蓝牙传输音频?在我的研究过程中,我发现它只能使用A2DP(Advanced Audio Distribution Profile).每个Android设备都支持A2DP吗?如果没有,是否可以使用蓝牙在两个Android设备之间传输音频?请帮我理解这个.
我查看了以下链接:
蓝牙低功耗设备由其地址唯一标识(在Android API中,他们将其称为MAC地址,并将其表示为冒号分隔的十六进制值,例如11:aa:22:bb:33:cc).
但要唯一识别BLE地址,您需要知道它是公共地址还是私人地址.本质上,识别地址需要49位,而不是48位.
随机地址可以是静态随机地址,不可解析私有地址或可解析私有地址,这些类型在两个最高有效字节(分别为11,00和10)中由位模式分隔.
但是我没有看到只要通过查看地址中的48位就可以将公共地址和随机地址分开的任何地方.
那么这在Android API中如何运作?当他们不知道您指定的地址是公开的还是随机的时,他们如何知道要连接的设备?
有问题的API例如是getRemoteDevice函数.它说:
Valid Bluetooth hardware addresses must be upper case, in a format such as
"00:11:22:33:AA:BB". The helper checkBluetoothAddress(String) is available
to validate a Bluetooth address.
A BluetoothDevice will always be returned for a valid hardware address,
even if this adapter has never seen that device.
Run Code Online (Sandbox Code Playgroud)
所以你给函数48位数据,没有办法告诉它地址是公共的还是私有的.这意味着设备未被唯一标识.
我有一个蓝牙设备已连接到我在4.4.2之前尝试的所有Android版本.现在,它没有连接Galaxy Tab 4或S3.Tab 3与4.1.2连接良好.问题似乎发生在AcceptThread尝试初始化时BluetoothSocket.我正在使用的代码基于sdk中的聊天示例.
我的接受代码
private class AcceptThread extends Thread {
// The local server socket
private BluetoothServerSocket mmServerSocket;
public boolean successInit = false;
public AcceptThread() {
closeAllConnections();
BluetoothServerSocket tmp = null;
// Create a new listening server socket
while(!successInit) {
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
successInit= true;
Log.i("TAG", "Socket Server Created");
}
catch(Exception e) {
Log.i("TAG", e.getMessage());
successInit = false;
}
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null; …Run Code Online (Sandbox Code Playgroud) 我正在运行Android 4.4.2并启用了"Bluetooth HCI snoop log",如此处所述嗅探/记录您自己的Android蓝牙流量
打开和关闭蓝牙后,我重新启动了手机.我在预期的位置找不到日志文件:
$ adb pull /sdcard/btsnoop_hci.log
remote object '/sdcard/btsnoop_hci.log' does not exist
Run Code Online (Sandbox Code Playgroud)
我怎样才能到达btsnoop_hci.log?
以下代码适用于运行Android 5.1.1(Build LMY48M)的Nexus 9,但不适用于运行Android 6.0的Nexus 9(Build MPA44l)
List<ScanFilter> filters = new ArrayList<ScanFilter>();
ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build();
ScanFilter.Builder builder = new ScanFilter.Builder();
builder.setManufacturerData((int) 0x0118, new byte[]{(byte) 0xbe, (byte) 0xac}, new byte[]{(byte) 0xff, (byte)0xff});
ScanFilter scanFilter = builder.build();
filters.add(scanFilter);
mBluetoothLeScanner.startScan(filters, settings, new ScanCallback() {
...
});
Run Code Online (Sandbox Code Playgroud)
在Android 5.x上,当看到与扫描过滤器匹配的制造商广告时,上述代码产生回调.(参见下面的示例Logcat输出.)在带有MPA44l的Nexus 9上,没有收到回调.如果您注释掉扫描过滤器,则会在Nexus 9上成功接收回调.
09-22 00:07:28.050 1748-1796/org.altbeacon.beaconreference D/BluetoothLeScanner? onScanResult() - ScanResult{mDevice=00:07:80:03:89:8C, mScanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mManufacturerSpecificData={280=[-66, -84, 47, 35, 68, 84, -49, 109, 74, 15, -83, -14, -12, -111, 27, -87, -1, -90, 0, 1, 0, …Run Code Online (Sandbox Code Playgroud) android bluetooth-lowenergy android-bluetooth android-6.0-marshmallow
我正在开发一个在后台运行的Android应用程序,并支持蓝牙配件.我想在后台不断听取蓝牙设备尝试打开手机插座.我的问题是,是否有可能在不经常保留部分唤醒锁的情况下实现这一点,因为这显然会产生严重的电池后果.所以我想知道的是蓝牙对手机入睡的影响.打开蓝牙插座时手机是否保持清醒状态?如果设备尝试连接,蓝牙芯片是否会自动唤醒Android?我试图做一些测试来回答这些问题,但是很难找出唤醒锁发生的事情.另外,我不知道我是否可以依赖于我观察到的行为或者是否可以在其他设备上进行更改.
我使用LeScanCallback(不能使用更新的扫描方法,因为我正在为api 18开发.不重要,因为android 5.0+ apis不提供此功能)以检测何时检测到附近的BLE设备:
private BluetoothAdapter.LeScanCallback bleCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
discoveredDevices.add(bluetoothDevice);
}
};
Run Code Online (Sandbox Code Playgroud)
我没有与设备配对或连接,因为这不是必需的,我只是想看看附近有哪些设备.
我正在尝试提供一项服务,每隔5分钟左右,就会调用一个网络服务器来更新当时附近的设备.
棘手的部分是Android设备将移动,所以现在附近的蓝牙设备可能不会在5分钟内.在那种情况下,我需要将其删除discoveredDevices.
理想情况下,我希望在蓝牙设备处于范围之前接收回叫,但现在不再.但是这个回调不存在.
(我知道android.bluetooth.device.action.ACL_CONNECTED和android.bluetooth.device.action.ACL_DISCONNECTED广播,但这些是你连接到蓝牙设备,我不想要.)
一个选项是每隔5分钟进行一次新的扫描,但是你无法判断所有附近的设备何时被发现,所以你必须进行定时扫描,例如扫描5秒然后将收集的数据发送到网络服务.
这听起来很脏并且有风险,因为您无法确定所有附近的设备是否在规定的时间内被发现,因此我非常希望避免这样做.
还有另一种方法吗?
编辑
某些设备会持续报告附近蓝牙设备的发现,即使它们之前已经被发现过.如果该功能是通用的,我可以解决我的问题,但这是特定于设备的.
例如,我的手机的蓝牙适配器只能发现附近的设备一次.我测试过的其他一些设备不断报告相同的附近设备,但不是所有设备都这样,所以我不能不依赖它.
似乎Nexus 7第一代不支持蓝牙低功耗,至少当我按照教程中的步骤完成时
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
我有以下代码的应用程序完成:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
Run Code Online (Sandbox Code Playgroud)
当然,我检查,蓝牙启用.
所以问题是,如何确定设备是否支持蓝牙低功耗标准?
更新:我正在使用android 4.3
我正在尝试使用BluatoothLeScanner.startScan功能而不是弃用的BluetoothAdapter.startLeScan.昨天我将我的Nexus 5更新到Android 6.0,从那时起我的应用程序就不再起作用了.我首先添加了此处所需的ACCESS_COARSE_LOCATION首选项, https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id.然后我添加了此处所述的权限:https://developer.android.com/training/permissions/requesting.html.但最后它似乎无法正常工作,它不会发送回设备.
这是我的代码:
表现
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stm.sensitronapp">
<uses-sdk android:maxSdkVersion="23"/>
<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"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>`
Run Code Online (Sandbox Code Playgroud)
DeviceScanActivity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE);
}
}
// Device scan callback.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int …Run Code Online (Sandbox Code Playgroud) android bluetooth-lowenergy android-bluetooth android-6.0-marshmallow