蓝牙的一堆东西

操作蓝牙需要蓝牙权限 及 定位权限

     Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION

蓝牙控制类

@SuppressLint("MissingPermission")
class BluetoothManager private constructor(){

    enum class Type {
        Connect, ConnectError, Read, IoError
    }

    companion object{

        const val TAG = "bl_blue"

        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            BluetoothManager()
        }
    }

    lateinit var context: Context
    private var bluetoothAdapter: BluetoothAdapter? = null
    private var mBluetoothA2dp: BluetoothA2dp? = null  //通过反射链接蓝牙时使用
    private var socket:SerialSocket? = null  //需要蓝牙通信时使用
    private var currentConnectDevice:BluetoothDevice? = null  //当前连接的设备
    var connectState = false 


    /**
     * 初始化
     */
    open fun init(context:Context):BluetoothManager{
        this.context = context
        bluetoothAdapter = if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q){
           val blueManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as android.bluetooth.BluetoothManager
            blueManager.adapter
        }else{
            BluetoothAdapter.getDefaultAdapter()
        }

        if(bluetoothAdapter?.isEnabled?:false){
            getBluetoothA2DP()
        }
        init?.let { it(bluetoothAdapter?.isEnabled?:false) }

        return instance
    }

    /**
     * 初始化广播
     */
    open fun registerReceiver():BluetoothManager{
        val filter = IntentFilter()
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)  //连接状态变化广播
        filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)
        filter.addAction(BluetoothDevice.ACTION_FOUND)
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) //蓝牙设备配对和解除配对时发送
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED) //开闭状态变化
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED) //扫描蓝牙
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED) //扫描结束

        context.registerReceiver(mBroadcastReceiver, filter)
        return instance
    }

    /**
     * 取消注册广播
     */
    open fun unRegisterReceiver(){
        context.unregisterReceiver(mBroadcastReceiver)
    }

    /**
     * 搜索附近蓝牙
     */
    open fun searchBluetooth(){
        if(!checkInit()){
            return
        }
        bluetoothAdapter?.let {
            if(it.isDiscovering){  //正在扫描则取消扫描后重新扫描
                it.cancelDiscovery()
            }
            val startDiscovery = it.startDiscovery()
            LogUtils.i(TAG," startDiscovery>>${ startDiscovery}")
        }
    }


    /**
     * 连接蓝牙设备  获取收发数据时使用此处
     */
    open fun connect(device:BluetoothDevice){
        currentConnectDevice = device
        socket = SerialSocket(context.getApplicationContext(), device)
        socket?.connect(object : SerialListener{
            override fun onSerialConnect() {
                LogUtils.i(TAG,"onSerialConnect")
                setConnectChanged(true)
            }

            override fun onSerialConnectError(e: Exception?) {
                LogUtils.i(TAG,"onSerialConnectError")
                setConnectChanged(false)
            }

            override fun onSerialRead(data: ByteArray?) {
                data?.let {
                    LogUtils.i(TAG,"onSerialRead>>${String(it)}")

                    if (String(it) == "+PTT=P") {
                        EventBusUtils.sendEvent(Event(Constants.BLE_DOWN, ""))
                    }
                    if (String(it) == "+PTT=R") {
                        EventBusUtils.sendEvent(Event(Constants.BLE_UP, ""))
                    }
                }

            }

            override fun onSerialRead(datas: ArrayDeque?) {
                LogUtils.i(TAG,"onSerialRead")
                datas?.let {
                    datas.forEach {
                        LogUtils.i(TAG,"onSerialRead>>${String(it)}")
                    }
                }
            }

            override fun onSerialIoError(e: Exception?) {
                LogUtils.i(TAG,"onSerialIoError")
                setConnectChanged(false)
            }

        })
    }

    fun setConnectChanged(state:Boolean){
        connectState = state
        connectChange?.let {
            it.invoke(connectState)
        }
    }

    /**
     * 断开连接与上边的一块用
     */
    open fun disConnect(){
        socket?.let {
            it.disconnect()
            currentConnectDevice = null
        }
    }


    fun checkInit():Boolean{
        if(bluetoothAdapter == null || !bluetoothAdapter!!.isEnabled){
            return false
        }
        return true
    }

    /**
     * 反射连接蓝牙
     */
    open fun connectBluetooth(device:BluetoothDevice){
        currentConnectDevice = device
        try {
            val connect: Method? = mBluetoothA2dp?.javaClass?.getDeclaredMethod("connect", BluetoothDevice::class.java)
            connect?.let {
                it.setAccessible(true)
                it.invoke(mBluetoothA2dp, device)
            }
        } catch (e: NoSuchMethodException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        }
    }

    /**
     * 反射断开蓝牙
     */
    private fun disconnectBluetooth() {
        LogUtils.i(TAG, "disconnect")
        if (mBluetoothA2dp == null) {
            return
        }
        if (currentConnectDevice == null) {
            return
        }
        try {
            val disconnect = mBluetoothA2dp!!.javaClass.getDeclaredMethod(
                "disconnect",
                BluetoothDevice::class.java
            )
            disconnect.isAccessible = true
            disconnect.invoke(mBluetoothA2dp, currentConnectDevice)
            currentConnectDevice = null
        } catch (e: NoSuchMethodException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            LogUtils.e(TAG, "connect exception:$e")
            e.printStackTrace()
        }
    }

    private fun getBluetoothA2DP() {
        if (bluetoothAdapter == null) {
            return
        }
        if (mBluetoothA2dp != null) {
            return
        }
        bluetoothAdapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener {
            override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
                if (profile == BluetoothProfile.A2DP) {
                    //Service连接成功,获得BluetoothA2DP
                    mBluetoothA2dp = proxy as BluetoothA2dp
                }
            }

            override fun onServiceDisconnected(profile: Int) {}
        }, BluetoothProfile.A2DP)
    }

    /**
     * 关闭蓝牙 此处时关闭所有
     */
    open fun close(){
        LogUtils.i("bl_blue","close")
        bluetoothAdapter?.let {
            if(it.isDiscovering){
                it.cancelDiscovery()
            }
            disConnect()
            disconnectBluetooth()

            it.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp)
            if(it.isEnabled){
                it.disable()
            }
        }
        unRegisterReceiver()
    }

    /**
     * 连接保存的设备
     */
    open fun connectSaveDevice(){
        val address = MmkvUtils.getInstance().decode(Constants.SP_SAVE_BLUETOOTH,"") as String
        LogUtils.i("bl_blue","address>>${address}")
        bluetoothAdapter?.let {
            if(!StringUtils.isEmpty(address)){
                val device = it.getRemoteDevice(address)
                if(device != null){
                    connect(device)
                }else{
                    disConnect()
                }
            }
        }
    }

    val mBroadcastReceiver:BroadcastReceiver
        get() {
           return object :BroadcastReceiver(){
                override fun onReceive(context: Context?, intent: Intent?) {
                    intent?.apply {
                        when(action){
                            BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED ->{  //连接状态
                                val connectState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)
                                when(connectState){
                                    BluetoothA2dp.STATE_CONNECTING -> {  //正在连接
                                        LogUtils.i(TAG,"正在连接")
                                    }
                                    BluetoothA2dp.STATE_CONNECTED -> {  //已连接
                                        LogUtils.i(TAG,"已连接")
                                        val connectDevice: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)  //保存已连接的蓝牙
                                        connectDevice?.let {
                                            MmkvUtils.getInstance().encode(Constants.SP_SAVE_BLUETOOTH,it.address)
                                            connect(it)
                                        }
                                    }
                                    BluetoothA2dp.STATE_DISCONNECTING -> {  //正在断开连接
                                        LogUtils.i(TAG,"正在断开连接")
                                    }
                                    BluetoothA2dp.STATE_DISCONNECTED -> {  //断开连接
                                        LogUtils.i(TAG,"断开连接")
                                    }
                                }
                            }

                            BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED -> { //播放状态改变
                                val playingState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)
                                when(playingState){
                                    BluetoothA2dp.STATE_PLAYING -> {
                                        LogUtils.i(TAG,"正在播放")
                                    }
                                    BluetoothA2dp.STATE_NOT_PLAYING -> {
                                        LogUtils.i(TAG,"未播放")
                                    }
                                }
                            }

                            BluetoothDevice.ACTION_FOUND -> {  //发现新设备
                                val foundDevice: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                                LogUtils.i(TAG,"foundDevice>>${foundDevice}")
                            }

                            BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
                                val deviceBound: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                                deviceBound?.let {
                                    LogUtils.i(TAG, "device name: $it.name")
                                }

                                val stateBondChanged =
                                    intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
                                when (stateBondChanged) {
                                    BluetoothDevice.BOND_NONE -> {
                                        LogUtils.i(TAG, "BOND_NONE 删除配对")
                                    }

                                    BluetoothDevice.BOND_BONDING -> {
                                        LogUtils.i(TAG, "BOND_BONDING 正在配对")
                                    }


                                    BluetoothDevice.BOND_BONDED -> {
                                        LogUtils.i(TAG, "BOND_BONDED 配对成功")
                                    }
                                }
                            }

                            BluetoothAdapter.ACTION_STATE_CHANGED -> {
                                val stateChanged = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
                                when (stateChanged) {
                                    BluetoothAdapter.STATE_OFF -> LogUtils.i(TAG, "STATE_OFF 手机蓝牙关闭")

                                    BluetoothAdapter.STATE_TURNING_OFF -> LogUtils.i(TAG, "STATE_TURNING_OFF 手机蓝牙正在关闭")

                                    BluetoothAdapter.STATE_ON -> LogUtils.i(TAG, "STATE_ON 手机蓝牙开启")

                                    BluetoothAdapter.STATE_TURNING_ON -> LogUtils.i(TAG, "STATE_TURNING_ON 手机蓝牙正在开启")
                                }
                            }

                            BluetoothAdapter.ACTION_DISCOVERY_STARTED -> {  //扫描
                                LogUtils.i(TAG, "开始扫描蓝牙 state: ACTION_DISCOVERY_STARTED");
                            }

                            BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
                                LogUtils.i(TAG, "蓝牙扫描结束 state: ACTION_DISCOVERY_FINISHED")
                            }
                        }
                    }
                }
            }
        }


    private var init: ((Boolean) -> Unit)? = null //初始化监听
    private var changed: ((Type) -> Unit)? = null //变化监听
    private var connectChange: ((Boolean) -> Unit)? = null //连接变化
    open fun setOnInitListener(init:(Boolean) -> Unit){
        this.init = init

    }
    open fun setOnChangeListener(changed:(Type) -> Unit){
        this.changed = changed
    }
    open fun setOnConnectChangeListener(connectChange:(Boolean) -> Unit){
        this.connectChange = connectChange
    }
}

这是别人写的一个用来进行蓝牙通信的socket的连接线程,就直接拿来用了

@SuppressLint("MissingPermission")
public class SerialSocket implements Runnable {

    private static final UUID BLUETOOTH_SPP = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    private final Context context;
    private SerialListener listener;
    private final BluetoothDevice device;
    private BluetoothSocket socket;
    private boolean connected;

    public SerialSocket(Context context, BluetoothDevice device) {
        if(context instanceof Activity)
            throw new InvalidParameterException("expected non UI context");
        this.context = context;
        this.device = device;
    }


    public String getName() {
        return device.getName() != null ? device.getName() : device.getAddress();
    }

    /**
     * connect-success and most connect-errors are returned asynchronously to listener
     */
    public void connect(SerialListener listener) throws IOException {
        this.listener = listener;
        Executors.newSingleThreadExecutor().submit(this);
    }

    public void disconnect() {
        listener = null; // ignore remaining data and errors
        // connected = false; // run loop will reset connected
        if(socket != null) {
            try {
                socket.close();
            } catch (Exception ignored) {
            }
            socket = null;
        }
    }

    public void write(byte[] data) throws IOException {
        if (!connected)
            throw new IOException("not connected");
        socket.getOutputStream().write(data);
    }

    @Override
    public void run() { // connect & read
        try {
            socket = device.createRfcommSocketToServiceRecord(BLUETOOTH_SPP);
            socket.connect();
            if(listener != null)
                listener.onSerialConnect();
        } catch (Exception e) {
            if(listener != null)
                listener.onSerialConnectError(e);
            try {
                socket.close();
            } catch (Exception ignored) {
            }
            socket = null;
            return;
        }
        connected = true;
        try {
            byte[] buffer = new byte[1024];
            int len;
            //noinspection InfiniteLoopStatement
            while (true) {
                len = socket.getInputStream().read(buffer);
                byte[] data = Arrays.copyOf(buffer, len);
                if(listener != null) {
                    listener.onSerialRead(data);
                }
            }
        } catch (Exception e) {
            connected = false;
            if (listener != null)
                listener.onSerialIoError(e);
            try {
                socket.close();
            } catch (Exception ignored) {
            }
            socket = null;
        }
    }

}

public interface SerialListener {
    void onSerialConnect      ();
    void onSerialConnectError (Exception e);
    void onSerialRead         (byte[] data);                // socket -> service
    void onSerialRead         (ArrayDeque datas);   // service -> UI thread
    void onSerialIoError      (Exception e);
}

使用

BluetoothManager.Companion.getInstance().init(this)  //初始化
                    .registerReceiver()   //注册广播
                .connectSaveDevice(); //自动连接已经保存的蓝牙 (这一步其实不需要蓝牙权限,系统连接成功过,这一步就可直接调用)

其他开关蓝牙/获取已配对设备/搜索附近设备的结果请自行处理

你可能感兴趣的:(android)