学而实习之 不亦乐乎

Android 经典蓝牙开发

2024-06-06 22:16:43

误区:接受第一个蓝牙项目时,想当然地认为传统蓝牙与低功耗蓝牙协议和工作方式是一样的,只是低功耗蓝牙更省电而已。其实这两者不仅工作方式不同,通信协议也是不同的。

一、权限申请

Android6.0搜索周围的蓝牙设备,需要位置权限 ACCESS_COARSE_LOCATION 和ACCESS_FINE_LOCATION 其中的一个,并且将手机的位置服务(定位 GPS)打开。

1、清单文件

<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />

<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!--模糊定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!--精准定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2、权限申请工具类(LocalUtils.java)

这个类用来检查GPS和定位权限,回调在Activity里面。

public class LocalUtils {

    //申请权限
    public static final int permission_LocationCode = 101;

    //打开gps定位
    public static final int open_GPSCode = 102;
    static String[] permissionsIndex;

    /**
     * 此方法用来检查gps和定位权限,先检查gps是否打开,在检查是否有定位权限
     * @param activity 上下文对象
     * @param permissions 权限的名称
     * @return
     */
    public static boolean checkLocalPermissiion(Activity activity, String[] permissions) {
        permissionsIndex = permissions;

        if (checkGPSIsOpen(activity)) {
            return checkPermissions(activity);
        } else {
            Toast.makeText(activity, "需要打开GPS", Toast.LENGTH_SHORT).show();
            goToOpenGPS(activity);
        }
        return false;
    }

    /**
     * 检查GPS是否打开
     *
     */
    public static boolean checkGPSIsOpen(Activity activity) {

        LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);

        if (locationManager == null)
            return false;
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    /**
     * 检查权限并申请权限
     */
    public static boolean checkPermissions(final Activity activity) {
        List<String> permissionDeniedList = new ArrayList<>();
        for (String permission : permissionsIndex) {
            int permissionCheck = ContextCompat.checkSelfPermission(activity, permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                return true;
            } else {
                permissionDeniedList.add(permission);
            }
        }

        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);

            ActivityCompat.requestPermissions(activity, deniedPermissions, permission_LocationCode);
        }
        return false;
    }

    /**
     * 去手机设置打开GPS
     *
     * @param activity
     */
    public static void goToOpenGPS(Activity activity) {
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        activity.startActivityForResult(intent, open_GPSCode);
    }
}

在Activity里面回调:

//GPS
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case LocalUtils.open_GPSCode://检查是否手机打开定位
            if (LocalUtils.checkGPSIsOpen(this)) {
                LocalUtils.checkLocalPermissiion(this, permissions);//检查定位权限
            } else {
                LocalUtils.goToOpenGPS(this);//打开GPS
            }
            break;
    }
}

/**
 * 权限回调
 */
@Override
public final void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case LocalUtils.permission_LocationCode://是否打开允许定位权限
            if (grantResults.length > 0) {
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        initClassica();//初始化经典蓝牙
                    }
                }
            }
            break;
    }

}

二、开启蓝牙

1、获取BluetoothAdapter

获取BluetoothAdapter两种方式:

方式一:

BluetoothManager systemService = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = systemService.getAdapter();

方式二:

BluetoothAdapter bluetoothAdapter =BluetoothAdapter.getDefaultAdapter();

2、判断设备是否支持蓝牙

如果 BluetoothAdapter.getDefaultAdapter()==null,不支持,否则支持。

3、开启蓝牙

/**
  * 自动打开蓝牙(同步)
  * 这个方法打开蓝牙会弹出提示
  * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功
  */
public void openBlueSync(Activity activity, int requestCode) {
    Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    activity.startActivityForResult(intent, requestCode);
}

三、扫描蓝牙

1、扫描蓝牙

/**
 * 扫描的方法 返回true 扫描成功
 * 通过接收广播获取扫描到的设备
 * @return
 */
public boolean scanBlueTooth() {
    //当前是否在扫描,如果是就取消当前的扫描,重新扫描
    if (bluetoothAdapter.isDiscovering()) {
        bluetoothAdapter.cancelDiscovery();
    }

    //此方法是个异步操作,一般搜索12秒
    return bluetoothAdapter.startDiscovery();
}

2、取消扫描

/**
 * 取消扫描蓝牙
 * @return true 为取消成功
 */
public boolean cancelScanBule() {
    return bluetoothAdapter.cancelDiscovery();
}

3、广播接收扫描的结果

系统自动回发送广播,告诉我们,扫描出来的蓝牙设备。定义接口回调广播中的结果(ClientCallBack.java)

public interface ClientCallBack {

    //开始扫描
    void onScanStarted();

    //扫描结束
    void onScanFinished();

    //扫描中
    void onScanning(BluetoothDevice device);

    //配对请求
    void onBondRequest();

    //配对成功
    void onBondSuccess(BluetoothDevice device);

    //正在配对
    void onBonding(BluetoothDevice device);

    //配对失败
    void onBondFail(BluetoothDevice device);

    //连接成功
    void onConnectSuccess();

    //连接失败
    void onConnectFail(String errorMsg);

    //连接关闭
    void onConnectClose();
}

BlueReceiver.java

public class BlueReceiver extends BroadcastReceiver {

  private String pin = "0000";  //此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
  private static final String TAG = "mcy_Receiver";
  private ClientCallBack callBack;

  public BlueReceiver(ClientCallBack callBack) {
      this.callBack = callBack;
  }

  public void setCallBack(ClientCallBack callBack){
      this.callBack=callBack;
  }

  //广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行
  @Override
  public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      Log.d(TAG, "action:" + action);
      BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
      if(callBack==null){
          return;
      }

      switch (action) {
          case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
              callBack.onScanStarted();
              break;
          case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
              callBack.onScanFinished();
              break;
          case BluetoothDevice.ACTION_FOUND:
              callBack.onScanning(device);
              break;
          case BluetoothDevice.ACTION_PAIRING_REQUEST:
                  callBack.onBondRequest();
              break;
          case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
              switch (device.getBondState()) {
                  case BluetoothDevice.BOND_NONE:
                      callBack.onBondFail(device);
                      break;
                  case BluetoothDevice.BOND_BONDING:
                      callBack.onBonding(device);
                      break;
                  case BluetoothDevice.BOND_BONDED:
                      callBack.onBondSuccess(device);
                      break;
              }
              break;
      }
  }
}

为了方便统一管理,把蓝牙的操作写在服务里面,ClassicsBlueToothService.java,因此,把广播注册在服务里面。

public class ClassicsBlueToothService extends Service {

    private IntentFilter filter;
    private BlueReceiver pinBlueReceiver;

    @Override
    public void onCreate() {
        super.onCreate();
        //获取蓝牙适配器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        //注册广播
        //蓝牙广播,系统自动发送广播,只要设置制定的 action 即可
        filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//结束扫描
        filter.addAction(BluetoothDevice.ACTION_FOUND);//发现设备
        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//发起配对请求
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//配对状态
        pinBlueReceiver = new BlueReceiver(blueCallBack);

        registerReceiver(pinBlueReceiver, filter);//注册广播
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(pinBlueReceiver);
    }
    ... ... ...
}

四、配对蓝牙

配对:

/**
 * 配对(配对成功与失败通过广播返回)
 * @param device
 */
public void pinBlueTooth(BluetoothDevice device) {
    if (device == null) {
        Log.e("mcy", "设备不可以为空");
        return;
    }

    //配对之前把扫描关闭
    if (bluetoothAdapter.isDiscovering()) {
        bluetoothAdapter.cancelDiscovery();
    }

    //判断设备是否配对,没有配对在配,配对了就不需要配了
    if (device.getBondState() == BluetoothDevice.BOND_NONE) {//BOND_NONE 没有配对状态
        Log.d("mcy", "attemp to bond:" + device.getName());
        try {
            boolean returnValue = device.createBond();
            Log.e("是否配对成功:", "" + returnValue);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.d("mcy", "配对失败");
        }
    }
}

取消配对:

/**
 * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
 *
 * @param device
 */
public void cancelPinBuleTooth(BluetoothDevice device) {
    if (device == null) {
        Log.d("mcy", "设备不可以为空");
        return;
    }

    //判断设备是否配对,没有配对就不用取消了
    if (device.getBondState() != BluetoothDevice.BOND_NONE) {
        Log.d("mcy", "配对--" + device.getName());
        try {
            Method removeBondMethod = device.getClass().getMethod("removeBond");
            Boolean returnValue = (Boolean) removeBondMethod.invoke(device);
            returnValue.booleanValue();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.d("mcy", "取消配对失败");
        }
    }
}

五、连接蓝牙

这里说一下 uuid 的问题,要想进行通信,客户端和服务端必须一致,否则连接失败,因为我用的手机进行的通讯,所以写了双向通信,既可以写也可以读。

连接蓝牙

注意:在连接蓝牙的同时,开启一个子线程,用来写入数据。

/**
 * @param uuid   用户指定的 uuid ,可随意写,只要格式对就行
 * @param device 连接的设备
 */
public void connectionBlueTooth(String uuid, BluetoothDevice device) {
    try {
        bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
        if (bluetoothSocket != null && !bluetoothSocket.isConnected()) {
            sendDataThread = new ClientThread(bluetoothSocket, blueCallBack);
            sendDataThread.start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

ClientThread.java

public class ClientThread extends Thread {

    private static final String TAG = "mcy";
    private ClientCallBack callBack;
    private BluetoothSocket bluetoothSocket = null;
    private Handler handler;
    private OutputStream outputStream;

    public ClientThread(BluetoothSocket bluetoothSocket, ClientCallBack callBack) {
        this.callBack = callBack;
        this.bluetoothSocket = bluetoothSocket;
    }

    /**
     * 写数据
     *
     * @param data
     */
    public void write(byte[] data) {
        Message message = new Message();
        message.obj = data;
        handler.sendMessage(message);
    }

    /**
     * 关闭各种连接连接
     */
    public void closeSocket() {
        try {
            outputStream.close();
            bluetoothSocket.close();
            callBack.onConnectClose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            bluetoothSocket.connect();
            outputStream = bluetoothSocket.getOutputStream();//读取需要发送的的数据
            Looper.prepare();
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    try {
                        byte[] data = (byte[]) msg.obj;
                        outputStream.write(data);
                        outputStream.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            callBack.onConnectSuccess();
            Looper.loop();
        } catch (IOException e) {
            callBack.onConnectFail(e.getMessage());
        }
    }
}

六、通信(实现双向通信)

1、客户端发送数据

/**
 * 写数据
 */
public void sendData(byte[] data) {
    if (sendDataThread != null) {
        sendDataThread.write(data);
    }
}

2、客户端接收数据

/**
 * 读数据
 */
public void readListern(String name, String uuid, ServiceCallback callBack) {
    acceptThread = new AcceptThread(name, uuid, bluetoothAdapter, callBack);
    acceptThread.start();
}

定义一个接口,来监听,收到数据的状态

public interface ServiceCallback {

    //连接成功
    void onConnectSuccess();

    //连接失败
    void onConnectFail(String errorMsg);

    //连接关闭
    void onConnectClose();

    //接收到的数据
    void onResultMessage(byte[] data);
}

开启一个子线程,用来监听服务端发过来的数据

public class AcceptThread extends Thread {

    private static final String TAG = "mcy";
    private ServiceCallback callBack;
    private BluetoothServerSocket serverSocket = null;
    private InputStream inputStream;
    private BufferedInputStream bufferedInputStream;
    private byte[] data;

    public AcceptThread(String name, String uuid, BluetoothAdapter bluetoothAdapter, ServiceCallback callBack) {
        this.callBack = callBack;
        try {
            serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(name, UUID.fromString(uuid));
        } catch (IOException e) {
            e.printStackTrace();
            callBack.onConnectFail(e.getMessage());
        }
    }

    /**
     * 关闭各种流和通信的socket
     */
    public void closeSocket() {
        try {
            inputStream.close();
            bufferedInputStream.close();
            serverSocket.close();
            callBack.onConnectClose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            final BluetoothSocket bluetoothSocket = serverSocket.accept();
            callBack.onConnectSuccess();
            inputStream = bluetoothSocket.getInputStream();//获取服务端发来的消息
            bufferedInputStream = new BufferedInputStream(inputStream);
            while (true) {
                int available =0;
                wh:
lable==0){
                    available=inputStream.available();
                }
                data = new byte[available];
                bufferedInputStream.read(data);
                callBack.onResultMessage(data);//回传数据
            }
        } catch (IOException e) {
            callBack.onConnectFail(e.getMessage());
            e.printStackTrace();
        }
    }
}

七、关闭各种通信

在第五步和第六步的子线程里均有关闭通信的方法

/**
 * 写数据断开连接
 *
 * @return
 */
public void cancleConnecion() {
    sendDataThread.closeSocket();
}

/**
 * 写数据断开连接
 *
 * @return
 */
public void cancleServiceConnecion() {
    acceptThread.closeSocket();
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "mcy";
    private TextView textView;
    private TextView textView2;
    private TextView textView3;
    private EditText editTxt;
    String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
    private final int openBTCode = 100;

    // ----------------经典蓝牙------------------
    private ClassicsBlueToothService.ClassicaBlueToothBind classicaBTBind;
    private ServiceConnection classicaConnection;
    private List<BluetoothDevice> devicesList = new ArrayList<>();
    private ClientCallBack blueCallBack;
    private String text = "";

    private String uuid = "6db14d27-04f1-4df8-98ca-356dfc16ee43";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //检查权限   >6.0以上版本需要动态的申请定位权限,< 6.0 清单文件声明了即可
        if (LocalUtils.checkLocalPermissiion(this, permissions)) {
            initClassica();
        }
    }


    private void initView() {
        textView = findViewById(R.id.textView);
        textView2 = findViewById(R.id.textView2);
        textView3 = findViewById(R.id.textView3);
        editTxt = findViewById(R.id.editTxt);
        findViewById(R.id.button5).setOnClickListener(this);
        findViewById(R.id.button11).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button5://经典--写数据
                text = editTxt.getText().toString();
                classicaBTBind.sendData(text.getBytes());
                break;
            case R.id.button11://低功耗--发送数据
                break;
        }
    }

    private void initClassica() {
        blueCallBack = new ClientCallBack() {
            @Override
            public void onScanStarted() {
                Log.e("mcy", "开始扫描");
            }

            @Override
            public void onScanFinished() {
                Log.e("mcy", "结束扫描");
            }

            @Override
            public void onScanning(BluetoothDevice device) {
                Log.e("mcy", "扫描到设备-->" + device.getName());
                if (!devicesList.contains(device)) {
                    //将设备加入列表数据中
                    devicesList.add(device);
                }
 
               textView.setText(textView.getText() + "\n" + device.getName());
                Log.e(TAG, "" + device.getName());

                //已配对的蓝牙
                if (device.getBondState() == BluetoothDevice.BOND_BONDED) {//BOND_BONDED 已经配对状态
                    textView2.setText(textView2.getText() + "\n" + device.getName());
                } else {
                    classicaBTBind.pinBlueTooth(devicesList.get(0));
                }
            }

            @Override
            public void onBondRequest() {
                Log.e("mcy", "开始配对");
            }

            @Override
            public void onBondFail(BluetoothDevice device) {
                Log.e("mcy", "取消配对");
            }

            @Override
            public void onBonding(BluetoothDevice device) {
                Log.e("mcy", "配对中");
            }

            @Override
            public void onBondSuccess(BluetoothDevice device) {
                Log.e("mcy", "配对成功");
                classicaBTBind.connectionBlueTooth(uuid, device);
                //registReadListener(); //测试使用,双端通讯
            }

            @Override
            public void onConnectSuccess() {
                Log.e("mcy", "连接成功");
            }

            @Override
            public void onConnectFail(String errorMsg) {
                Log.e("mcy", "连接失败" + errorMsg);
            }

            @Override
            public void onConnectClose() {
                Log.e("mcy", "连接关闭");
            }
        };

        classicaConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                classicaBTBind = ((ClassicsBlueToothService.ClassicaBlueToothBind) service);
                if (blueCallBack != null) {
                    classicaBTBind.setBlueCallback(blueCallBack);//设置广播监听
                }

                if (classicaBTBind.getAdapter() != null) {
                    //判断蓝牙是否开启
                    if (!classicaBTBind.getAdapter().isEnabled()) {
                        //打开蓝牙
                        openBlueSync(MainActivity.this, openBTCode);
                    } else {
                        //========================开始执行工作=============================
                        classicaBTBind.scanBlueTooth();//扫描蓝牙
                        registReadListener();//注册读数据事件
                    }
                } else {
                    Toast.makeText(MainActivity.this, "此设备不支持蓝牙", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                classicaBTBind = null;
            }
        };

        bindService(new Intent(this, ClassicsBlueToothService.class), classicaConnection, BIND_AUTO_CREATE);
    }

    //经典蓝牙注册读数据事件
    private void registReadListener() {
        classicaBTBind.readListern("Demo", uuid, new ServiceCallback() {

            @Override
            public void onConnectSuccess() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接成功~");
                    }
                });
            }

            @Override
            public void onConnectFail(final String errorMsg) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接失败" + errorMsg);
                    }
                });
            }

            @Override
            public void onConnectClose() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接关闭");
                    }
                });
            }

            @Override
            public void onResultMessage(final byte[] data) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView3.setText(new String(data));
                    }
                });
            }
        });
    }

    /**
     * 自动打开蓝牙(同步)
     * 这个方法打开蓝牙会弹出提示
     * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功
     */
    public void openBlueSync(Activity activity, int requestCode) {
        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        activity.startActivityForResult(intent, requestCode);
    }

    //GPS
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case LocalUtils.open_GPSCode://检查是否手机打开定位
                if (LocalUtils.checkGPSIsOpen(this)) {
                    LocalUtils.checkLocalPermissiion(this, permissions);
                } else {
                    LocalUtils.goToOpenGPS(this);
                }
                break;
        }
    }

    /**
     * 权限回调
     */
    @Override
    public final void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case LocalUtils.permission_LocationCode://是否打开允许定位权限
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            initClassica();//初始化经典蓝牙
                        }
                    }
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(classicaConnection);
    }
}

ClassicsBlueToothService.java:

public class ClassicsBlueToothService extends Service {

    private IntentFilter filter;
    private BlueReceiver pinBlueReceiver;
    private BluetoothAdapter bluetoothAdapter;
    private ClientThread sendDataThread;
    private BluetoothSocket bluetoothSocket;
    private ClientCallBack blueCallBack;
    private AcceptThread acceptThread;

    @Override
    public void onCreate() {
        super.onCreate();

        //获取蓝牙适配器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        //注册广播
        //蓝牙广播,系统自动发送广播,只要设置制定的 action 即可
        filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//结束扫描
        filter.addAction(BluetoothDevice.ACTION_FOUND);//发现设备
        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//发起配对请求
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//配对状态
        pinBlueReceiver = new BlueReceiver(blueCallBack);

        registerReceiver(pinBlueReceiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(pinBlueReceiver);
    }

    public class ClassicaBlueToothBind extends Binder {

        public BluetoothAdapter getAdapter() {
            return bluetoothAdapter;
        }

        public void setBlueCallback(ClientCallBack callback) {
            ClassicsBlueToothService.this.blueCallBack = callback;
            pinBlueReceiver.setCallBack(callback);
        }

        /**
         * 扫描的方法 返回true 扫描成功
         * 通过接收广播获取扫描到的设备
         *
         * @return
         */
        public boolean scanBlueTooth() {
            //当前是否在扫描,如果是就取消当前的扫描,重新扫描
            if (bluetoothAdapter.isDiscovering()) {
                bluetoothAdapter.cancelDiscovery();
            }

            //此方法是个异步操作,一般搜索12秒
            return bluetoothAdapter.startDiscovery();
        }

        /**
         * 取消扫描蓝牙
         *
         * @return true 为取消成功
         */
        public boolean cancelScanBule() {
            return bluetoothAdapter.cancelDiscovery();
        }

        /**
         * 配对(配对成功与失败通过广播返回)
         * 弹出配对框
         *
         * @param device
         */
        public void pinBlueTooth(BluetoothDevice device) {
            if (device == null) {
                Log.e("mcy", "设备不可以为空");
                return;
            }

            //配对之前把扫描关闭
            if (bluetoothAdapter.isDiscovering()) {
                bluetoothAdapter.cancelDiscovery();
            }

            //判断设备是否配对,没有配对在配,配对了就不需要配了
            if (device.getBondState() == BluetoothDevice.BOND_NONE) {//BOND_NONE 没有配对状态
                Log.d("mcy", "attemp to bond:" + device.getName());
                try {
                    boolean returnValue = device.createBond();
                    Log.e("是否配对成功:", "" + returnValue);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "配对失败");
                }
            }
        }

        /**
         * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
         *
         * @param device
         */
        public void cancelPinBuleTooth(BluetoothDevice device) {
            if (device == null) {
                Log.d("mcy", "设备不可以为空");
                return;
            }

            //判断设备是否配对,没有配对就不用取消了
            if (device.getBondState() != BluetoothDevice.BOND_NONE) {
                Log.d("mcy", "配对--" + device.getName());
                try {
                    Method removeBondMethod = device.getClass().getMethod("removeBond");
                    Boolean returnValue = (Boolean) removeBondMethod.invoke(device);
                    returnValue.booleanValue();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "取消配对失败");
                }
            }
        }

        /**
         * @param uuid   用户指定的 uuid ,可随意写,只要格式对就行,客户端和服务端保持一致即可。
         * @param device 连接的设备
         */
        public void connectionBlueTooth(String uuid, BluetoothDevice device) {
            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
                if (bluetoothSocket != null && !bluetoothSocket.isConnected()) {
                    sendDataThread = new ClientThread(bluetoothSocket, blueCallBack);
                    sendDataThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /**
         * 写数据
         */
        public void sendData(byte[] data) {
            if (sendDataThread != null) {
                sendDataThread.write(data);
            }
        }

        /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleConnecion() {
            sendDataThread.closeSocket();
        }

        /**
         * 读数据
         */
        public void readListern(String name, String uuid, ServiceCallback callBack) {
            acceptThread = new AcceptThread(name, uuid, bluetoothAdapter, callBack);
            acceptThread.start();
        }

        /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleServiceConnecion() {
            acceptThread.closeSocket();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new ClassicaBlueToothBind();
    }
}

八、小结

假设有两个经典蓝牙设备A和B,相互进行通信,根据以上过程,简单总结如下图: