文章类型: ANDROID
关键词: Android中如何实现蓝牙的配对与连接,Android,Bluetooth,蓝牙,配对,连接
内容摘要: Android中如何实现蓝牙的配对与连接

Android中如何实现蓝牙的配对与连接

2017/7/20 16:39:57    来源:apple    阅读:

Android中如何实现蓝牙的配对与连接


这段时间在项目中负责做蓝牙的设置模块,蓝牙这部分不算简单,自己先是花了一些时间看系统的蓝牙设置代码,感觉有点熟了才开动的,但期间还是踩了不少坑,有些问题网上也搜不到,现在做完了,有一些心得,记录下来。


1. AndroidManifest中添加蓝牙管理权限


<uses-permission android:name="android.permission.BLUETOOTH"/>

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>


2. 打开蓝牙


打开蓝牙有两种方式,发送蓝牙开启请求或代码后台自动打开蓝牙。


2.1 发送蓝牙开启请求


先判断BluetoothAdapter是不是为空,为空有可能是系统没有蓝牙模块,再判断蓝牙的状态是不是开启的,不是开启的就发送请求。


BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();

if (btAdapter != null && !btAdapter.isEnabled()) {

  Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

  startActivity(intent)

}


2.2 后台自动打开蓝牙


if (btAdapter != null && !btAdapter.isEnabled()) {

  btAdapter.enable();

}

3. 获取已经绑定(配对)的设备


Set<BluetoothDevice> bondedDevices = btAdapter.getBondedDevices();  //返回已绑定的蓝牙设备集


BluetoothDevice有如下方法:

  getBondState()  //获取设备绑定状态,BOND_NONE(未绑定), BOND_BONDING(正在绑定), BOND_BONDED(已绑定)

  getType()   //获取蓝牙类型,DEVICE_TYPE_CLASSIC(普通类型BR/EDR), DEVICE_TYPE_LE(低功耗类型), DEVICE_TYPE_DUAL(双类型BR/EDR/LE), DEVICE_TYPE_UNKNOWN(未知)

  getAddress()  //蓝牙地址

  getBluetoothClass()   //获取蓝牙类别(BluetoothClass),如手机、电脑、耳机,注意与蓝牙类型的区别

  getName()   //蓝牙设备名字


BluetoothClass蓝牙类别说明:

  目前有12个大类,定义在BluetoothClass.Device.Major下

BITMASK、MISC、COMPUTER、PHONE、NETWORKING、AUDIO_VIDEO、PERIPHERAL、IMAGING、WEARABLE、TOY、HEALTH、UNCATEGORIZED


  每个大类有若干个小类别,定义在BluetoothClass.Device下

  如: AUDIO_VIDEO_WEARABLE_HEADSET、AUDIO_VIDEO_HANDSFREE、AUDIO_VIDEO_RESERVED、AUDIO_VIDEO_MICROPHONE、AUDIO_VIDEO_LOUDSPEAKE

4. 监听蓝牙设备的变化


// 监听蓝牙设备的变化

IntentFilter filter = new IntentFilter();

filter.addAction(BluetoothDevice.ACTION_FOUND);  //发现新设备

filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);  //绑定状态改变

filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);  //开始扫描

filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);  //结束扫描

filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);  //连接状态改变

filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  //蓝牙开关状态改变

BluetoothReceiver receiver = new BluetoothReceiver();

mActivity.registerReceiver(receiver, filter);


...


private class BluetoothReceiver extends BroadcastReceiver {

  @Override

  public void onReceive(Context context, Intent intent) {

    switch(intent.getAction()) {

      case BluetoothAdapter.ACTION_FOUND:

        //获取扫描到的设备

        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

        //判断扫描到的设备是不是在已绑定设备列表中,在就跳过

        for (BluetoothDevice d: bondedDevices) {

          if (d.getAddress().equals(device.getAddress())) {

            return;

          }

        }

        mScannedDevices.add(device);

        break;


      case BluetoothAdapter.ACTION_DISCOVERY_STARTED:

        //开始扫描

        break;


      case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:

        //结束扫描

        break;


      case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:

        //绑定状态改变

        break;


      case BluetoothAdapter.ACTION_STATE_CHANGED:

        //蓝牙开关状态改变

        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);

        switch (state) {

          case BluetoothAdapter.STATE_OFF:

          break;

          case BluetoothAdapter.STATE_ON:

          break;

        }

        break;

    }

  }

}

5. 绑定蓝牙设备


绑定比较简单,调用 BluetoothDevice的createBond就一句代码,调用后就开始尝试绑定。


private boolean createBond(BluetoothDevice device) {

  return device.createBond();

}

绑定成功后会触发刚注册的蓝牙监听器,action为 ACTION_BOND_STATE_CHANGED


6. 取消绑定


BluetoothDevice绑定的方法是开放的,取消绑定的方法却是隐藏的,只对系统app开放,坑爹,只能用反射来解决了。


private boolean removeBond(BluetoothDevice device) {

  Class btDeviceCls = BluetoothDevice.class;

  Method removeBond = btDeviceCls.getMethod("removeBond");

  removeBond.setAccessible(true);

  return (boolean) removeBond.invoke(device);

}

7. 连接


绑定(配对)和连接是两个不同的过程,绑定是指两个设备发现了对方的存在,可以获取到对方的名称、地址等信息,有能力建立起连接;连接是指两个设备共享了一个RFCOMM通道,有能力进行数据互传。确认绑定上了之后,才能开始连接。可以试试蓝牙音箱的连接过程,就是先点击一次,开始配对,配对成功后出现在已绑定的列表中,再点击一次,就开始连接,连接成功后蓝牙音箱就有声音了。 

这一步我吃了不少亏,网上搜到的都是下面的这种连接方式


UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

private void connect(BluetoothDevice device) {

  BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);

  socket.connect();

  ...


  socket.close();

}

这种连接是用蓝牙来进行Socket通信的,而我要做的是如何把手机上连上蓝牙耳机或蓝牙音箱,这种方式是不行的。 

折腾了好久,最后找到了下面的连接方法,专门针对AUDIO、VIDEO类型的蓝牙设备的连接。


 if (device.getBluetoothClass().getMajorDeviceClass() != BluetoothClass.Device.Major.AUDIO_VIDEO) {

     return;

 }

 btdapter.getProfileProxy(context, new BluetoothProfile.ServiceListener() {

     @Override

     public void onServiceConnected(int profile, BluetoothProfile proxy) {

         BluetoothHeadset bluetoothHeadset = (BluetoothHeadset) proxy;

         Class btHeadsetCls = BluetoothHeadset.class;

         try {

             Method connect = btHeadsetCls.getMethod("connect", BluetoothDevice.class);

             connect.setAccessible(true);

             connect.invoke(bluetoothHeadset, device);

         } catch (Exception e) {

             Log.e(TAG, e + "");

         }

     }


     @Override

     public void onServiceDisconnected(int profile) {


     }

 }, BluetoothProfile.HEADSET);

↑ 上一篇文章:Toast 在activity关闭后,还在显示的问题解决 关键词:Toast,在activity关闭后,还在显示的问题解决.. 发布日期:2017/6/29 11:25:47
↓ 下一篇文章:JAVA不经过Catch(Exception e)直接到finally或者退出原因 关键词:JAVA不经过Catch(Exception,e)直接到.. 发布日期:2017/7/20 16:41:18
相关文章:
android开发中在文件AndroidManifest.xml中出现警告"Not targeting the latest versions of Android" 关键词:android,警告,开发,文件,AndroidManifest.xml,Not,targeti.. 发布日期:2017-09-20 11:26
五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程 关键词:Android,开发环境,部署,搭建教程 发布日期:2017-03-08 11:13
android 两个应用之间的通信与调用 关键词:android,两个应用之间的通信与调用 发布日期:2017-05-10 15:32
相关目录:.NETANDROIDJAVA软件开发
我要评论
正在加载评论信息......