开发配置:

在AndroidManifest.xml中配置权限

<!-- 使用蓝牙的权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <!-- 扫描蓝牙设备或者操作蓝牙设置 -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 这个权限用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!-- 这个权限用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

 

主要流程:

开启蓝牙 

检测蓝牙

配对蓝牙

连接

通信

开启蓝牙

//蓝牙相关
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null){
            // 说明此设备不支持蓝牙操作
            XToastUtils.info("此设备不支持蓝牙");
            return ;
        }else {
            //蓝牙还未打开,打开蓝牙
            if(!mBluetoothAdapter.isEnabled()){
                //第一种方法(弹出对话框提示信息)
                Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                startActivity(enabler);
//                //第二种方法(直接打开,没有提示)
//                BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//                bluetoothAdapter.enable();
            }
        }

动态权限

/**
     * targetSdkVersion若是大于或等于23,除了添加了蓝牙权限外,还要动态获取位置权限,才能将搜索                    到的蓝牙设备显示出来。
     * 若是小于,则不需要动态获取权限。
     * 动态申请权限
     */
    public void applyPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            //检查是否已经给了权限
            int checkpermission = ContextCompat.checkSelfPermission(getApplicationContext(),
                    Manifest.permission.ACCESS_FINE_LOCATION);

            if (checkpermission != PackageManager.PERMISSION_GRANTED) {//没有给权限
                Log.e("permission", "动态申请");
                //参数分别是当前活动,权限字符串数组,requestcode
                ActivityCompat.requestPermissions(ProDataUploadActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            }else{
                XToastUtils.info("已经有权限了");
            }
        }
    }

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            XToastUtils.info("已授权");
        } else {
            XToastUtils.error("拒绝授权");
        }

    }

 开启广播接收扫描结果 和 配对结果

//扫描
scanBlueCallBack = new ScanBlueCallBack();
        scanBlueReceiver = new ScanBlueReceiver(scanBlueCallBack);
        IntentFilter filter1 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        IntentFilter filter2 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(scanBlueReceiver,filter1);
        registerReceiver(scanBlueReceiver,filter2);
        registerReceiver(scanBlueReceiver,filter3);
//配对
pinBlueCallBack = new PinBlueCallBack();
        pinBlueReceiver = new PinBlueReceiver(pinBlueCallBack);
        IntentFilter filter4 = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
        IntentFilter filter5 = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(pinBlueReceiver,filter4);
        registerReceiver(pinBlueReceiver,filter5);
package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

/**
 * ************************************
 *
 * @ClassName: 
 * @Description: java类作用描述
 * @Author: fl
 * @CreateDate: 2021/6/10 15:43
 * @Version: 1.0
 * ************************************
 */

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 *扫描广播接收类
 * Created by fl on 2021/6/13.
 */
public class ScanBlueReceiver extends BroadcastReceiver {
    private static final String TAG = ScanBlueReceiver.class.getName();
    private ScanBlueCallBack callBack;

    public ScanBlueReceiver(ScanBlueCallBack 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(device != null && "HC-06".equals(device.getName())){
            Log.d(TAG, "设备名称:" + device.getName());
        }else{
            return;
        }

        switch (action){
            case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                Log.d(TAG, "开始扫描...");
                callBack.onScanStarted();
                break;
            case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                Log.d(TAG, "结束扫描...");
                callBack.onScanFinished();
                break;
            case BluetoothDevice.ACTION_FOUND:
                Log.d(TAG, "发现设备...");
                callBack.onScanning(device);
                break;
        }
    }
}
package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.bonus.sdsagmeasureapp.util.ByteUtil;

import java.lang.reflect.Method;

/**配对广播接收类
 * 
 */

public class PinBlueReceiver extends BroadcastReceiver {
    private String pin = "1234";  //此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
    private static final String TAG = PinBlueReceiver.class.getName();
    private PinBlueCallBack callBack;

    public PinBlueReceiver(PinBlueCallBack 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 (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
            try {
                callBack.onBondRequest();
                //1.确认配对
//                ClsUtils.setPairingConfirmation(device.getClass(), device, true);
                Method setPairingConfirmation = device.getClass().getDeclaredMethod("setPairingConfirmation",boolean.class);
                setPairingConfirmation.invoke(device,true);
                //2.终止有序广播
                Log.d("order...", "isOrderedBroadcast:"+isOrderedBroadcast()+",isInitialStickyBroadcast:"+isInitialStickyBroadcast());
                abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
                //3.调用setPin方法进行配对...
//                boolean ret = ClsUtils.setPin(device.getClass(), device, pin);
                Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
//                Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{ByteUtil.hexStringToByte(pin)});
                Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
            switch (device.getBondState()) {
                case BluetoothDevice.BOND_NONE:
                    Log.d(TAG, "取消配对");
                    callBack.onBondFail(device);
                    break;
                case BluetoothDevice.BOND_BONDING:
                    Log.d(TAG, "配对中");
                    callBack.onBonding(device);
                    break;
                case BluetoothDevice.BOND_BONDED:
                    Log.d(TAG, "配对成功");
                    callBack.onBondSuccess(device);
                    break;
            }
        }
    }
}

 

 开启扫描 和结束扫描可以做一些你想要的操作

package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.ScanCallback;

/**
 * ************************************
 *
 * @ClassName: ScanBlueCallBack
 * @Description: java类作用描述
 * @Author: fl
 * @CreateDate: 2021/6/10 18:11
 * @Version: 1.0
 * ************************************
 */
public class ScanBlueCallBack extends ScanCallback {

    BluetoothDevice device;

    public BluetoothDevice getDevice() {
        return device;
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    /**
     * 开始扫描
     */
    public void onScanStarted() {

    }
    /**
     * 结束扫描
     */
    public void onScanFinished() {

    }

    /**
     * 将扫描的设备存储起来后面连接使用
     * @param device
     */
    public void onScanning(BluetoothDevice device) {
        this.device = device;
    }

}
package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

import android.bluetooth.BluetoothDevice;

/**
 * ************************************
 * 配对成功
 * @ClassName: PinBlueCallBack
 * @Description: java类作用描述
 * @Author: fl
 * @CreateDate: 2021/6/10 21:22
 * @Version: 1.0
 * ************************************
 */
public class PinBlueCallBack {

    private BluetoothDevice device;
    /**
     * 配对成功 标志
     */
    public boolean flag = false;

    public BluetoothDevice getDevice() {
        return device;
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public void onBondRequest() {
    }

    public void onBondFail(BluetoothDevice device) {
    }

    public void onBonding(BluetoothDevice device) {
    }

    /**
     * 配对成功
     * @param device
     */
    public void onBondSuccess(BluetoothDevice device) {
        this.device = device;
        this.flag = true;
    }
}

 

扫描可能会扫描出很多设备,你可以做一个页面把所有的设备显示出来

然后在页面操作后台进行连接调用 可以参考这个


因为我的只需要连接固定蓝牙,我这样写的

先搜索已配对设备,是否有 HC-06 这个我需要的蓝牙,有就直接不扫描了,没有在开启扫描去搜索

// 已配对的设备
        boolean isNeed = true; //是否找到需要的蓝牙
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                if("HC-06".equals(device.getName())){
                    this.device = device;
                    pinBlueCallBack.setFlag(true);
                    isNeed = false;
                }
            }
        }
        if(isNeed){
            boolean flag = scanBlue();
            if(flag){
                //开启线程去扫描蓝牙,并在扫描到之后配对
                new bluetoothSearchThread().start();
            }
        }


//开启线程等待,只要配对成功就连接
new bluetoothPairThread().start();

 

/**
     * 等待12秒,如果未搜索到蓝牙就提示,搜索到了就配对连接
     */
    private class bluetoothSearchThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                Thread.sleep(12000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Message msg = new Message();
            msg.what = 0;
            String msgStr = "超时未搜索到蓝牙!";
            if(scanBlueCallBack.getDevice() != null){
                msgStr = "已搜索到蓝牙";
                device = scanBlueCallBack.getDevice();
                pin(device);
            }
            msg.obj = msgStr;
            handler.sendMessage(msg);
        }
    }
/**
     * 连接线程
     */
    private class bluetoothPairThread extends Thread {
        @Override
        public void run() {
            super.run();
//            while(true){
//                //退出时中断线程
//                if (isBlueToothPairStop){
//                    break;
//                }
                //配对成功
                if(pinBlueCallBack.isFlag()){
                    connect(device,connectBlueCallBack);
                }
//            }
        }
    }
/**
     * 连接 (在配对之后调用)
     * @param device
     */
    public void connect(BluetoothDevice device, ConnectBlueCallBack callBack){
        if (device == null){
            Log.d(TAG, "bond device null");
            return;
        }
        //连接之前把扫描关闭
        if (mBluetoothAdapter.isDiscovering()){
            mBluetoothAdapter.cancelDiscovery();
        }
        connectBlueTask = new ConnectBlueTask(callBack);
        connectBlueTask.execute(device);

    }
package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

/**
 * ************************************
 *
 * @ClassName: ConnectBlueTask
 * @Description: java类作用描述
 * @Author: fl
 * @CreateDate: 2021/6/10 21:26
 * @Version: 1.0
 * ************************************
 */

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.AsyncTask;
import android.util.Log;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;

/**连接线程
 * Created by zqf on 2018/7/7.
 */

public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {
    private static final String TAG = ConnectBlueTask.class.getName();
    private BluetoothDevice bluetoothDevice;
    private ConnectBlueCallBack callBack;

    public ConnectBlueTask(ConnectBlueCallBack callBack){
        this.callBack = callBack;
    }

    @Override
    protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
        bluetoothDevice = bluetoothDevices[0];
        BluetoothSocket socket = null;
        try{
//            Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);
            //方法一:uuid
//            socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
            //方法二:反射
            Method m = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
            socket = (BluetoothSocket) m.invoke(bluetoothDevice, 1);
            if (socket != null && !socket.isConnected()){
                socket.connect();
            }
        }catch (IOException | NoSuchMethodException e){
            Log.e(TAG,"socket连接失败");
            try {
                socket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
                Log.e(TAG,"socket关闭失败");
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return socket;
    }

    @Override
    protected void onPreExecute() {
        Log.d(TAG,"开始连接");
        if (callBack != null){
            callBack.onStartConnect();
        }
    }

    @Override
    protected void onPostExecute(BluetoothSocket bluetoothSocket) {
        if (bluetoothSocket != null && bluetoothSocket.isConnected()){
            Log.d(TAG,"连接成功");
            if (callBack != null){
                callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
            }
        }else {
            Log.d(TAG,"连接失败");
            if (callBack != null){
                callBack.onConnectFail(bluetoothDevice);
            }
        }
    }
}
package com.bonus.sdsagmeasureapp.ui.adapter.BlueBooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

/**
 * ************************************
 *
 * @ClassName: ConnectBlueCallBack
 * @Description: java类作用描述
 * @Author: fl
 * @CreateDate: 2021/6/10 21:40
 * @Version: 1.0
 * ************************************
 */
public class ConnectBlueCallBack {

    private BluetoothDevice device;
    private BluetoothSocket socket;
    private BluetoothAdapter bluetoothAdapter;
    public boolean flag = false;

    public ConnectBlueCallBack() {
    }

    public ConnectBlueCallBack(BluetoothAdapter bluetoothAdapter) {
        this.bluetoothAdapter = bluetoothAdapter;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public BluetoothAdapter getBluetoothAdapter() {
        return bluetoothAdapter;
    }

    public void setBluetoothAdapter(BluetoothAdapter bluetoothAdapter) {
        this.bluetoothAdapter = bluetoothAdapter;
    }

    public BluetoothDevice getDevice() {
        return device;
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    public BluetoothSocket getSocket() {
        return socket;
    }

    public void setSocket(BluetoothSocket socket) {
        this.socket = socket;
    }

    public void onStartConnect() {
    }

    /**
     * 连接成功
     * @param bluetoothDevice 设备
     * @param bluetoothSocket socket
     */
    public void onConnectSuccess(BluetoothDevice bluetoothDevice, BluetoothSocket bluetoothSocket) {
            setDevice(bluetoothDevice);
            setSocket(bluetoothSocket);
            flag = true;

    }
    /**
     * 连接失败
     * @param bluetoothDevice 设备
     */
    public void onConnectFail(BluetoothDevice bluetoothDevice) {
    }

}

配对的方法 

public void pin(BluetoothDevice device){
        if (device == null){
            XToastUtils.info("未找到设备");
            return;
        }
        //配对之前把扫描关闭
        if (mBluetoothAdapter.isDiscovering()){
            mBluetoothAdapter.cancelDiscovery();
        }
        Log.e(TAG, "需配对设备码:"+device.getBondState());
        Log.e(TAG, "本机配对码:"+BluetoothDevice.BOND_NONE);
        Log.e(TAG, "需配对设备名称:"+device.getName());
        //判断设备是否配对,没有配对在配,配对了就不需要配了(一旦配对了,他们的码就会不一样)
        if (device.getBondState() == BluetoothDevice.BOND_NONE) {
            Log.d(TAG, "attemp to bond:" + device.getName());
            try {
                Method createBondMethod = device.getClass().getMethod("createBond");
                Boolean returnValue = (Boolean) createBondMethod.invoke(device);
                returnValue.booleanValue();
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "attemp to bond fail!");
            }
        }
    }

扫描的方法

/**
     * 扫描的方法 返回true 扫描成功
     * 通过接收广播获取扫描到的设备
     * @return
     */
    public boolean scanBlue(){
        //当前是否在扫描,如果是就取消当前的扫描,重新扫描
        if (mBluetoothAdapter.isDiscovering()){
            mBluetoothAdapter.cancelDiscovery();
        }
        //此方法是个异步操作,一般搜索12秒
        return mBluetoothAdapter.startDiscovery();
    }

 上面的代码就可以连接蓝牙了,选在开启线程监听蓝牙返回数据,这个监听线程可以一开始就开启

/**
     * 是否启动蓝牙监听返回数据
     */
    private class receiveThread extends Thread {
        @Override
        public void run() {
            super.run();
            while(true){
                if(isReceive){
                    break;
                }
                if(isConnectBlue()){
                    isReceive = true;
                    try {
                        is = socket.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
//                    connectBlueTask.cancel(true);
                    new readThread().start();
//                    new ReadTask(readCallBack,socket).execute();
                    Message msg = new Message();
                    msg.what=0;
                    msg.obj = "启动蓝牙监听线程";
                    handler.sendMessage(msg);
                }
            }
        }
    }


/**
     * 蓝牙监听线程
     */
    public class readThread extends Thread{
        @Override
        public void run() {
            try {

                while (true) {
                    Message msg = new Message();
                    int count = 0;
                    while (count == 0) {
                        count = is.available();
                    }
                    String message = "监听返回[";
                    byte buf[] = new byte[count];
                    if (buf != null) {
                        is.read(buf);
                        message += ByteUtil.bytesToHexString(buf) + "]";
                    }
                    msg.what=1;
                    msg.obj = message;
                    handler.sendMessage(msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

判断蓝牙是否连接

/**
     * 蓝牙是否连接
     * @return
     */
    public boolean isConnectBlue(){
        if(socket == null){
            socket = connectBlueCallBack.getSocket();
        }
        return socket != null && socket.isConnected();
    }

 给蓝牙发送数据

/**
     * 提交数据
     */
    private void submitBaseStationData() {

        String order = "fix position "+171.33+" "+31.05+" "+15.6+"\r\n";
        //使用蓝牙提交数据
        //TODO
        if(isConnectBlue()){
            XToastUtils.info("蓝牙连接中");
//            new WriteTask(writeCallBack,socket).execute(order);
            try {
                os = socket.getOutputStream();//获取输出流
                if (os != null) {//判断输出流是否为空
                    os.write(order.getBytes("UTF-8"));
//                    os.write(order.getBytes());
                }
                os.flush();
//                os.close();//关闭输出流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else{
            XToastUtils.info("蓝牙已断开或蓝牙未连接");
        }
    }