Android - 无法连接到 Lollipop 上的蓝牙设备
Android - Could not connect to bluetooth device on Lollipop
我有一个在 Android 4.3 和 4.4 上运行良好的应用程序。
该应用程序将与自定义蓝牙设备进行连接和通信。
在我将 Nexus 5 刷入 Lollipop 后,我突然无法连接到该设备。连接结果总是133。这是日志:
D/BluetoothGatt﹕ connect() - device: 00:07:80:04:1A:5A, auto: true
D/BluetoothGatt﹕ registerApp()
D/BluetoothGatt﹕ registerApp() - UUID=xxxxxx-xxxx-xxxxx-xxxx-xxxxxxxx
D/BluetoothGatt﹕ onClientRegistered() - status=0 clientIf=6
D/BluetoothGatt﹕ onClientConnectionState() - status=133 clientIf=6 device=00:07:80:04:1A:5A
我的代码:
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
return false;
}
Handler handler = new Handler(Looper.getMainLooper());
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
handler.post(new Runnable() {
@Override
public void run() {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
}
}
});
if (mConnectionState == STATE_CONNECTING) {
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
handler.post(new Runnable() {
@Override
public void run() {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
});
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
有人对此有任何想法吗?
所以我发现问题出在 Lollipop 中的传输选择。
正如您在 here 中看到的
中的变化
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
函数正在调用
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)
传输设置为 TRANSPORT_AUTO。
就我而言,因为我将始终使用 TRANSPORT_LE(值为 2)
我尝试从我的代码中调用第二种方法并将传输设置为 TRANSPORT_LE。
由于未知原因,我不能直接调用它,所以我使用反射来调用它。
到目前为止,这对我来说很好。
if(TTTUtilities.isLollipopOrAbove()) {
// Little hack with reflect to use the connect gatt with defined transport in Lollipop
Method connectGattMethod = null;
try {
connectGattMethod = device.getClass().getMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mBluetoothGatt = (BluetoothGatt) connectGattMethod.invoke(device, BluetoothConnectService.this, false, mGattCallback, TRANSPORT_LE);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
如果您对我的回答有任何疑问,请随时在评论中提问。
谢谢。
我认为自己使用反射调用 connectGatt 方法不是明智之举。由于私有函数可以随更新随时更改,因此您的应用程序会出现错误。
而且无论如何 TRANSPORT_AUTO 如果在您的外设广告数据包中设置了适当的标志,则应该尝试以所需的方式连接到您的外设。如果您的外围设备不支持 TRANSPORT_BREDR 模式,那么您应该在广告数据中设置一个标准标志 "BrEdrNotSupported" 让中央知道它。
您使用的是哪种 BLE IC?如果是 CC254x 可能与他们的外围设备软件栈问题有关:
https://e2e.ti.com/support/wireless_connectivity/f/538/t/401240
对于遇到相同问题的 Xamarin 用户,这里有一个稍微不同的解决方案。我在使用 Xamarin 跨平台 SDK 的 Nexus 7 Android 6 上遇到了同样的问题。使用 TRANSPORT_LE 解决了这个问题。与其使用 Reflection 通过其签名获取方法(不起作用),不如使用 Reflection 遍历所有方法,直到找到匹配的名称。请参阅下面的代码:
BluetoothDevice bd = (BluetoothDevice)device.NativeDevice;
Java.Lang.Reflect.Method[] methods = bd.Class.GetDeclaredMethods();
foreach (Java.Lang.Reflect.Method possibleConnectGattMethod in methods)
{
// Find matching method name connectGatt and then invoke it with TRANSPORT_LE
}
我有一个在 Android 4.3 和 4.4 上运行良好的应用程序。
该应用程序将与自定义蓝牙设备进行连接和通信。
在我将 Nexus 5 刷入 Lollipop 后,我突然无法连接到该设备。连接结果总是133。这是日志:
D/BluetoothGatt﹕ connect() - device: 00:07:80:04:1A:5A, auto: true
D/BluetoothGatt﹕ registerApp()
D/BluetoothGatt﹕ registerApp() - UUID=xxxxxx-xxxx-xxxxx-xxxx-xxxxxxxx
D/BluetoothGatt﹕ onClientRegistered() - status=0 clientIf=6
D/BluetoothGatt﹕ onClientConnectionState() - status=133 clientIf=6 device=00:07:80:04:1A:5A
我的代码:
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
return false;
}
Handler handler = new Handler(Looper.getMainLooper());
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
handler.post(new Runnable() {
@Override
public void run() {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
}
}
});
if (mConnectionState == STATE_CONNECTING) {
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
handler.post(new Runnable() {
@Override
public void run() {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
});
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
有人对此有任何想法吗?
所以我发现问题出在 Lollipop 中的传输选择。
正如您在 here 中看到的
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
函数正在调用
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)
传输设置为 TRANSPORT_AUTO。
就我而言,因为我将始终使用 TRANSPORT_LE(值为 2)
我尝试从我的代码中调用第二种方法并将传输设置为 TRANSPORT_LE。
由于未知原因,我不能直接调用它,所以我使用反射来调用它。
到目前为止,这对我来说很好。
if(TTTUtilities.isLollipopOrAbove()) {
// Little hack with reflect to use the connect gatt with defined transport in Lollipop
Method connectGattMethod = null;
try {
connectGattMethod = device.getClass().getMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mBluetoothGatt = (BluetoothGatt) connectGattMethod.invoke(device, BluetoothConnectService.this, false, mGattCallback, TRANSPORT_LE);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
mBluetoothGatt = device.connectGatt(BluetoothConnectService.this, true, mGattCallback);
}
如果您对我的回答有任何疑问,请随时在评论中提问。
谢谢。
我认为自己使用反射调用 connectGatt 方法不是明智之举。由于私有函数可以随更新随时更改,因此您的应用程序会出现错误。
而且无论如何 TRANSPORT_AUTO 如果在您的外设广告数据包中设置了适当的标志,则应该尝试以所需的方式连接到您的外设。如果您的外围设备不支持 TRANSPORT_BREDR 模式,那么您应该在广告数据中设置一个标准标志 "BrEdrNotSupported" 让中央知道它。
您使用的是哪种 BLE IC?如果是 CC254x 可能与他们的外围设备软件栈问题有关:
https://e2e.ti.com/support/wireless_connectivity/f/538/t/401240
对于遇到相同问题的 Xamarin 用户,这里有一个稍微不同的解决方案。我在使用 Xamarin 跨平台 SDK 的 Nexus 7 Android 6 上遇到了同样的问题。使用 TRANSPORT_LE 解决了这个问题。与其使用 Reflection 通过其签名获取方法(不起作用),不如使用 Reflection 遍历所有方法,直到找到匹配的名称。请参阅下面的代码:
BluetoothDevice bd = (BluetoothDevice)device.NativeDevice;
Java.Lang.Reflect.Method[] methods = bd.Class.GetDeclaredMethods();
foreach (Java.Lang.Reflect.Method possibleConnectGattMethod in methods)
{
// Find matching method name connectGatt and then invoke it with TRANSPORT_LE
}