我一直在网上搜索,并没有看到任何关于如何准确实现OOB配对的方法.我希望有人能指点我一些示例代码来帮助我.Android开发者网站中的聊天示例根本没有真正涉及这种类型的配对.
基本上,我有一个Android平板电脑,我想安全地与一个用C++编写的设备配对,没有内置的显示/ IO机制.要配对的平板电脑将充当GUI/IO接口,我将通过蓝牙发回消息和第四个消息.因此,我想通过OOB配对方案将平板电脑与每台设备进行安全配对.
我理解OOB的概念,但是当我在android.developers.com网站上查找我的Android客户端代码时,我很难找到适当的方法来调用.另外,在查看bluez的东西时,我找不到太多可以继续使用我的C++编写的服务器.
基本用例是用户将通过USB连接将平板电脑连接到设备.USB连接将有助于传递每个设备的密钥/ mac地址,然后使用该信息对蓝牙.
我可以弄清楚USB部分,但是一旦我在客户端和服务器上获得密钥和必要信息,我似乎无法找到正确的方法来调用两端成功并安全地配对.
我已经有一个客户端/服务器通过不安全的连接进行通话,所以我遇到的唯一问题就是两端的实际配对.一旦我配对,我就可以使用secureRFComm来完成我未来的所有消息传递.
当您在Android中使用蓝牙或WiFi Direct时,在所有握手等结束时,您最终会使用套接字.
使用TCP/IP,我们在套接字之上有一个超过一个的库,用于高级协议:HTTP,XMPP,IMAP等.由于这些库,我们可以处理更多特定于域的抽象一个操作(例如,"下载此文件"),由库处理的低级套接字管道.
问题:对于任何高级协议,是否已知通过Android的蓝牙和/或WiFi Direct层生成的插槽工作(或可能工作)?
现在,我对特定协议并不挑剔 - 我只是在寻找这种协议层的例子,以便让开发人员更容易使用这些类型的连接选项.
例如,看起来我可以为OkHTTP创建一个fork或附加组件,它使用套接字的替代源,我可以创建一个同样的Java HTTP服务器.鉴于这些,应用程序开发人员将编写通过蓝牙或WiFi Direct进行交谈的HTTP应用程序(至少在客户端,编码应该是相当"自然"的感觉,一旦连接特定的配对和握手已经开始).
IOW,回去处理原始套接字感觉这么二十年前... :-)
谢谢!
UPDATE
根据Kristopher Micinski对ZeroMQ答案的评论,我认为可能会有一些澄清.
更容易说出我不想要的东西:创建它们后我不想触摸套接字.更高级别的其他东西应该为我处理那些,并处理我认为是"协议"的东西(例如,确定某些通信操作何时结束,超过套接字关闭).
大多数情况下,这是我的书.大多数低级套接字的书籍示例都是不现实的,例如"我们打开服务器的套接字并立即开始爆破表示要上传的图像的字节,然后在我们完成时关闭套接字".虽然这些例子很有效,但你在现实生活中永远不会写出类似的东西:
如果您真的在套接字级别工作,那么您将实现一些希望解决身份验证,错误处理等问题的协议,即使您自己正在推出协议
很少有开发人员今天直接使用套接字来进行Internet操作
现在,如果该层提供的协议是开发人员习惯的(例如,HTTP)或者即使他们没有使用它(例如,XMPP),也会很酷.而且我会满足于简单的场景(例如,N路支持很酷但不是必需的).在这方面,基于初步研究(由睡眠不足的大脑进行),ZeroMQ并不是一个糟糕的选择.与XDPP堆栈相比,它缺乏一点"品牌识别",可以使用任意套接字.但是从袖口看它似乎满足了我正在寻找的东西.
我认识到这些堆栈将受到底层传输的限制(例如,蓝牙仅适用于N路,适用于N的小值).我当然不想描绘 - 在这里或在我的书中 - 我描绘的任何解决方案都是基于套接字的通信的全部和最终结果.
我只想要一些对实际使用更加真实的祷告.奖励积分如果它是我可以理解的东西,因为我一直使用更高级别的TCP/IP通信协议,所以我缺乏直接套接字操作的经验.
它已被问到,但我没有找到任何解决方案.对于蓝牙应用我正在使用bluetoothShare.class.
我的源代码,用于将文件发送到目标设备
MainActvity.class:
Set<BluetoothDevice> devices = btAdapter
.getBondedDevices();
final String btDeviceName = selected_deviceName;
BluetoothDevice device = null;
for (BluetoothDevice itDevice : devices) {
if (btDeviceName.equals(itDevice.getName())) {
device = itDevice;
}
}
if (device != null) {
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, uri.toString());
values.put(BluetoothShare.MIMETYPE, "image/jpeg");
values.put(BluetoothShare.DESTINATION,
device.getAddress());
values.put(BluetoothShare.DIRECTION,
BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
final Uri contentUri = getApplicationContext()
.getContentResolver().insert(
BluetoothShare.CONTENT_URI, values);
Log.v(TAG, "Insert contentUri: " + contentUri
+ " to device: " + device.getName());
Toast.makeText(getApplicationContext(), "Success", …Run Code Online (Sandbox Code Playgroud) 在我们的应用程序中,我想使用Android v4.2或更高版本连接到之前配对的A2DP蓝牙扬声器并直接播放音频.
我可以使用此代码成功创建A2DP配置文件对象以启动该过程:
/* Manifest permissions */
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Run Code Online (Sandbox Code Playgroud)
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.A2DP)
Run Code Online (Sandbox Code Playgroud)
并且以下监听器响应连接:
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothSpeaker = (BluetoothA2dp) proxy;
// no devices are connected
List<BluetoothDevice> connectedDevices = mBluetoothSpeaker.getConnectedDevices();
//the one paired (and disconnected) speaker is returned here
int[] statesToCheck = {BluetoothA2dp.STATE_DISCONNECTED};
List<BluetoothDevice> disconnectedDevices = mBluetoothSpeaker.getDevicesMatchingConnectionStates(statesToCheck);
BluetoothDevice …Run Code Online (Sandbox Code Playgroud) 我已经尝试过蓝牙LE广告,即使用Android手机作为BLE"外围设备".启动和停止持续广告一旦正常工作,但如果我想实际传输一些不同的数据,我需要在一个周期内启动,停止和重新启动广告,并始终更改广告包.
我当然使用这些方法:
BluetoothLeAdvertiser.startAdvertising()
BluetoothLeAdvertiser.stopAdvertising()
至少在摩托罗拉Moto G 4G第二代.(XT1072)与Android 5.0.2的循环只运行一段时间,然后蓝牙堆栈出现问题,无法再启动新的广告.当快速运行循环时,这很快发生,如果运行缓慢,则需要更多时间,因此可能与某些缓冲区填满有关.
我的问题是:这是否也发生在摩托罗拉以外的其他设备上?
(当然,欢迎任何其他相关评论.)
从理论上讲,它可能依赖于一些制造商特定的HAL实现等.所以我想知道我是否应该让其他设备能够解决这个问题,因为谷歌/摩托罗拉的任何修复都需要一些时间.
这个测试应用程序 可以用来试试这个:
https://bitbucket.org/MarkusKauppinen/bleadvertisertest
如果一切顺利,它将乐意继续广告,如果这个问题再现,它将在几分钟左右的时间内显示一个对话框.如果您的设备根本不支持蓝牙LE广告或BLE,它就会崩溃.(这只是一个快速而肮脏的测试应用程序.)
另一种简单的方法是从https://github.com/devunwired/accessory-samples运行"bluetoothadvertiser"应用程序,并快速点击UI上的"更新广告"按钮一段时间.
额外细节:
蓝牙LE外设模式支持(广告需要)在Lollipop中添加,在4.x中不可用.只有某些设备具有外设模式支持.兼容性至少包含在:
https://altbeacon.github.io/android-beacon-library/beacon-transmitter-devices.html 支持Android 5 BLE外设模式 芯片组的芯片组/设备支持Android 5上的BLE外设角色
例如,这些设备应该得到支持:摩托罗拉Moto E 4G(2015),摩托罗拉Moto G 4G(第二代),索尼Xperia M4 Aqua,中兴Blade S6,摩托罗拉Moto X(2014),三星Galaxy S6,谷歌Nexus 6 ,谷歌Nexus 9,HTC One M9,三星Galaxy S6 Edge.
至于"脏细节",在此之前我总是可以在LogCat中看到"GKI_Exception":
GKI_exception():65524 getbuf:缓冲区外
在第一个"GKI_Exception"之后不久,广告以AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR失败.这条线......
E/BtGatt.btif?### ASSERT:external/bluetooth/bluedroid/main /../ btif/src/btif_gatt_client.c 803行上下文传输失败!(3)###
......可能很重要,但我不熟悉BlueDroid.所述断言在这里:
一些可能相关的问题:
https://code.google.com/p/android/issues/detail?id = 65455 < - 我在此添加了一些注释和日志文件.
https://code.google.com/p/android-developer-preview/issues/detail?id=1753 在三星S4上
扫描大量BLE标签
蓝牙崩溃
我是Android编程的初学者,因为我3个月前才开始.我正在做一个项目,使用蓝牙将Android应用程序连接到arduino.我已经有了Android应用程序的代码(bluetooth.adapter,socket,.etc.).连接代码已经正常工作.其中一个目标是Android应用程序在与蓝牙设备配对时自动输入密码,而无需用户输入PIN.
这个论坛上的旧帖子没什么用.(许多建议使用不安全模式,但我确实需要安全模式,在我的情况下,arduino是服务器,而手机应用程序是客户端,因此createInsecureRfcommSocketToServiceRecord()服务器方法对我不起作用)
我在android开发者网站上搜索并发现了这个关于bluetoothdevice类的信息:
setPairingConfirmation(boolean confirm)确认PAIRING_VARIANT_PASSKEY_CONFIRMATION配对的密码.
PAIRING_VARIANT_PIN ="将提示用户输入图钉或应用程序将为用户输入图钉".
PAIRING_VARIANT_PASSKEY_CONFIRMATION ="系统将提示用户确认屏幕上显示的密钥或应用程序将确认用户的密钥"
似乎使用代码,应用程序将是输入密码和确认密码使其成为"自动连接"功能,但Android网站没有给出如何使用它的示例代码.你们有没有使用这个或相关过程的示例代码?我感谢您的帮助!
我正在制作一个使用蓝牙连接的应用程序.我打电话蓝牙连接onCreate()和关闭它onDestroy()的MainActivity:
// Bluetooth
private Bluetooth bt;
private boolean registered = false;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = new Bluetooth(this);
bt.enableBluetooth();
bt.setCommunicationCallback(this);
bt.connectToName(bt.getBluetoothDevice(this));
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mReceiver, filter);
registered = true;
}
@Override
public void onDestroy() {
super.onDestroy();
if(registered) {
unregisterReceiver(mReceiver);
registered=false;
}
bt.removeCommunicationCallback();
bt.disconnect();
if (handler != null && runnable != null) {
handler.removeCallbacks(runnable);
}
}
Run Code Online (Sandbox Code Playgroud)
该应用程序还支持LANDSCAPE和PORTRAIT模式(使用两种不同的布局).当屏幕旋转时,由于布局不同,MainActivity调用onCreate()和onDestroy功能.出于这个原因,我收到以下错误:
@@@ ABORTING: INVALID HEAP ADDRESS …Run Code Online (Sandbox Code Playgroud) sockets android bluetooth android-activity android-bluetooth
在我的应用程序中我有启动和停止按钮,当用户按下启动时我调用startScan方法
bluetoothAdapter.getBluetoothLeScanner().startScan(getLeScanCallback());
Run Code Online (Sandbox Code Playgroud)
当用户按下停止时,我会调用stopScan,但它似乎什么也没做.BluetoothAdapter会持续扫描新设备.
bluetoothAdapter.getBluetoothLeScanner().stopScan(getLeScanCallback());
Run Code Online (Sandbox Code Playgroud)
这是我的getLeScanCallback方法:
private ScanCallback getLeScanCallback(){
ScanCallback leScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
boolean duplicate = false;
for(Device d : devices) {
if(d.getAddress().equals(result.getDevice().getAddress()))
duplicate = true;
}
if(!duplicate) {
Device device = new Device();
device.setName(result.getDevice().getName());
device.setAddress(result.getDevice().getAddress());
device.setStatus(getString(R.string.disconnected));
devices.add(device);
deviceListAdapter.notifyDataSetChanged();
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
return leScanCallback;
}
Run Code Online (Sandbox Code Playgroud)
即使在调用stopScan()之后它也会被调用.我做错了什么,换句话说,如何停止扫描BLE设备?
我有一个功能,我需要获取系统活动音频输出设备的当前和检测开关。就像是:
在我看来,这应该有一个 API,但似乎有几个。最有意义的一个似乎是,MediaRouter但它有两个大问题阻止我如上所述使用它:
Complete Local Name可用于此目的,可从BluetoothDevice类型获得,但不能从MediaRouter. 相反,MediaRouter使一个productName可用,有时可以是蓝牙设备的别名,而不是静态名称。我已经放弃了这个 API 并继续寻找其他解决方案,如果有人认为有办法解决上述问题,请告诉我,最重要的是第一个。我会注意到我同时使用了android.media.MediaRouter和androidxone,它们都有这些问题。
我现在正在利用其他 API 的组合。它有效,但它远非可接受的解决方案:
使用AudioManager.registerAudioDeviceCallback(object : AudioDeviceCallback)非蓝牙设备检测(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER))。当添加或删除这些设备中的任何一个时,我会收到回调,然后我可以检查是否存在有线类型设备,那么它在 100% 的时间都是活动的,如果不是,则嵌入式类型是活动的。这有点hacky,但它有效。
更有趣的是,为了检测蓝牙输出设备,我使用了一个私有 API,Android 本身在设置应用程序中使用它来显示当前的音频输出设备。
BluetoothA2dp::class.java.getDeclaredMethod("getActiveDevice") 获取当前活动的输出设备。这是通过获取配置文件代理服务来完成的bluetoothAdapter.getProfileProxyBluetoothA2dp::class.java.getField("ACTION_ACTIVE_DEVICE_CHANGED").get(null)以检测蓝牙有源音频设备的开关。此解决方案有效,但也有一些限制:
android a2dp android-audiomanager android-bluetooth mediarouter
我正在开发一个使用蓝牙的 Android 应用程序,我想使用新的 Android 12 Bluetooth_SCAN 和 CONNECT 权限来消除对位置权限的需要
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
如蓝牙文档所示
问题是,该应用程序有一项主要功能和一项可选功能。主要功能在这些权限下运行良好。
然而,可选功能使用信标扫描。当使用“neverForLocation”标志时,Android 操作系统会从扫描中过滤掉这些信标。
注意:如果您在 android:usesPermissionFlags 中包含 neverForLocation,则会从扫描结果中过滤掉一些 BLE 信标。
如果从清单权限中删除了该标志,则在扫描期间会出现信标。
但是,如果我从清单中删除此标志,那么即使不想使用此功能的用户也必须提供位置权限,否则正常的 BLEScan 不会返回任何内容。这是我想避免提供的事实,即这些新权限的全部原因是避免询问用户位置。
有没有办法在向操作系统发出实际运行时请求权限时提供此标志,而不是在清单中声明它?任何帮助或想法表示赞赏。
android ×10
bluetooth ×3
a2dp ×2
java ×2
pairing ×2
android-12 ×1
android-wifi ×1
mediarouter ×1
sockets ×1