【问题标题】:How to programmatically pair a bluetooth device on Android如何以编程方式在 Android 上配对蓝牙设备
【发布时间】:2011-02-14 07:54:42
【问题描述】:

对于我的应用程序,我正在尝试以编程方式配对蓝牙设备。我可以显示要配对的设备的配对对话框,并且可以输入密码。当我按“配对”时,对话框被删除,没有任何反应。

我只需要支持 Android 2.0 及更高版本的设备。

目前我正在使用以下代码开始配对进度:


public void pairDevice(BluetoothDevice device) {
        String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
        Intent intent = new Intent(ACTION_PAIRING_REQUEST);
        String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
        intent.putExtra(EXTRA_DEVICE, device);
        String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
        int PAIRING_VARIANT_PIN = 0;
        intent.putExtra(EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

在开始配对请求之前,我会停止扫描新设备。

我的应用程序具有以下蓝牙权限:

  • android.permission.BLUETOOTH_ADMIN
  • android.permission.BLUETOOTH

【问题讨论】:

标签: android bluetooth


【解决方案1】:

我设法通过一个作为服务的应用程序自动请求与具有键盘功能的设备的配对过程,以检查特定类型设备的存在和“设置”应用程序的修改版本。

我不得不说我正在开发一个运行 Android 4.0.3 的自定义设备,没有外部控件(没有返回/主页/确认按钮):在启动时配对控制器完成,无需任何交互,直到 PIN 请求是强制性的。

首先,我创建了一个服务,在启动时启动一个活动(使用android.intent.action.BOOT_COMPLETEDandroid.permission.RECEIVE_BOOT_COMPLETED) 定期检查 onReceive 回调中是否存在 1344 类设备(键盘,根据请求输入数据的唯一方法):

public void onReceive(Context context, Intent intent) 
...
    BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
...
if(dev.getBluetoothClass().getDeviceClass() == 1344){...}

过滤后,我选择第一个可用的键盘,然后将 BT 地址传递给“设置”应用:

Intent btSettingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
btSettingsIntent.putExtra("btcontroller", dev.getAddress());
startActivityForResult(btSettingsIntent, 1);

棘手的部分是寻找调用配对过程的最佳位置。仅使用

intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);

引导我进入一个配对对话框,该对话框关闭后让我与设备配对,但无法使用。

深入研究 com.Android.settings.Bluetooth 的类,我发现了自己的方式

createDevicePreference(CachedBluetoothDevice cachedDevice) 

在 DeviceListPreferenceFragment 中。

从那里我确实将我之前选择的 BT 地址与即将出现的可用地址进行了比较,一旦成功匹配,我就会调用

cachedDevice.startPairing();

我知道,这很棘手并且需要访问 Android 源代码,但在自定义环境中它可以工作。

我希望这会有所帮助。

【讨论】:

  • 这没有回答问题
【解决方案2】:

这是我的答案:

在 onCreate() 中这样写:

    registerReceiver(incomingPairRequestReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST));

然后创建变量

private final BroadcastReceiver incomingPairRequestReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
            BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //pair from device: dev.getName()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                dev.setPairingConfirmation(true);
                //successfull pairing
            } else {
                //impossible to automatically perform pairing,
                //your Android version is below KITKAT
            }
        }
    }
};

【讨论】:

  • setPairingConfirmation(boolean confirm) 需要 BLUETOOTH_PRIVILEGED 权限,但此权限不适用于第三方应用程序。见Android Developers
【解决方案3】:

不幸的是,我认为您将获得的最好的结果是为用户打开设置/无线和网络/蓝牙设置,如下所示:

    Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
    startActivityForResult(intent, REQUEST_PAIR_DEVICE);

【讨论】:

  • 使用kiosk模式很麻烦,所以我选择打开蓝牙设置。
【解决方案4】:

使用反射,您可以从 BluetoothDevice 类调用方法 createBond。

看到这个帖子:How to unpair or delete paired bluetooth device programmatically on android?

解除配对也有解决办法。

【讨论】:

  • ..自 JB aka 4.1.x 以来已被删除
  • 它还没有被删除,这仍然适用于我的 4.3 Nexus 4 并且它仍然非常适合 source code
【解决方案5】:

Reflection is DODGY,不同厂商可以随意改变这些底层方法!我在这里的 10 台设备上测试了许多不同的应用程序,这些反射方法仅在大约 75% 的设备上完全有效。如果您想要一个适用于所有人的应用,在使用反射时要非常小心 - 尝试一些云测试,在 100 多台设备上测试您的应用并检查失败率。

在这种情况下,从 API 19 (KitKat 4.4) 开始根本不需要反射

BluetoothDevice 有新方法 CreateBond。

 private void pairDevice(BluetoothDevice device) {

            device.createBond();
    }

developer.android.com/reference/android/bluetooth/BluetoothDevice.html

【讨论】:

  • 可以在基于云的测试工具上测试蓝牙吗?
  • 最近没看,去年我试过,没有我联系的​​云测试公司允许我做这种类型的测试。
【解决方案6】:

您可能需要 startActivityForResult 而不仅仅是 startActivity?

其他选项是查看 BluetoothChat 应用程序示例并启动 RFComm 连接套接字,一旦启动套接字,配对请求就会自动出现,而无需发送单独的配对意图。这样你就不需要处理配对了。

http://developer.android.com/resources/samples/BluetoothChat/index.html

【讨论】:

    【解决方案7】:

    我正在使用这个类在我的客户端智能手机和服务器设备之间进行连接:

    private class ConnectThread extends Thread
    {
        private final BluetoothSocket mmSocket;
    
        private final UUID WELL_KNOWN_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
    
        public ConnectThread(BluetoothDevice device)
        {
            // Use a temporary object that is later assigned to mmSocket,because
            // mmSocket is final
            BluetoothSocket tmp = null;
    
            // Get a BluetoothSocket to connect with the given BluetoothDevice
            try
            {
                tmp = device.createRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
                //This is the trick
                Method m = device.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
                tmp = (BluetoothSocket) m.invoke(device, 1);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
    
            mmSocket = tmp;
        }
    
        public void run()
        {
            DebugLog.i(TAG, "Trying to connect...");
            // Cancel discovery because it will slow down the connection
            mBluetoothAdapter.cancelDiscovery();
    
            try
            {
                // Connect the device through the socket. This will block
                // until it succeeds or throws an exception
                mmSocket.connect();
                DebugLog.i(TAG, "Connection stablished");
            } catch (IOException connectException)
            {
                // Unable to connect; close the socket and get out
                DebugLog.e(TAG, "Fail to connect!", connectException);
                try
                {
                    mmSocket.close();
                } catch (IOException closeException)
                {
                    DebugLog.e(TAG, "Fail to close connection", closeException);
                }
                return;
            }
        }
    
        /** Will cancel an in-progress connection, and close the socket */
        public void cancel()
        {
            try
            {
                mmSocket.close();
            } catch (IOException e)
            {
            }
        }
    }
    

    首先,获取您要连接的BluetoothDevice 对象(列出配对设备或发现设备)。然后做:

    ConnectThread ct = new ConnectThread(device);
    ct.start();
    

    因为connect() 是一个阻塞调用,所以这个连接过程应该总是在一个独立于主活动线程的线程中执行。请参阅Android Developers 了解更多详细信息。

    【讨论】:

    • 我想实现一个设备通过蓝牙将图像发送到另一个设备..但我卡在接受线程..怎么办..??
    • @Umang,我的回答只是配对设备。他们之间交换信息是另一段历史。我建议您创建一个详细说明您的问题的帖子。
    【解决方案8】:

    我发现对 PAIRING_VARIANT_PIN 使用不同的值会导致不同的配对 UI 行为。

    查看此页面: http://code.google.com/p/backport-android-bluetooth/source/browse/trunk/backport-android-bluetooth201/src/backport/android/bluetooth/BluetoothDevice.java?spec=svn67&r=67

    我怀疑您遇到的问题是两台设备都是蓝牙 2.1,在这种情况下,配对请求会导致两台设备上都显示一个 6 位数的密钥。

    我能够实现的最佳结果是使用 PAIRING_VARIANT_PIN = 0。当我的应用程序提示时,我输入了 pin 1234,并且我的目标设备上出现了一个 6 位数的密码。配对用户界面完成,就是这样。

    您需要了解如何使用其他一些配对变体或配对变体引脚来发起蓝牙 2.1 配对请求。或者,您没有捕捉到正常运行的活动的结果。

    考虑到我一直在尝试这样做,我决定我的最终用户只需在使用我的应用程序之前使用 android 设置进行配对。

    【讨论】:

    • @Peter O. Stack Overflow 通知我您已编辑此内容。由于这是我的第一篇文章,如果您不介意,我有一些问题: - 我不记得我的原始信息,所以我看不到您删除的内容。有没有办法做到这一点? - 你有机会解决这个问题吗? - 有没有办法直接向用户发送消息,而不是做我现在正在做的事情?提前致谢。
    • 1.单击“已编辑”一词后的日期以查看编辑历史记录。 2. 不,我没有解决问题的办法,因为我对这个主题不太熟悉。 3. 不,不是直接的,就像在私人消息中那样。但如果任一用户的声望至少为 100,而另一个用户的声望至少为 20,则前一个用户可以create a gallery chat room 并邀请另一个用户进入。
    【解决方案9】:

    这就是我得到它的方式:

    Bluetooth device = mBtAdapter.getRemoteDevice(address);
    //address:11:23:FF:cc:22 
    Method m = device.getClass()        
     .getMethod("createBond", (Class[]) null);
             m.invoke(device, (Object[]) null); // send pairing dialog request
    
    After pairing//
           connectDevice(address);
    

    【讨论】:

      【解决方案10】:

      顺便说一句,除了我的评论之外,即使这些 ACTION 类型确实存在,也不是您使用它们的方式。这是一个例子:

      Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
      intent.putExtra(EXTRA_DEVICE, device);
      int PAIRING_VARIANT_PIN = 272;
      intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
      sendBroadcast(intent);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-30
        • 2012-12-23
        • 2011-09-16
        • 2012-03-25
        • 1970-01-01
        • 2014-03-13
        • 1970-01-01
        相关资源
        最近更新 更多