我的公司正在开发一个使用多个因素(例如密码,指纹,位置和...蓝牙)的多因素身份验证库。对于蓝牙,使用蓝牙发现功能简单地检测设备是否在附近(任何人都可以广播信号)对于我们来说是不安全的,并且在使用蓝牙服务初始化应用程序后检测设备是否已连接是不可行的。侦听器,因为用户本来已经连接了他们的设备,并且在用户每次要注册设备并稍后验证该设备已连接时要求用户断开连接并重新连接他们的设备,这是很糟糕的UX。理想的UX是在用户打开应用之前先连接设备,当用户尝试添加蓝牙作为安全因素时,我们的SDK会检测到当前已将哪些蓝牙设备连接到手机并将其添加到已注册设备列表中,最后,通过身份验证,可以通过查询蓝牙服务是否当前已连接来自动找到所连接的设备。
检测设备当前是否连接的唯一公开可用接口是使用BluetoothAdapter :: getBondedDevices()循环配对设备,然后检查该设备是否使用了SDK已提供给我们的代理之一(耳机,A2DP,健康等)与BluetoothDevice :: getProfileProxy(...)一起传递我们自己的BluetoothProfile.ServiceListener实现。 这是不够的,因为绝大多数蓝牙设备无法使用任何这些代理进行检测,因为它们不使用任何这些代理。值得注意的设备是Fitbit和Garmin设备。这与我们的iOS SDK形成对比,在iOS SDK中,iOS允许用户简单地检索所有连接的蓝牙设备,而无需使用代理。
我们所采用的解决方案是访问程序包专用功能BluetoothAdapter :: getBluetoothService(...)以获取对基础蓝牙服务(IBluetooth)的引用,然后查询是否使用IBluetooth连接了设备: getConnectionState(BluetoothDevice设备)。此方法使我们与iOS SDK处于同等地位,可检测到绝大多数已连接的蓝牙设备。
try {
Method method = mBluetooth.getClass().getDeclaredMethod("getBluetoothService", Class.forName("android.bluetooth.IBluetoothManagerCallback"));
method.setAccessible(true);
Object interfaceThing = method.invoke(mBluetooth, new Object[]{ null });
Method method2 = interfaceThing.getClass().getDeclaredMethod("getConnectionState", BluetoothDevice.class);
method2.setAccessible(true);
for (BluetoothDevice device : mBluetooth.getBondedDevices()) {
try {
boolean isConnected = (Integer) method2.invoke(interfaceThing, device) != 0;
if (isConnected) {
onBtDeviceDiscovered(device);
}
} catch (Exception e) {
Log.e("asdf", "onRefresh: ughugh");
}
}
} catch (Exception e) {
Log.e("asdf", "onRefresh: ughugh");
}
至少我问我们在Android P上继续使用此非SDK接口是否可以(即,从Play商店禁止实施我们SDK的任何人,特别是在Android P及更高版本上)他们终于开始关注这种事情。