当前位置:   article > 正文

Android蓝牙——BLE的开启、搜索、配对与连接_android 蓝牙连接

android 蓝牙连接

1、权限

首先需要在AndroidManifest中申请如下权限。

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

2、获得蓝牙管理对象

BluetoothManager的主要作用是从中得到我们需要的对象

  1. //@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
  2. //首先获取BluetoothManager
  3. BluetoothManager bluetoothManager=(BluetoothManager) context.getService(Context.BLUETOOTH_SERVICE);

3、获得蓝牙适配器

蓝牙适配器是我们操作蓝牙的主要对象,可以从中获得配对过的蓝牙集合,可以获得蓝牙传输对象等等

  1. //获取BluetoothAdapter
  2. if (bluetoothManager != null)
  3. BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();

4、注册广播来接收蓝牙配对信息

蓝牙搜索结果,蓝牙状态变化是通过广播的方式通知APP的,APP需要在蓝牙开启前注册广播

  1. // 用BroadcastReceiver来取得搜索结果
  2. IntentFilter intent = new IntentFilter();
  3. intent.addAction(BluetoothDevice.ACTION_FOUND);//搜索发现设备
  4. intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变
  5. intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);//行动扫描模式改变了
  6. intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//动作状态发生了变化
  7. context.registerReceiver(searchDevices, intent);

5、反注册广播和清楚蓝牙连接

在不需要使用蓝牙的时候调用,反注册广播取消蓝牙的配对

  1. /**
  2. * 反注册广播取消蓝牙的配对
  3. *
  4. * @param context
  5. */
  6. public void unregisterReceiver(Context context) {
  7. context.unregisterReceiver(searchDevices);
  8. if (mBluetoothAdapter != null)
  9. mBluetoothAdapter.cancelDiscovery();
  10. }

6、蓝牙接收广播

  1. /**
  2. * 蓝牙接收广播
  3. */
  4. private BroadcastReceiver searchDevices = new BroadcastReceiver() {
  5. //接收
  6. public void onReceive(Context context, Intent intent) {
  7. String action = intent.getAction();
  8. Bundle b = intent.getExtras();
  9. Object[] lstName = b.keySet().toArray();
  10. // 显示所有收到的消息及其细节
  11. for (int i = 0; i < lstName.length; i++) {
  12. String keyName = lstName[i].toString();
  13. Log.e("bluetooth", keyName + ">>>" + String.valueOf(b.get(keyName)));
  14. }
  15. BluetoothDevice device;
  16. // 搜索发现设备时,取得设备的信息;注意,这里有可能重复搜索同一设备
  17. if (BluetoothDevice.ACTION_FOUND.equals(action)) {
  18. device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  19. onRegisterBltReceiver.onBluetoothDevice(device);
  20. }
  21. //状态改变时
  22. else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
  23. device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  24. switch (device.getBondState()) {
  25. case BluetoothDevice.BOND_BONDING://正在配对
  26. Log.d("BlueToothTestActivity", "正在配对......");
  27. onRegisterBltReceiver.onBltIng(device);
  28. break;
  29. case BluetoothDevice.BOND_BONDED://配对结束
  30. Log.d("BlueToothTestActivity", "完成配对");
  31. onRegisterBltReceiver.onBltEnd(device);
  32. break;
  33. case BluetoothDevice.BOND_NONE://取消配对/未配对
  34. Log.d("BlueToothTestActivity", "取消配对");
  35. onRegisterBltReceiver.onBltNone(device);
  36. default:
  37. break;
  38. }
  39. }
  40. }
  41. };

6、注册蓝牙回调广播

  1. /**
  2. * 注册蓝牙回调广播
  3. */
  4. private void blueToothRegister() {
  5. BltManager.getInstance().registerBltReceiver(this, new BltManager.OnRegisterBltReceiver() {
  6. /**搜索到新设备
  7. * @param device
  8. */
  9. @Override
  10. public void onBluetoothDevice(BluetoothDevice device) {
  11. if (bltList != null && !bltList.contains(device)) {
  12. bltList.add(device);
  13. }
  14. if (myAdapter != null)
  15. myAdapter.notifyDataSetChanged();
  16. }
  17. /**连接中
  18. * @param device
  19. */
  20. @Override
  21. public void onBltIng(BluetoothDevice device) {
  22. btl_bar.setVisibility(View.VISIBLE);
  23. blt_status_text.setText("连接" + device.getName() + "中……");
  24. }
  25. /**连接完成
  26. * @param device
  27. */
  28. @Override
  29. public void onBltEnd(BluetoothDevice device) {
  30. btl_bar.setVisibility(View.GONE);
  31. blt_status_text.setText("连接" + device.getName() + "完成");
  32. }
  33. /**取消链接
  34. * @param device
  35. */
  36. @Override
  37. public void onBltNone(BluetoothDevice device) {
  38. btl_bar.setVisibility(View.GONE);
  39. blt_status_text.setText("取消了连接" + device.getName());
  40. }
  41. });
  42. }

7、打开蓝牙

判断当前设备是否支持蓝牙,如果支持则打开蓝牙

  1. /**
  2. * 判断是否支持蓝牙,并打开蓝牙
  3. * 获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。
  4. * 如果没打开,需要让用户打开蓝牙:
  5. */
  6. public void checkBleDevice(Context context) {
  7. if (mBluetoothAdapter != null) {
  8. if (!mBluetoothAdapter.isEnabled()) {
  9. Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  10. enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  11. context.startActivity(enableBtIntent);
  12. }
  13. } else {
  14. Log.i("blueTooth", "该手机不支持蓝牙");
  15. }
  16. }

8、搜索蓝牙

        搜索后添加到自定义的集合中以供自身程序的逻辑使用。注意:搜索到的结果会在广播中回调过来,这里不做回调。若使用过时的接口,则在当前逻辑里回调结果。我们这里使用广播,不建议使用过时的方法。

  1. /**
  2. * 搜索蓝牙设备
  3. * 通过调用BluetoothAdapter的startLeScan()搜索BLE设备。
  4. * 调用此方法时需要传入 BluetoothAdapter.LeScanCallback参数。
  5. * 因此你需要实现 BluetoothAdapter.LeScanCallback接口,BLE设备的搜索结果将通过这个callback返回。
  6. * <p/>
  7. * 由于搜索需要尽量减少功耗,因此在实际使用时需要注意:
  8. * 1、当找到对应的设备后,立即停止扫描;
  9. * 2、不要循环搜索设备,为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描,消耗电量。
  10. * <p/>
  11. * 如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。
  12. * 其中UUID数组指定你的应用程序所支持的GATT Services的UUID。
  13. * <p/>
  14. * 注意:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索。
  15. */
  16. private boolean startSearthBltDevice(Context context) {
  17. //开始搜索设备,当搜索到一个设备的时候就应该将它添加到设备集合中,保存起来
  18. checkBleDevice(context);
  19. //如果当前发现了新的设备,则停止继续扫描,当前扫描到的新设备会通过广播推向新的逻辑
  20. if (getmBluetoothAdapter().isDiscovering())
  21. stopSearthBltDevice();
  22. Log.i("bluetooth", "本机蓝牙地址:" + getmBluetoothAdapter().getAddress());
  23. //开始搜索
  24. mBluetoothAdapter.startDiscovery();
  25. //这里的true并不是代表搜索到了设备,而是表示搜索成功开始。
  26. return true;
  27. }

9、停止搜索蓝牙设备

  1. public boolean stopSearthBltDevice() {
  2. //暂停搜索设备
  3. if(mBluetoothAdapter!=null)
  4. return mBluetoothAdapter.cancelDiscovery();
  5. }

10、连接蓝牙

注意:连接蓝牙的前提是我们已经建立好了蓝牙服务器端。所以,这里我们先建立蓝牙服务器 ——1)先建立蓝牙服务器端

  1. /**
  2. * 这个操作应该放在子线程中,因为存在线程阻塞的问题
  3. */
  4. public void run(Handler handler) {
  5. //服务器端的bltsocket需要传入uuid和一个独立存在的字符串,以便验证,通常使用包名的形式
  6. BluetoothServerSocket bluetoothServerSocket = tmBluetoothAdapter.listenUsingRfcommWithServiceRecord("com.bluetooth.demo", BltContant.SPP_UUID);
  7. while (true) {
  8. try {
  9. //注意,当accept()返回BluetoothSocket时,socket已经连接了,因此不应该调用connect方法。
  10. //这里会线程阻塞,直到有蓝牙设备链接进来才会往下走
  11. socket = getBluetoothServerSocket().accept();
  12. if (socket != null) {
  13. BltAppliaction.bluetoothSocket = socket;
  14. //回调结果通知
  15. Message message = new Message();
  16. message.what = 3;
  17. message.obj = socket.getRemoteDevice();
  18. handler.sendMessage(message);
  19. //如果你的蓝牙设备只是一对一的连接,则执行以下代码
  20. getBluetoothServerSocket().close();
  21. //如果你的蓝牙设备是一对多的,则应该调用break;跳出循环
  22. //break;
  23. }
  24. } catch (IOException e) {
  25. try {
  26. getBluetoothServerSocket().close();
  27. } catch (IOException e1) {
  28. e1.printStackTrace();
  29. }
  30. break;
  31. }
  32. }
  33. }

——2)在蓝牙服务器建立之后,再进行连接蓝牙的操作。

  1. /**
  2. * 尝试连接一个设备,子线程中完成,因为会线程阻塞
  3. *
  4. * @param btDev 蓝牙设备对象
  5. * @param handler 结果回调事件
  6. * @return
  7. */
  8. private void connect(BluetoothDevice btDev, Handler handler) {
  9. try {
  10. //通过和服务器协商的uuid来进行连接
  11. mBluetoothSocket = btDev.createRfcommSocketToServiceRecord(BltContant.SPP_UUID);
  12. if (mBluetoothSocket != null)
  13. //全局只有一个bluetooth,所以我们可以将这个socket对象保存在appliaction中
  14. BltAppliaction.bluetoothSocket = mBluetoothSocket;
  15. //通过反射得到bltSocket对象,与uuid进行连接得到的结果一样,但这里不提倡用反射的方法
  16. //mBluetoothSocket = (BluetoothSocket) btDev.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(btDev, 1);
  17. Log.d("blueTooth", "开始连接...");
  18. //在建立之前调用
  19. if (getmBluetoothAdapter().isDiscovering())
  20. //停止搜索
  21. getmBluetoothAdapter().cancelDiscovery();
  22. //如果当前socket处于非连接状态则调用连接
  23. if (!getmBluetoothSocket().isConnected()) {
  24. //你应当确保在调用connect()时设备没有执行搜索设备的操作。
  25. // 如果搜索设备也在同时进行,那么将会显著地降低连接速率,并很大程度上会连接失败。
  26. getmBluetoothSocket().connect();
  27. }
  28. Log.d("blueTooth", "已经链接");
  29. if (handler == null) return;
  30. //结果回调
  31. Message message = new Message();
  32. message.what = 4;
  33. message.obj = btDev;
  34. handler.sendMessage(message);
  35. } catch (Exception e) {
  36. Log.e("blueTooth", "...链接失败");
  37. try {
  38. getmBluetoothSocket().close();
  39. } catch (IOException e1) {
  40. e1.printStackTrace();
  41. }
  42. e.printStackTrace();
  43. }
  44. }

11、自动连接以往配对成功的设备

注意:连接的前提是服务器端已开启,若没开启则进行8.1的操作

  1. /**
  2. * 尝试配对和连接
  3. *
  4. * @param btDev
  5. */
  6. public void createBond(BluetoothDevice btDev, Handler handler) {
  7. if (btDev.getBondState() == BluetoothDevice.BOND_NONE) {
  8. //如果这个设备取消了配对,则尝试配对
  9. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  10. btDev.createBond();
  11. }
  12. } else if (btDev.getBondState() == BluetoothDevice.BOND_BONDED) {
  13. //如果这个设备已经配对完成,则尝试连接
  14. connect(btDev, handler);
  15. }
  16. }
  17. /**
  18. * 获得系统保存的配对成功过的设备,并尝试连接
  19. */
  20. public void getBltList() {
  21. if (getmBluetoothAdapter() == null) return;
  22. //获得已配对的远程蓝牙设备的集合
  23. Set<BluetoothDevice> devices = getmBluetoothAdapter().getBondedDevices();
  24. if (devices.size() > 0) {
  25. for (Iterator<BluetoothDevice> it = devices.iterator(); it.hasNext(); ) {
  26. BluetoothDevice device = it.next();
  27. //自动连接已有蓝牙设备
  28. createBond(device, null);
  29. }
  30. }
  31. }

        外界只需要调用getBltList();方法即可进行自动连接。

12、输入mac地址自动连接设备

        前提是系统原来连接过该地址。

  1. /**
  2. * 输入mac地址进行自动配对
  3. * 前提是系统保存了该地址的对象
  4. *
  5. * @param address
  6. */
  7. public void autoConnect(String address, Handler handler) {
  8. if (getmBluetoothAdapter().isDiscovering()) getmBluetoothAdapter().cancelDiscovery();
  9. BluetoothDevice btDev = getmBluetoothAdapter().getRemoteDevice(address);
  10. connect(btDev, handler);
  11. }

13、蓝牙连接状态

        用于我们判断该蓝牙设备是出于:未配对还是配对未连接还是已连接状态

  1. public String bltStatus(int status) {
  2. String a = "未知状态";
  3. switch (status) {
  4. case BluetoothDevice.BOND_BONDING:
  5. a = "连接中";
  6. break;
  7. case BluetoothDevice.BOND_BONDED:
  8. a = "连接完成";
  9. break;
  10. case BluetoothDevice.BOND_NONE:
  11. a = "未连接/取消连接";
  12. break;
  13. }
  14. return a;
  15. }

14、蓝牙点击事件

包括蓝牙的打开,关闭,被搜索,断开连接

  1. /**
  2. * 蓝牙操作事件
  3. *
  4. * @param context
  5. * @param status
  6. */
  7. public void clickBlt(Context context, int status) {
  8. switch (status) {
  9. case BltContant.BLUE_TOOTH_SEARTH://搜索蓝牙设备,在BroadcastReceiver显示结果
  10. startSearthBltDevice(context);
  11. break;
  12. case BltContant.BLUE_TOOTH_OPEN://本机蓝牙启用
  13. if (getmBluetoothAdapter() != null)
  14. getmBluetoothAdapter().enable();//启用
  15. break;
  16. case BltContant.BLUE_TOOTH_CLOSE://本机蓝牙禁用
  17. if (getmBluetoothAdapter() != null)
  18. getmBluetoothAdapter().disable();//禁用
  19. break;
  20. case BltContant.BLUE_TOOTH_MY_SEARTH://本机蓝牙可以在300s内被搜索到
  21. Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
  22. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
  23. context.startActivity(discoverableIntent);
  24. break;
  25. case BltContant.BLUE_TOOTH_CLEAR://本机蓝牙关闭当前连接
  26. try {
  27. if (getmBluetoothSocket() != null)
  28. getmBluetoothSocket().close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. break;
  33. }
  34. }

        到此,蓝牙从打开到连接的方法都写完了。最后我们来总结一下。

        当我们获得到了bluetoothsocket对象的时候,我们就可以像使用socket编程一样,让两个蓝牙之间传输数据。甚至可以在程序内部监听蓝牙耳机的暂停/播放/音量键等的点击事件。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/956040
推荐阅读
相关标签
  

闽ICP备14008679号