如何在Android上以编程方式配对和连接HID蓝牙设备(蓝牙键盘)

12

我可以将蓝牙键盘配对,但无法连接使其成为输入设备。 我查看了开发者网站提供的文档 - http://developer.android.com/guide/topics/connectivity/bluetooth.html#Profiles

文档中指出,Android 蓝牙 API 提供以下蓝牙配置文件的实现,但您可以实现 BluetoothProfile 接口来编写自己的类以支持特定的蓝牙配置文件:

  • 耳机(Headset)
  • A2DP
  • 医疗健康设备(Health Device)

没有文档说明如何为 HID 蓝牙设备(键盘)实现 BluetoothProfile。

Android 已经为 HID 设备实现了蓝牙连接,但这些 API 是隐藏的。我尝试使用反射来使用它们,但是键盘并没有作为输入设备连接。这就是我所做的:

private void connect(final BluetoothDevice bluetoothDevice) {
    if(bluetoothDevice.getBluetoothClass().getDeviceClass() == 1344){
        final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
                @Override
                public void onServiceConnected(int profile, BluetoothProfile proxy) {
                    Log.i("btclass", profile + "");

                    if (profile == getInputDeviceHiddenConstant()) {
                        Class instance = null;
                        try {
                            //instance = Class.forName("android.bluetooth.IBluetoothInputDevice");
                            instance = Class.forName("android.bluetooth.BluetoothInputDevice");
                            Method connect = instance.getDeclaredMethod("connect", BluetoothDevice.class);
                            Object value = connect.invoke(proxy, bluetoothDevice);
                            Log.e("btclass", value.toString());
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }



                    }
                }

                @Override
                public void onServiceDisconnected(int profile) {

                }
            };

            mBluetoothAdapter.getProfileProxy(this, mProfileListener,getInputDeviceHiddenConstant());


    }

}

public static int getInputDeviceHiddenConstant() {
    Class<BluetoothProfile> clazz = BluetoothProfile.class;
    for (Field f : clazz.getFields()) {
        int mod = f.getModifiers();
        if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
            try {
                if (f.getName().equals("INPUT_DEVICE")) {
                    return f.getInt(null);
                }
            } catch (Exception e) {
                Log.e("", e.toString(), e);
            }
        }
    }
    return -1;
}

你成功地建立了HID连接吗?我遇到了一个问题,新版本的Android没有蓝牙HID配置文件。你用的是哪个Android版本? - DutchKevv
@DutchKev - 我在Android 4.4.2上尝试过了,就像我在下面回答的那样,你无法通过编程方式连接它。此外,我不知道更新的Android版本是否提供蓝牙HID配置文件。 - Passiondroid
1
感谢回复。请查看以下代码。昨晚我继续解决同一个问题,并取得了一些进展。当我首先通过正常的Android蓝牙连接处理程序“手动”连接时,我可以使用反射创建一个L2CAP蓝牙套接字。 - DutchKevv
2个回答

8

由于安全原因,第三方应用程序无法连接到蓝牙键盘,因为该应用程序可能是键盘记录器。因此,只能由用户手动完成。


2
你有这方面的任何来源吗? - Saba

1

这是我在Android Marshmallow(6.0)上使用的代码。为了启动L2CAP连接(HID所需)

public static BluetoothSocket createL2CAPBluetoothSocket(String address, int psm){
    return createBluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false,false, address, psm);
}

// method for creating a bluetooth client socket
private static BluetoothSocket createBluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, int port){
    Log.e(TAG, "Creating socket with " + address + ":" + port);

    try {
        Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
                int.class, int.class,boolean.class,boolean.class,String.class, int.class);
        constructor.setAccessible(true);
        BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(type,fd,auth,encrypt,address,port);
        return clientSocket;
    }catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

public Boolean connect(View v) {

    try {
        // TODO: Check bluetooth enabled
        mDevice = getController();

        if (mDevice != null) {
            Log.e(TAG, "Controller is paired");

            // Create socket
            mSocket = createL2CAPBluetoothSocket(mDevice.getAddress(), 0x1124);

            if (mSocket != null) {

                if (!mSocket.isConnected()) {
                    mSocket.connect();
                }

                Log.e(TAG, "Socket successfully created");

                ConnectedThread mConnectedThread = new ConnectedThread(mSocket);
                mConnectedThread.run();
            }

        } else {
            showToast("Controller is not connected");
        }

        return true;

    } catch (Exception e) {
        e.printStackTrace();

        if (e instanceof IOException){
            // handle this exception type
        } else {
            // We didn't expect this one. What could it be? Let's log it, and let it bubble up the hierarchy.

        }

        return false;
    }
}

private BluetoothDevice getController() {
    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

    if (pairedDevices.size() > 0) {
        for (BluetoothDevice device : pairedDevices) {
            if (device.getName().equals("Wireless Controller"))    // Change to match DS4 - node name
            {
                Log.d(TAG, "Found device named: " + device.getName());

                return device;
            }
        }
    }

    return null;
}

它仍然可能在创建服务时出现问题,您需要为设备设置正确的L2CAP PSAM,但希望它能有所帮助。

你能否在Android 6.0上以编程方式连接蓝牙键盘? - Passiondroid
@DutchKevv,你提到需要为设备设置正确的L2CAP PSAM。如果我正确解释你的代码,那么对于你的设备,它看起来是0x1124。你是如何发现这个值的?有没有一种方法可以运行来发现它,或者你是在设备制造商的文档中找到的? - superbeef150

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接