Android 蓝牙开发模块详解 (含 demo)

1、简介

实现一下功能:
(1)扫描其他蓝牙设备
(2)查询本地蓝牙适配,用于配对蓝牙设备
(3)建立 RFCOMM 信道
(4)通过服务发现连接其他设备
(5)数据通信
(6)管理多个连接

在这里插入图片描述

2、基本功能简介

1)、设置权限
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

2)开启蓝牙

  //启动蓝牙
    private void enableBluetooh() {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //获取蓝牙适配器
        if (bluetoothAdapter == null) {
            Log.i(TAG,"设备不支持蓝牙功能");
            return;
        }

        if (bluetoothAdapter.isEnabled()) { //如果蓝牙没有打开
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent,100);
        }
    }

    public  void onActivityResult(int requestCode,int resultCode,Intent data) {
        if (requestCode == 100) {
            if (resultCode == RESULT_OK) {
                Log.i(TAG,"蓝牙开启成功");
            } else {
                Log.i(TAG,"蓝牙开启失败");
            }
        }
    }
3)、发现蓝牙设备

(1)使本机蓝牙处于可见状态,会被其他蓝牙设备搜索

    //是自身可以被发现
    private void ensureDiscoverable() {
        if(bluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent (BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300); //设置本机蓝牙在 300 秒之内可以被 搜索
            startActivity(discoverableIntent);
        }
    }

(2)查找已经配对的设备,及以前已经配对过的设备

   //查找已经配对过的设备,及已经配对过的设备
    private void pairedDevices() {
        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice devices : pairedDevices) {
                Log.i(TAG ,"device name: " + devices.getName() + "\n" +
                "device address: " + devices.getAddress());
            }
        } else {
            Log.i(TAG,"没有找到已匹配的设备");
        }
    }

(3)搜索设备

   //搜索新的蓝牙设备 //先注册一个 广播 来获取搜索结果
    private void searchDevices() {
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);   //当一个设备被发现时 ,调用广播
        this.registerReceiver(mReceiver,filter);
        
        //当搜索结束后,调用 广播
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        this.registerReceiver(mReceiver,filter);
        
        bluetoothAdapter.startDiscovery();// 用这个方法来搜索设备
    }
    
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String  action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                //已经配对过的跳过
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    Log.i(TAG,"device name: " + device.getName() + " device address: " + device.getAddress());
                }
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                //搜索结束
                Log.i(TAG,"设备搜索结束");
            }
        }
    };

4、建立连接

当查找到蓝牙设备之后,接下来建立连接,本机可以作为一个服务端,来接收其他设备的连接。

    private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    private String NAME_INSECURE;
    public  class AcceptThread extends  Thread{
        //像一个服务器一样时刻监听是否有连接
        private BluetoothServerSocket serverSocket;
        public AcceptThread(boolean secure) {
            BluetoothServerSocket temp = null;
            try {
                temp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE,MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
            }

            serverSocket = temp;
        }

        public  void  run(){
            BluetoothSocket socket = null;
            while (true) {
                try {
                    socket = serverSocket.accept();
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e(TAG,"accept socket fail");
                    break;
                }
            }
            
            if (socket != null) {
                //此时可以做一个数据交换线程 把socket 传进去
            }
        }
        
        //取消监听
        public void cancel() {
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

5、交换数据

当搜索到蓝牙设备之后,接下来就会获取到设备地址,通过地址获取BluetoothDeviced对象,可以将其看作是一个客户端。通过对象。device.createRfcommSocketToServiceRecord(MY_UUID) 同一个 UUID 可与服务器建立连接 获取另一个 socket 对象。

   //另一个设备连接本机 , 相当于客户端
    private class ConnectThread extends  Thread {
        private BluetoothSocket socket;
        private BluetoothDevice device;
        
        public ConnectThread(BluetoothDevice device, boolean secure){
            this.device = device;
            BluetoothSocket tmp = null;
            try {
                tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        public void  run(){
            bluetoothAdapter.cancelDiscovery(); //取消设备查找

            try {
                socket.connect();
            } catch (IOException e) {
                e.printStackTrace();
                try {
                    socket.close();  //连接失败
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            //此时可以创建一个线程 把 socket  传进去
        }
        
        public void cancel () {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

6、建立数据通信线程

接下来 我们读取通信数据

 private class ConnectedThread extends  Thread{
        private BluetoothSocket socket;
        private InputStream inputStream;
        private OutputStream outputStream;

        public ConnectedThread(BluetoothSocket socket) {
            this.socket = socket;

            //获取输入输出流
            try {
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        public void  run() {
            byte [] buff = new byte [1024];
            int len = 0;

            //读数据需要不断监听 ,写 不需要

            while (true) {
                try {
                    len = inputStream.read(buff);
                    //获取到的数据 长度
                } catch (IOException e) {
                    e.printStackTrace();
                    start();//重新启动服务
                }
            }
        }


        public void write(byte[] buffer) {
            try {
                outputStream.write(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


        public void  cancel() {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

6、实例练习

6.1、代码结构

在这里插入图片描述

6.2 、 xml 文档
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:layout_height="match_parent">
                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_op_id"
                    android:textSize="30dp"
                    android:text="打开蓝牙"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_close_id"
                    android:textSize="30dp"
                    android:text="关闭蓝牙"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_discovered_id"
                    android:textSize="30dp"
                    android:text="允许搜索"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_search_id"
                    android:textSize="30dp"
                    android:text="开始搜索"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_paired_id"
                    android:textSize="30dp"
                    android:text="已经配对"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_pair_id"
                    android:textSize="30dp"
                    android:text="蓝牙配对"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_unPair_id"
                    android:textSize="30dp"
                    android:text="取消配对"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_server_id"
                    android:textSize="30dp"
                    android:text="开启服务"/>


            </LinearLayout>


            <LinearLayout
                android:orientation="vertical"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_serverUnconnect_id"
                    android:textSize="30dp"
                    android:text="服务断开"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_connect_id"
                    android:textSize="30dp"
                    android:text="蓝牙连接"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_unConnect_id"
                    android:textSize="30dp"
                    android:text="取消连接"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_clientRev_id"
                    android:textSize="30dp"
                    android:text="客户端收"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_clientSend_id"
                    android:textSize="30dp"
                    android:text="客户端发"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_serverRev_id"
                    android:textSize="30dp"
                    android:text="服务端收"/>

                <Button
                    android:layout_width="match_parent"
                    android:layout_height="60dp"
                    android:id="@+id/bt_ServerSend_id"
                    android:textSize="30dp"
                    android:text="服务端发"/>

            </LinearLayout>
        </LinearLayout>


    </ScrollView>

</LinearLayout>
6.3、添加权限
    <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" />
6.4 功能代码
package myapplication.lum.com.mybluetoothapplication;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private String  TAG = "MainActivity lum: ";
    private BluetoothAdapter mbluetoothAdapter;
    private Button buttonOpen,buttonClose,buttonDiscover,buttonSearch,buttonPaired, buttonPair,
            buttonUnpair,buttonServer,buttonServerUnconnect, buttonConnect,buttonUnconnect,
            buttonClientRev,buttonClientSend,buttonServRev,buttonServSend;

    private static final int REQUEST_ENABLE = 0x1; //请求能够打开蓝牙
    private static final int REQUEST_CODE_PERMISSION_LOCATION = 0x2; //权限请求

    private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    private BluetoothDevice bluetoothDevice; //我们将要连接配对的设备
    private    BluetoothSocket bluetoothSocket; //蓝牙配对客户端的 socket
    private   BluetoothServerSocket serverSocket; //服务端的 socket
    private    BluetoothSocket serverClientSocket;//服务端接受的 客户端socket

    private AcceptThread acceptThread;  //服务端线程
    private ClientThread clientThread ; //客户端线程

    private  OutputStream outputStream ; //输出流
    private InputStream inputStream ; //输入流

    private Byte[] buffer ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkPermissions();
        checkBLEFeature();
        initView();
    }

    /**
     * 检查BLE是否起作用
     */
    private void checkBLEFeature() {
        //判断是否支持蓝牙4.0
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Log.i(TAG,"设备支持BLE");
        } else {
            Log.i(TAG,"设备不支持BLE");
        }
    }

    private void initView(){
        mbluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //获取默认的蓝牙适配器

        //蓝牙搜索需要注册
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);  //蓝牙搜索
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //蓝牙搜索结束
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //蓝牙设备状态改变
        registerReceiver(mReceiver,filter);

        buttonOpen = (Button) findViewById(R.id.bt_op_id);
    buttonClose = (Button) findViewById(R.id.bt_close_id);
    buttonDiscover = (Button) findViewById(R.id.bt_discovered_id);
    buttonSearch  = (Button) findViewById(R.id.bt_search_id);
    buttonPaired = (Button) findViewById(R.id.bt_paired_id);
    buttonPair = (Button) findViewById(R.id.bt_pair_id);
        buttonUnpair = (Button) findViewById(R.id.bt_unPair_id);
        buttonServer = (Button) findViewById(R.id.bt_server_id);
        buttonServerUnconnect = (Button) findViewById(R.id.bt_unConnect_id);
        buttonConnect = (Button) findViewById(R.id.bt_connect_id);
        buttonUnconnect = (Button) findViewById(R.id.bt_unConnect_id);
        buttonClientRev = (Button) findViewById(R.id.bt_clientRev_id);
        buttonClientSend = (Button) findViewById(R.id.bt_clientSend_id);
        buttonServRev = (Button) findViewById(R.id.bt_serverRev_id);
        buttonServSend = (Button) findViewById(R.id.bt_ServerSend_id);

        buttonOpen.setOnClickListener(this);
        buttonClose.setOnClickListener(this);
        buttonDiscover.setOnClickListener(this);
        buttonSearch.setOnClickListener(this);
        buttonPaired.setOnClickListener(this);
        buttonPair.setOnClickListener(this);
        buttonUnpair.setOnClickListener(this);
        buttonServer.setOnClickListener(this);
        buttonServerUnconnect.setOnClickListener(this);
        buttonConnect.setOnClickListener(this);
        buttonUnconnect.setOnClickListener(this);
        buttonClientRev.setOnClickListener(this);
        buttonClientSend.setOnClickListener(this);
        buttonServRev.setOnClickListener(this);
        buttonServSend.setOnClickListener(this);

    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_op_id:
                enableBluetooh(); //打开蓝牙
                break;
            case R.id.bt_close_id:
                closeBluetooh();//关闭蓝牙
                break;
            case R.id.bt_discovered_id:
                disCoveredEnable();//允许被搜索
                break;
            case R.id.bt_paired_id:
                pairedConnect();//已经配对的设备
                break;
            case R.id.bt_search_id:
                mbluetoothAdapter.startDiscovery();//搜索设备
                Log.i(TAG,"开始进行搜索");
                break;
            case R.id.bt_pair_id:  //蓝牙配对
                paireDevice();
                break;
            case R.id.bt_unPair_id:
                unPairDevices();//取消蓝牙配对
                break;
            case R.id.bt_server_id:
                serverOpen();//打开服务端
                break;
            case R.id.bt_serverUnconnect_id:  //服务端断开连接
                serverUnconnect();//服务端断开连接
                break;
            case R.id.bt_connect_id:
                clientConnectDevices();//蓝牙连接
                break;
            case R.id.bt_unConnect_id:
                clientUnConnectDevices();//取消蓝牙连接
                break;
            case R.id.bt_clientRev_id:
                clientReadRev();//客户端接收数据
                break;
            case R.id.bt_clientSend_id:
                clientSendData();//客户端发送数据
                break;
            case R.id.bt_serverRev_id:
                serverReadRev();//服务端接收数据
                break;
            case R.id.bt_ServerSend_id:
                serverSendData();//服务端发送数据
                break;
                default:
                    break;
        }
    }

    //服务端发送数据
    private void serverSendData() {
        sendData("服务端发送数据".getBytes(),serverClientSocket);
        Log.i(TAG,"服务端发送数据");
    }


    //服务端 接收数据
    private void serverReadRev() {
        ReadReceiveThread clientReadThread = new ReadReceiveThread(serverClientSocket);
        clientReadThread.start();
    }



    //客户端发送数据
    private void clientSendData() {
        sendData("客户端发送数据".getBytes(),bluetoothSocket);
        Log.i(TAG,"客户端发送数据");
    }

    //客户端接收数据
    private void clientReadRev() {
        ReadReceiveThread clientReadThread = new ReadReceiveThread(bluetoothSocket);
        clientReadThread.start();
    }

    //发送数据
    public  void sendData(byte[]   bytStr,BluetoothSocket socket){
        try {
            if (outputStream == null) {
                outputStream = socket.getOutputStream();
            }
            outputStream.write(bytStr);
            Log.i(TAG,"发送的数据是: " + new String(bytStr));
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG,"发送数据错误");
        }
    }

    // 取数据线程
    private class ReadReceiveThread extends Thread {

        private BluetoothSocket socket ;

        public ReadReceiveThread(BluetoothSocket bluetoothSocket) {
            socket = bluetoothSocket;
        }
        public void run() {
            byte[] buffer = new byte[1024];
            int bytes;

            try {

                 Log.i(TAG,"is socket connect: " + socket.isConnected() + " socket: " + socket );
                if (inputStream == null) {
                    inputStream = socket.getInputStream();
                }

                while (true) {
                    if ((bytes = inputStream.read(buffer)) > 0) {
                        byte[] buf_data = new byte[bytes];
                        for (int i = 0; i < bytes; i++) {
                            buf_data[i] = buffer[i];
                        }
                        String str = new String(buf_data);

                         Log.i(TAG,"接收的数据是: " + str);
                    }
                }
            } catch (IOException e1) {
                e1.printStackTrace();
                Log.e(TAG,"接收数据错误");
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }

        }
    }


    //服务端断开连接
    private void serverUnconnect() {
        acceptThread.cancel();
    }

    //打开服务端
    private void serverOpen() {
        acceptThread =  new AcceptThread();
        acceptThread.start(); //开启服务线程
    }

    //开启服务端线程 接收 客户端连接
    private class AcceptThread extends  Thread{


        public AcceptThread () {
            BluetoothServerSocket temp = null;

            try {
                temp = mbluetoothAdapter.listenUsingRfcommWithServiceRecord("BLUE_TEST",MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
                Log.i(TAG,"创建服务器失败");
            }

            serverSocket = temp;
            Log.i(TAG,"server socket 创建成功: " + serverSocket);
        }

        public  void run(){
            BluetoothSocket socket = null;

            while (true) {
                try {
                    socket = serverSocket.accept();
                    if (socket != null) {
                        serverClientSocket = socket;
                        Log.i(TAG,"服务端连接 socket: " + socket);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e(TAG,"accept() fail");
                    break;
                }
            }

        }


        public void  cancel(){
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                    serverSocket = null;
                    Log.i(TAG,"服务端取消连接");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            ;
        }
    }

    /**
     * 检查权限
     */
    private void checkPermissions() {
        String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
        List<String> permissionDeniedList = new ArrayList<>();
        for (String permission : permissions) {
            int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                onPermissionGranted(permission);
            } else {
                permissionDeniedList.add(permission);
            }
        }
        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
            ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
        }
    }

    /**
     * 权限回调
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public final void onRequestPermissionsResult(int requestCode,
                                                 @NonNull String[] permissions,
                                                 @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_CODE_PERMISSION_LOCATION:
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            onPermissionGranted(permissions[i]);
                        }
                    }
                }
                break;
        }
    }


    /**
     * 开启GPS
     * @param permission
     */
    private void onPermissionGranted(String permission) {
        switch (permission) {
            case Manifest.permission.ACCESS_FINE_LOCATION:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkGPSIsOpen()) {
                    new AlertDialog.Builder(this)
                            .setTitle("提示")
                            .setMessage("当前手机扫描蓝牙需要打开定位功能。")
                            .setNegativeButton("取消",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            finish();
                                        }
                                    })
                            .setPositiveButton("前往设置",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                            startActivity(intent);
                                        }
                                    })

                            .setCancelable(false)
                            .show();
                } else {
                    //GPS已经开启了
                }
                break;
        }
    }

    /**
     * 检查GPS是否打开
     * @return
     */
    private boolean checkGPSIsOpen() {
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        if (locationManager == null)
            return false;
        return locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
    }


    //取消蓝牙连接
    private void clientUnConnectDevices() {
    clientThread.cancel();
    }

    //蓝牙连接
    private void clientConnectDevices() {
        clientThread = new ClientThread();
        clientThread.start();
    }

    //开启服务端线程 接收 客户端连接
    private class ClientThread extends  Thread{
        public ClientThread () {
            BluetoothSocket temp = null;
            //配对之前把扫描关闭
            if (mbluetoothAdapter.isDiscovering()){
                mbluetoothAdapter.cancelDiscovery();
            }
            try {
                temp = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
                Log.i(TAG,"连接失败");
            }

            bluetoothSocket = temp;  //把配对时 反射获取的 获取的socket 赋值
            Log.i(TAG,"客户端 配对 socket 初始化:" + bluetoothSocket);
        }

        public  void run(){
            try {
                bluetoothSocket.connect();
                Log.i(TAG,"连接设备");
            } catch (IOException e) {
                e.printStackTrace();
                try {
                    bluetoothSocket.close();
                    Log.e(TAG,"设备连接失败");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }

        public void  cancel(){
            if (bluetoothSocket != null && bluetoothSocket.isConnected()){
                try {
                    bluetoothSocket.close();
                    bluetoothSocket = null;
                    Log.i(TAG,"取消设备连接");
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.i(TAG,"取消设备连接失败");
                }
            }
        }
    }

    //取消蓝牙配对
    private void unPairDevices() {
        Method method = null;
        //配对之前把扫描关闭
        if (mbluetoothAdapter.isDiscovering()){
            mbluetoothAdapter.cancelDiscovery();
        }
        try {
            method = bluetoothDevice.getClass().getMethod("removeBond", (Class[]) null);
            method.invoke(bluetoothDevice, (Object[]) null);
            Log.i(TAG,"取消蓝牙配对");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    //配对蓝牙设备
    private void paireDevice() {

        //配对之前把扫描关闭
        if (mbluetoothAdapter.isDiscovering()){
            mbluetoothAdapter.cancelDiscovery();
        }
        try {
            Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
            method.invoke(bluetoothDevice, 1);
            Log.i(TAG,"配对成功");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            Log.i(TAG,"配对失败");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            Log.i(TAG,"配对失败");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            Log.i(TAG,"配对失败");
        }

    }


    //搜索蓝牙 需要进行广播接收 搜索到一个设备 接收到一个广播
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String  action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                if (device.getBondState() == BluetoothDevice.BOND_BONDED) {  //搜索蓝牙设备
                    Log.i(TAG,"搜索到 已经配对的设备; device name: " + device.getName() + "  device address: " + device.getAddress());
                } else {
                    Log.i(TAG,"搜索到 没有配对的设备; device name: " + device.getName() + "  device address: " + device.getAddress());
                    if(device.getAddress().equals("00:20:00:76:45:39")) {  //指定一个蓝牙设备,根据自己设备
                        bluetoothDevice = device;
                        Log.i(TAG,"指定配对连接的device");
                    }
                }
            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {            // 更新蓝牙设备的绑定状态
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
                    Log.i(TAG,"正在配对 device name: " + device.getName() + "  device address: " + device.getAddress() + " devices uuid: " + device.getUuids());
                } else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                    Log.i(TAG,"完成配对 device name: " + device.getName() + "  device address: " + device.getAddress() + " devices uuid: " + device.getUuids());
                } else if (device.getBondState() == BluetoothDevice.BOND_NONE) {
                    Log.i(TAG,"取消配对 device name: " + device.getName() + "  device address: " + device.getAddress() + " devices uuid: " + device.getUuids());
                }
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {  //搜索结束
                //搜索结束
                Log.i(TAG,"设备搜索结束");
            }
        }
    };


    //已经配对的设备
    private void pairedConnect() {
        Set<BluetoothDevice> pairedDevices = mbluetoothAdapter.getBondedDevices();
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice devices : pairedDevices) {
                Log.i(TAG ,"device name: " + devices.getName()  +
                        "    device address: " + devices.getAddress());
            }
        } else {
            Log.i(TAG,"没有找到已匹配的设备");
        }

    }

    //允许蓝牙被搜索
    private void disCoveredEnable() {
        if(mbluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent (BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300); //设置本机蓝牙在 300 秒之内可以被 搜索
            startActivity(discoverableIntent);
            Log.i(TAG,"设置蓝牙被搜索模式");
        } else {
            Log.i(TAG,"蓝牙模式是: " + mbluetoothAdapter.getScanMode());
        }
    }

    //关闭蓝牙
    private void closeBluetooh() {
        if (mbluetoothAdapter.isEnabled()) {
            mbluetoothAdapter.disable();//关闭蓝牙
            Log.i(TAG,"蓝牙关闭");
        }
    }

    //启动蓝牙
    private void enableBluetooh() {

        if (mbluetoothAdapter == null) {
            Log.i(TAG,"设备不支持蓝牙功能");
            return;
        }

        if (!mbluetoothAdapter.isEnabled()) { //如果蓝牙没有打开
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent,REQUEST_ENABLE);

            //bluetoothAdapter.enable();//隐式打开蓝牙
        } else {
            Log.i(TAG,"蓝牙已经打开");
        }
    }

    public  void onActivityResult(int requestCode,int resultCode,Intent data) {
        if (requestCode == REQUEST_ENABLE) {
            if (resultCode == RESULT_OK) {
                Log.i(TAG,"蓝牙开启成功");
            } else {
                Log.i(TAG,"蓝牙开启失败");
            }
        }
    }

    public void onDestroy() {
        super.onDestroy();
        //解除注册
        unregisterReceiver(mReceiver);
        Log.e(TAG,"解除注册");
        if (mbluetoothAdapter != null)
            mbluetoothAdapter.cancelDiscovery(); //取消搜索
    }
}

6.5 log 展示

在这里插入图片描述

6.6 心得
  1. 蓝牙 有 经典蓝牙 和 BLE 之分,本案例是经典蓝牙
    2)蓝牙 搜索 配对 连接
  2. 蓝牙连接时 需要服务端先启动
    4)服务端 客户端 数据传输 使用的不是同一 socket

文献参考:
Android蓝牙开发—经典蓝牙详细开发流程
https://blog.csdn.net/zqf_888/article/details/81060606

Android开发之蓝牙连接与配对设备
https://blog.csdn.net/VRoymond/article/details/60133903

android 蓝牙之数据传输
https://blog.csdn.net/qq_35702797/article/details/81285643

展开阅读全文

没有更多推荐了,返回首页