美文网首页
Android蓝牙2.0—SppUtils开发

Android蓝牙2.0—SppUtils开发

作者: CaoMeng | 来源:发表于2018-11-26 16:56 被阅读15次

    前言:

    从事Android开发两年多了,一直在搞蓝牙2.0、4.0、UsbHost等硬件方面通信,每次给生产做的工具老是出Bug,换一个蓝牙厂家的模块,感觉就有点问题,老是在想API都是一样的,为什么不能兼容所有厂家的蓝牙模块?其实是自己一直没去看源码,有时候源码一句话就觉得问题,百度了半天,或者在技术群里面问半天,还没人回复,终于下定决心自己做一个通用的蓝牙通信框架。一切都从源码开始:

    由于生产线检测蓝牙设备次数比较平凡,所以他们不想输入配对码,嫌弃这样太浪费时间了,最开始百度很多,搜索到ClsUtils的工具类,通过反射拿到BlueToothDevice.java类的方法通过设置pin码,确实能够解决自动配对的问题,但是问题来了,我的7.0Android手机就不行,最后通过Debug发现反射去拿setPairingConfirmation(boolean confirm)的时候出错了,原因是 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)这个权限只能系统应用拥有,第三方应用没有这个权限,所有在我的7.0系统手机上任然会出现输入配对码的Dialog。解决方式:参见下文

        /**
         * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
         * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
         *
         * @return true confirmation has been sent out
         *         false for error
         */
        @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
        public boolean setPairingConfirmation(boolean confirm) {
            if (sService == null) {
                Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
                return false;
            }
            try {
                return sService.setPairingConfirmation(this, confirm);
            } catch (RemoteException e) {Log.e(TAG, "", e);}
            return false;
        }
    

    EmpsunSppUtils

    使用集成:

    allprojects {
        repositories {
            google()
            jcenter()
            //在Project的grade文件中添加
            maven { url 'https://jitpack.io' }
        }
    }
    
    //在Module添加依赖
    implementation 'com.github.CHENDUEMPSUN:EmpsunSppUtils:v1.0.0'
    

    Step1:onCreat()

    //获得工具操作对象
    SppUtils sppUtils = new SppUtils(this);
    //开启蓝牙服务
    mSppUtils.setupService();
    mSppUtils.startService();
    

    Step2:onStart()

    public void onStart() {
         super.onStart();
         if(!mSppUtils.isBluetoothEnabled()) {
            //开启蓝牙
            mSppUtils.enable();
         } else {
            //开启服务
            if(!mSppUtils.isServiceAvailable()) {
                mSppUtils.setupService();
                mSppUtils.startService();
             }
        }
    }
    

    Step3:onDestroy()

    public void onDestroy() {
        super.onDestroy();
        //断开蓝牙连接
        if(mSppUtils.getServiceState() == SppState.STATE_CONNECTED) {
           mSppUtils.disconnect();
        }
        //停止服务
        mSppUtils.stopService();
    }
    

    搜索

    //开启搜索
    sppUtils.startDiscovery();
    //搜索的回调
    sppUtils.setOnDeviceCallBack(new SppUtils.OnDeviceCallBack() {
          @Override
          public void onDeviceCallBack(BluetoothDevice bluetoothDevice) {
                //search some BluetoothDevice
                
                }
            });
    

    连接

    mSppUtils.connect("蓝牙地址");
    mSppUtils.setBluetoothConnectionListener(new SppUtils.BluetoothConnectionListener() {
               public void onDeviceConnected(String name, String address) {
                   Toast.makeText(getApplicationContext(), "连接成功 " + name, Toast.LENGTH_SHORT).show();
               }
    
               public void onDeviceDisconnected() {
                   Toast.makeText(getApplicationContext(), "断开连接", Toast.LENGTH_SHORT).show();
               }
    
               public void onDeviceConnectionFailed() {
                   Toast.makeText(getApplicationContext(), "连接失败", Toast.LENGTH_SHORT).show();
               }
           });
    

    发送数据

    mSppUtils.send("byte数组", false);
    

    接收数据

    mSppUtils.setOnDataReceivedListener(new SppUtils.OnDataReceivedListener() {
             @Override
             public void onDataReceived(final byte[] data, String message) {
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
                         mReciveData.setText(mReciveData.getText()+ SppStringUtils.bytesToHexString(data));
                     }
                 });
    
             }
         });
    

    断开连接

    //断开蓝牙连接
    if(mSppUtils.getServiceState() == SppState.STATE_CONNECTED) {
         mSppUtils.disconnect();
      }
    

    清除已配对的设备

    mSppUtils.unPairDevices();
    

    16进制字符串与byte数组的转换

    mSppUtils.bytesToHexString();
    mSppUtils.hexStringToBytes();
    

    备注:

    1、在Library中加入定位权限,不然在Android6.0以上系统上使用,搜索不到蓝牙

    2、本Module采用通信方式为非安全模式 不需要通过输入pin码进行配对

    private class ConnectThread extends Thread {
          private final BluetoothSocket mmSocket;
          private final BluetoothDevice mmDevice;
          private String mSocketType;
    
          public ConnectThread(BluetoothDevice device) {
              mmDevice = device;
              BluetoothSocket tmp = null;
              try {
                  //Android2.3以下的API 这种方式会需要pin码 安全通信
                  //tmp = device.createRfcommSocketToServiceRecord(UUID_DEVICE);
                  //这种方式会不需要pin码 非安全通信
                  tmp = device.createInsecureRfcommSocketToServiceRecord(UUID_DEVICE);
    
              } catch (IOException e) {
    
              }
              mmSocket = tmp;
          }
    
          public void run() {
              //总是取消搜索,因为它会减慢连接速度
              mAdapter.cancelDiscovery();
              try {
                  //这是一个阻塞调用,只会在连接成功或异常时返回
                  mmSocket.connect();
              } catch (IOException e) {
                  try {
                      mmSocket.close();
                  } catch (IOException e2) {
    
                  }
                  connectionFailed();
                  return;
              }
    
              // Reset the ConnectThread because we're done
              synchronized (SppService.this) {
                  mConnectThread = null;
              }
              connected(mmSocket, mmDevice, mSocketType);
          }
    
          public void cancel() {
              try {
                  mmSocket.close();
                  Log.e(TAG,"ConnectThread: mmSocket.close()");
              } catch (IOException e) {
    
              }
          }
      }
    

    3、市面上有很多通过反射拿到BlueDevice的方法设置pin码,进行自动配对。但是这种只适用于Androidx.x以下系统,x.x以上系统同样会弹出输入pin码的Dialog,因为x.x之后:@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)这个是系统应用权限,第三方应用根本没有这个权限,在x.x上反射是拿不到这个方法的,所以x.x以上系统实现不了自动配对,依然是弹出对话框输入pin码。(具体是哪个系统版本暂未查证)
    除非:采用非安全通信方式就不需要输入pin码

        /**
       * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
       *
       * @return true confirmation has been sent out
       *         false for error
       */
      @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
      public boolean setPairingConfirmation(boolean confirm) {
          if (sService == null) {
              Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
              return false;
          }
          try {
              return sService.setPairingConfirmation(this, confirm);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
          return false;
      }
    
    

    Demo参见:https://github.com/CHENDUEMPSUN/EmpsunSppUtils

    相关文章

      网友评论

          本文标题:Android蓝牙2.0—SppUtils开发

          本文链接:https://www.haomeiwen.com/subject/rhibqqtx.html