第9天蓝牙设备

一.蓝牙介绍:

是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换,我们主要掌握这几项技能:

  • 添加权限:
<!-- 用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 用于访问GPS定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
  • 打开蓝牙并设置允许被搜索
//调用系统开关蓝牙弹窗->用户手动允许
	Intent intent = new Intent();
	intent.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE);//开启蓝
    intent.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);//允许蓝牙被搜索
   intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,200);//设置允许被搜索时间200s内可以被搜索到
    startActivityForResult(intent,100);
  • 关闭蓝牙
bluetoothAdapter.disable();//强制关闭蓝牙
  • 搜索附近的蓝牙
bluetoothAdapter.startDiscovery();//搜索
  • 配对蓝牙:
bluetoothDevice.createBond();//发起配对
  • 使用蓝牙传输数据:socket和ServerSocket传输数据
//1.获得客户端Socket
BluetoothSocket socket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
socket.connect();
//2.获得服务端Socket
BluetoothServerSocket serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(bluetoothAdapter.getName(),uuid);
serverSocket.accpet();

二.蓝牙的作用:

在这里插入图片描述在这里插入图片描述

三 .蓝牙工作原理以及涉及到的类:

在这里插入图片描述

  • BluetoothManager 蓝牙管理类,管理BluetoothAdapter。主要负责管理蓝牙的本地连接。
  • BluetoothAdapter 蓝牙适配器类:代表本蓝牙设备
  • BluetoothDevice 蓝牙设备,配对后的远程蓝牙设备.
  • BluetoothServiceSocket 服务端连接类
  • BluetoothSocket:客户端连接类
  • UUID(universal unique identifier , 全局唯一标识符)
    格式如下:UUID格式一般是”xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,可到http://www.uuidgenerator.com 申请。UUID分为5段,是一个8-4-4-4-12的字符串,这个字符串要求永不重复。蓝牙建立连接时双方必须使用固定的UUID
    例如:文件传输服务
    OBEXFileTransferServiceClass_UUID = ‘{00001106-0000-1000-8000-00805F9B34FB}’

四.蓝牙客户端代码:

如何区分客户端和服务端?如果设备A连接设备B 那么A就是客户端,B就是服务端。
客户端功能:打开蓝牙/关闭蓝牙/搜索附近蓝牙设备/点击其中一个建立连接

在这里插入图片描述

(0)添加权限:

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"/>

(1)MainActivity代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener,MainAdapter.OnItemClick{

    private Button mStart,mStop,mSearch;
    private RecyclerView mRv;
    private BluetoothManager manager;
    private BluetoothAdapter bluetoothAdapter;
    private List<BluetoothDevice>list=new ArrayList<>();
    private BluetoothReceiver receiver;
    private MainAdapter adapter;

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        initBluetooth();
    }

    private void init(){
        mStart = findViewById(R.id.startBtn);
        mStop = findViewById(R.id.stopBtn);
        mSearch = findViewById(R.id.searchBtn);
        mRv = findViewById(R.id.rv);
        mStart.setOnClickListener(this);
        mStop.setOnClickListener(this);
        mSearch.setOnClickListener(this);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        mRv.setLayoutManager(manager);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void initBluetooth(){
         manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
         bluetoothAdapter = manager.getAdapter();
         if (bluetoothAdapter == null){
             Toast.makeText(this,"蓝牙设备故障",Toast.LENGTH_SHORT).show();
             return;
         }
         receiver = new BluetoothReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);//
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(receiver,filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

    @Override
    public void onClick(View view) {
        if (R.id.startBtn == view.getId()){
            Intent intent = new Intent();
            intent.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            intent.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,200);
            startActivityForResult(intent,100);
        }else if (R.id.stopBtn == view.getId()){
            bluetoothAdapter.disable();
        }else if (R.id.searchBtn == view.getId()){
            bluetoothAdapter.startDiscovery();//搜索
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 100){
            if (bluetoothAdapter.isEnabled()){
                Toast.makeText(this,"蓝牙启动",Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(this,"蓝牙未启动",Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public void OnItem(int index) {
         //发起绑定->搜索到的蓝牙设备中的一台
        BluetoothDevice device = list.get(index);
        device.createBond();
      
    }

    private class BluetoothReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            //绑定状态改变;搜索完成;搜索到一台设备

            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)){
                //搜索到一台设备广播
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                list.add(device);
            }else if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)){
                //搜索完成
                //绑定适配器
                adapter = new MainAdapter(list);
                adapter.setClick(MainActivity.this);
                mRv.setAdapter(adapter);
            }else if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
                //绑定状态改变
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                int state = device.getBondState();
                if (state == BluetoothDevice.BOND_BONDED){
                    //发起蓝牙连接线程
                    new BluetoothThread(device).start();
                }
            }
        }
    }
}

(2)客户端线程代码

public class BluetoothThread extends Thread {

    private UUID uuid = UUID.fromString("00001106-0000-1000-8000-00805F9B34FB");
    private String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/xxyy.txt";
    private BluetoothDevice device;

    public BluetoothThread(BluetoothDevice device){
        this.device = device;
    }

    @Override
    public void run() {
        super.run();
        try {
            BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);
            socket.connect();//建立连接
            Log.e("ZXY","客户端建立连接");
            FileInputStream inputStream = new FileInputStream(path);
            OutputStream out = socket.getOutputStream();
            byte[]buff = new byte[1024];
            int leng = 0;
            while ((leng=inputStream.read(buff))!=-1){
                out.write(buff,0,leng);
            }
            out.flush();
            out.close();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五.蓝牙服务端代码:

服务端是被连接者,只有打开蓝牙和关闭蓝牙的功能
(0)添加权限:

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"/>

(1)MainActivity代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button mStart,mStop;
    private BluetoothManager manager;//蓝牙管理器
    private BluetoothAdapter bluetoothAdapter;//蓝牙适配器->开关搜索等本机蓝牙操作
    private BluetoothReceiver receiver;//蓝牙绑定广播接收器

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        initBluetooth();
    }

    private void init(){
          mStart = findViewById(R.id.startBtn);
          mStop = findViewById(R.id.stopBtn);
          mStart.setOnClickListener(this);
          mStop.setOnClickListener(this);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void initBluetooth(){
         manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
         bluetoothAdapter = manager.getAdapter();//获取本机蓝牙适配器
         if (bluetoothAdapter==null){
             //本机无蓝牙硬件模块
             Toast.makeText(this,"本机蓝牙设备故障",Toast.LENGTH_SHORT).show();
             return;
         }
         //蓝牙设备可用
        receiver = new BluetoothReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(receiver,filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

    @Override
    public void onClick(View view) {
        if (bluetoothAdapter==null)
            return;
        if (R.id.startBtn == view.getId()){
// bluetoothAdapter.enable();强制开启->基本无效->手机系统是否允许
            //用户手动允许开启蓝牙
            //调用系统开关蓝牙弹窗->用户手动允许
            Intent intent = new Intent();
            intent.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE);//开启蓝牙
            intent.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);//允许蓝牙被搜索
            intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,200);//设置允许被搜索时间200s内可以被搜索到
            startActivityForResult(intent,100);
        }else if (R.id.stopBtn == view.getId()){
            bluetoothAdapter.disable();//强制关闭蓝牙
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode==100){
            String msg;
            //蓝牙是否开启
            if (bluetoothAdapter.isEnabled()){
                msg = "开启成功";
            }else
                msg = "开启失败";
            Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
        }
    }

    //注册蓝牙配对广播->通过广播侦听配对状态
    private class BluetoothReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            //接收蓝牙配对广播
            if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
                //配对过来的蓝牙设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                int state = device.getBondState();//获取绑定状态
                new BluetoothThread(bluetoothAdapter).start();
                if (state == BluetoothDevice.BOND_NONE){
                    //未绑定
                    Log.e("ZXY","未绑定");
                }else if (state == BluetoothDevice.BOND_BONDING){
                    //绑定中
                    Log.e("ZXY","绑定中");
                }else if (state == BluetoothDevice.BOND_BONDED){
                    //绑定完成
                    Log.i("lq","绑定完成");
                }
            }
        }
    }

}

(2)服务端线程代码:

/** * 蓝牙serversocket线程 * */
public class BluetoothThread extends Thread{

    BluetoothAdapter adapter;//本机蓝牙适配器
    UUID uuid = UUID.fromString("00001106-0000-1000-8000-00805F9B34FB");//系统随机产生string字符串35年内不重复->连接蓝牙时秘钥
    String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/xxyy.txt";
    //传递过来的txt文件本地保存路径

    public BluetoothThread(BluetoothAdapter adapter){
        this.adapter = adapter;
    }

    @Override
    public void run() {
        super.run();
        try {
            BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord(adapter.getName(),uuid);
            //侦听连接过来的socket
            BluetoothSocket socket = serverSocket.accept();
            Log.e("ZXY","蓝牙连接成功");
            InputStream in = socket.getInputStream();
            //向本地sd卡保存文件的输出流
            FileOutputStream out = new FileOutputStream(path);
            byte[]buff = new byte[1024];
            int leng = 0;
            while ((leng=in.read(buff))!=-1){
                out.write(buff,0,leng);
                Log.e("ZXY","服务器边读边保存");
            }
            out.flush();
            out.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}