Classic Bluetooth 学习记录

蓝牙常用类及常用方法

BluetoothAdapter 蓝牙适配器
  • cancelDiscovery() 取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不再继续搜索,在销毁蓝牙广播前或与服务器连接前使用。
  • disable() 关闭蓝牙
  • enable() 打开蓝牙,这个方法打开蓝牙不会弹出提示,更多的时候我们需要问下用户是否打开,一下这两行代码同样是打开蓝牙,不过会提示用户:
    Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(intent, requestCode);
  • getAddress() 获取本地蓝牙地址
  • getDefaultAdapter() 获取默认BluetoothAdapter,唯一一个。
  • getName() 获取本地蓝牙名称
  • getRemoteDevice(String address) 根据蓝牙地址获取远程蓝牙设备
  • getState() 获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)
  • isDiscovering() 判断当前是否正在查找设备,是返回true
  • isEnabled() 判断蓝牙是否打开,已打开返回true,否则,返回false
  • listenUsingRfcommWithServiceRecord(String name,UUID uuid) 根据名称,UUID创建并返回BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步
  • startDiscovery()开始搜索,startDiscovery()方法是一个异步方法,调用后会立即返回。该方法会进行对其他蓝牙设备的搜索,该过程会持续12秒。该方法调用后,搜索过程实际上是在一个System Service中进行的,所以可以调用cancelDiscovery()方法来停止搜索(该方法可以在未执行discovery请求时调用)。
    请求Discovery后,系统开始搜索蓝牙设备,在这个过程中,系统会发送以下三个广播:
    ACTION_DISCOVERY_START:开始搜索
    ACTION_DISCOVERY_FINISHED:搜索结束
    ACTION_FOUND:找到设备,这个Intent中包含两个extra fields:EXTRA_DEVICE和EXTRA_CLASS,分别包含BluetooDevice和BluetoothClass。

BluetoothDevice 描述了一个蓝牙设备
  • createRfcommSocketToServiceRecord(UUIDuuid) 根据UUID创建并返回一个BluetoothSocket
  • getState() 蓝牙状态这里要说一下,只有在 BluetoothAdapter.STATE_ON 状态下才可以监听,具体可以看andrid api;
  • 这个类其他的方法,如getAddress(),getName(),同BluetoothAdapter

BluetoothServerSocket

这个类一种只有三个方法两个重载的accept(),accept(inttimeout)两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行!还有一点需要注意的是,这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端与客户端的两个BluetoothSocket的连接。


BluetoothSocket

跟BluetoothServerSocket相对,是客户端一共5个方法,不出意外,都会用到。

  • close(), 关闭
  • connect() 连接
  • getInptuStream() 获取输入流
  • getOutputStream() 获取输出流
  • getRemoteDevice() 获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备

BluetoothClass 描述了设备通用特性和功能的蓝牙类
  • class BluetoothClass.Device 定义所有设备类的常量
  1. public int getDeviceClass () 返回BluetoothClass中的设备类部分(主要的和较小的)
  2. public int getMajorDeviceClass () 返回BluetoothClass中设备类的主要部分
  • class BluetoothClass.Service 定义所有服务类的常量

蓝牙配对与取消配对
  • 蓝牙配对:
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
            //版本号大于23,可以直接用device.createBond(),小于23时则用反射
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                device.createBond();
                adapter.notifyDataSetChanged();
            } else {//适配
                try {
                    Method method = BluetoothDevice.class.getMethod("createBond");
                    method.invoke(device);
                    adapter.notifyDataSetChanged();
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
  • 取消配对:
                        //取消配对
                        //好像只有在信号范围内才有效  (像系统一样直接可以取消没找到方法???????)
                        Method method = BluetoothDevice.class.getMethod("removeBond", (Class[]) null);
                        method.invoke(device, (Object[]) null);
                        adapter.notifyDataSetChanged();
                        popupWindow.dismiss();
                        popupWindow = null;
                        Toast.makeText(MainActivity.this, "取消配对成功!", Toast.LENGTH_SHORT).show();
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                        Log.e("onClick", e + "");
                    }
                }

蓝牙信号强度
  • 获取蓝牙信号强度,在广播onReceive方法中通过intent获取
   @Override
    public void onReceive(Context context, Intent intent) {
        int rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);//获取信号强度
    }
  • 蓝牙强度Rssi的取值范围
    Rssi和接收功率有关,单位是dBm,一般为负值,反应的是信号的衰减程度,理想状态下(无衰减),Rssi = 0dBm,实际情况是,即使蓝牙设备挨得非常近,Rssi也只有-50dBm的强度,在传输过程中,不可避免要损耗。
    • 一般情况下,经典蓝牙强度
      1. -50 ~ 0dBm 信号强
      2. -70 ~-50dBm 信号中
      3. <-70dBm 信号弱
    • 低功耗蓝牙分四级
      1. -60 ~ 0 4
      2. -70 ~ -60 3
      3. -80 ~ -70 2
      4. <-80 1
  • rssi信号强度与距离的转换公式
    • d = 10^((abs(rssi) - A) / (10 * n))
    • 其中:d - 计算所得距离(单位:m),rssi - 接收信号强度,A - 发射端和接收端相隔1米时的信号强度,n - 环境衰减因子。

基本用法

  1. 获取本地蓝牙适配器
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  1. 打开蓝牙
 if (bluetoothAdapter == null) {
            Toast.makeText(this, "本设备没有蓝牙模块", Toast.LENGTH_SHORT).show();
            finish();
        } else if (!bluetoothAdapter.isEnabled()) {
            //直接开启蓝牙
//            bluetoothAdapter.enable();
            //请求开启蓝牙
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 0);
            }
  1. 搜索设备
private void startBluetooth() {
        if (adapter == null) {
            return;
        }
        if (bluetoothAdapter == null) {
            //创建蓝牙是配置
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        }
        bluetoothAdapter.startDiscovery();
        //创建广播接收蓝牙消息
        receiver = new BluetoothReceiver(this.adapter, bluetoothAdapter, this);
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        //注册蓝牙广播
        this.registerReceiver(receiver, filter);

    }

定义BroadcastReceiver:

 if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            adapter.add(device);
            adapter.notifyDataSetChanged();
        } else if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            context.unregisterReceiver(this);
        }
    }
  1. 建立连接
  • 服务器端:
BluetoothServerSocket serverSocket = mAdapter. listenUsingRfcommWithServiceRecord(serverSocketName,UUID);
serverSocket.accept();
  • 客户端:
final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
UUID uuid = UUID.fromString(SPP_UUID);
BluetoothSocket socket;
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
adapter.cancelDiscovery();
socket.connect();
  1. 数据传递
  • 获取数据
   //获取信息
   @Override
   public void run() {
       try {
           DataInputStream is = new DataInputStream(socket.getInputStream());
           Log.e("run", "" + is.readUTF());
           String msg;
           while ((msg = is.readUTF()) != null) {
               Message message = Message.obtain();
               message.what = 0;
               message.obj = "收到的消息-" + device.getName() + ":" + msg;
               if (mListener != null) {
                   mListener.getMase(message);
               }
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
  • 写入数据
   public void send(final String msg) {
      new Thread() {
          @Override
          public void run() {
              try {
                  DataOutputStream os = new DataOutputStream(socket.getOutputStream());
                  os.writeUTF(msg);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }.start();
  }

数据转换

使用socket.getInputStream接收到的数据是字节流,这样的数据是没法分析的,所以很多情况需要一个byte转十六进制String的函数:

public static String bytesToHex(byte[] bytes) {
  char[] hexChars = new char[bytes.length * 2];
  for ( int j = 0; j &lt; bytes.length; j++ ) {
      int v = bytes[j] &amp; 0xFF;
      hexChars[j * 2] = hexArray[v &gt;&gt;&gt; 4];
      hexChars[j * 2 + 1] = hexArray[v &amp; 0x0F];
  }
  return new String(hexChars);
}

猜你喜欢

转载自blog.csdn.net/lala_peng/article/details/86523431
今日推荐