• android -------- 蓝牙通信


    前面介绍了蓝牙的一些知识,今天来聊一聊蓝牙之间的通信,实现两个设备通信。

    我用两部手机实现相互发消息的功能

    无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,UniversallyUnique Identifier)

    蓝牙的UUID

    两个蓝牙设备进行连接时需要使用同一个UUID。但很多读者可能发现,有很多型号的手机(可能是非Android系统的手机)之间使用了不同的程序也可以使用蓝牙进行通讯。从表面上看,它们之间几乎不可能使用同一个UUID。

    UUID的格式如下:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    UUID的格式被分成5段,其中中间3段的字符数相同,都是4,第1段是8个字符,最后一段是12个字符。所以UUID实际上是一个8-4-4-4-12的字符串。

    实际上,UUID和TCP的端口一样,也有一些默认的值。例如,将蓝牙模拟成串口的服务就使用了一个标准的UUID:

    00001101-0000-1000-8000-00805F9B34FB

    除此之外,还有很多标准的UUID,如下面就是两个标准的UUID:

    信息同步服务:00001104-0000-1000-8000-00805F9B34FB

    文件传输服务:00001106-0000-1000-8000-00805F9B34FB

    蓝牙终端间数据传输

    通过蓝牙传输数据与Socket类似。在网络中使用Socket和ServerSocket控制客户端和服务端的数据读写。而蓝牙通讯也由客户端和服务端Socket来完成。蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket。这两个类都在android.bluetooth包中。

    无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,Universally Unique Identifier),UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。

    模拟一个蓝牙数据的传输:

        private ListView lvDevices;
        // 获取到蓝牙适配器
        private BluetoothAdapter mBluetoothAdapter;
        // ListView的字符串数组适配器
        private List<String> bluetoothDevices = new ArrayList<String>();
        private ArrayAdapter<String> arrayAdapter;
        // UUID,蓝牙建立链接需要的
        private final UUID MY_UUID = UUID
                .fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//随便定义一个
    
        // 获取到选中设备的客户端串口,全局变量,否则连接在方法执行完就结束了
        private BluetoothSocket clientSocket;
        // 选中发送数据的蓝牙设备,全局变量,否则连接在方法执行完就结束了
        private BluetoothDevice device;
        // 获取到向设备写的输出流,全局变量,否则连接在方法执行完就结束了
        private OutputStream os;//输出流
    
    
        // 为其链接创建一个名称
        private final String NAME = "Bluetooth_Socket";
    
        // 服务端利用线程不断接受客户端信息
        private AcceptThread thread;

    主要代码:

    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.demo2);
            initView();
        }
    
        private void initView() {
                 findViewById(R.id.btn1).setOnClickListener(this);
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
            lvDevices = (ListView) findViewById(R.id.listview);
            //获取已经配对的蓝牙设备
            Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
            if (pairedDevices.size() > 0) {
                for (BluetoothDevice device : pairedDevices) {
                    bluetoothDevices.add(device.getName() + ":"+ device.getAddress());
                }
            }
            arrayAdapter = new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices);
            lvDevices.setAdapter(arrayAdapter);
            lvDevices.setOnItemClickListener(this);//Activity实现OnItemClickListener接口
    
            //每搜索到一个设备就会发送一个该广播
            IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
            this.registerReceiver(receiver, filter);
            //当全部搜索完后发送该广播
            filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
            this.registerReceiver(receiver, filter);
    
    
            // 实例接收客户端传过来的数据线程
            thread = new AcceptThread();
            // 线程开始
            thread.start();
    
        }
    
    
        @Override
        public void onClick(View v) {
            //如果当前在搜索,就先取消搜索
            if (mBluetoothAdapter.isDiscovering()) {
                mBluetoothAdapter.cancelDiscovery();
            }
            //开启搜索
            mBluetoothAdapter.startDiscovery();
        }
    
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            String s = arrayAdapter.getItem(position);
            String address = s.substring(s.indexOf(":") + 1).trim();//把地址解析出来
            //主动连接蓝牙服务端
            try {
                //判断当前是否正在搜索
                if (mBluetoothAdapter.isDiscovering()) {
                    mBluetoothAdapter.cancelDiscovery();
                }
                try {
                    if (device == null) {
                        //获得远程设备
                        device = mBluetoothAdapter.getRemoteDevice(address);
                    }
                    if (clientSocket == null) {
                        //创建客户端蓝牙Socket
                        clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
                        //开始连接蓝牙,如果没有配对则弹出对话框提示我们进行配对
                        clientSocket.connect();
                        //获得输出流(客户端指向服务端输出文本)
                        os = clientSocket.getOutputStream();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(this, "失败", Toast.LENGTH_LONG).show();
                }
                if (os != null) {
                    //往服务端写信息
                    os.write("蓝牙信息来了".getBytes("utf-8"));
                    // 吐司一下,告诉用户发送成功
                    Toast.makeText(this, "发送信息成功,请查收", Toast.LENGTH_LONG).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
                // 如果发生异常则告诉用户发送失败
                Toast.makeText(this, "发送信息失败", Toast.LENGTH_LONG).show();
            }
        }
    
    
    
        /**
         * 定义广播接收器
         */
        private final BroadcastReceiver receiver = 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) {
                        bluetoothDevices.add(device.getName() + ":" + device.getAddress());
                        arrayAdapter.notifyDataSetChanged();//更新适配器
                    }
    
                } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                    //已搜素完成
                    Toast.makeText(Demo2Activity.this,"已搜索完成",Toast.LENGTH_LONG).show();
                }
            }
        };
    
        // 创建handler,因为我们接收是采用线程来接收的,在线程中无法操作UI,所以需要handler
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                super.handleMessage(msg);
                // 通过msg传递过来的信息,吐司一下收到的信息
                Log.i(NAME,msg.obj.toString());// 接收其他设备传过来的消息
                Toast.makeText(Demo2Activity.this, (String) msg.obj, Toast.LENGTH_LONG).show();
            }
        };
    
    
        // 服务端接收信息线程
        private class AcceptThread extends Thread {
            private BluetoothServerSocket serverSocket;// 服务端接口
            private BluetoothSocket socket;// 获取到客户端的接口
            private InputStream is;// 获取到输入流
            private OutputStream os;// 获取到输出流
    
            public AcceptThread() {
                try {
                    // 通过UUID监听请求,然后获取到对应的服务端接口
                    serverSocket = mBluetoothAdapter
                            .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
    
            public void run() {
                try {
                    // 接收其客户端的接口
                    socket = serverSocket.accept();
                    // 获取到输入流
                    is = socket.getInputStream();
                    // 获取到输出流
                    os = socket.getOutputStream();
    
                    // 无线循环来接收数据
                    while (true) {
                        // 创建一个128字节的缓冲
                        byte[] buffer = new byte[128];
                        // 每次读取128字节,并保存其读取的角标
                        int count = is.read(buffer);
                        // 创建Message类,向handler发送数据
                        Message msg = new Message();
                        // 发送一个String的数据,让他向上转型为obj类型
                        msg.obj = new String(buffer, 0, count, "utf-8");
                        // 发送数据
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
    
            }
        }

    分别在两个手机上安装APP,点击扫描设备,然后点击连接的蓝牙名称发送消息

    下图是我发送给另一个设备,然后另一个收到消息在发送消息过来。

    效果图:

              

    源码下载:https://github.com/DickyQie/android-bluetooth

  • 相关阅读:
    JavaScript语言基础
    IP地址分类及CIDR划分方法
    Python静态方法实现单实例模式
    【转载】http和socket之长连接和短连接
    DDoS攻击
    Vue自定义过滤器
    解决跨域问题
    微信菜单创建
    canvas标签(1)--线条、矩形、圆形、文本、阴影、抛小球
    Bootstrap CSS概览代码文字标注篇
  • 原文地址:https://www.cnblogs.com/zhangqie/p/8862226.html
Copyright © 2020-2023  润新知