当前位置: 首页 > article >正文

Android蓝牙通信

需求:手机扫描Android设备二维码,获取蓝牙MAC地址,建立Scoket通信,发送数据。

手机客户端:

申请蓝牙权限

<uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-feature android:name="android.hardware.bluetooth" />
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
public void requestPermission() {
        if (Build.VERSION.SDK_INT >= 23 ) {
            ArrayList<String> permissionsList = new ArrayList<>();
            String[] permissions = {
                    Manifest.permission.BLUETOOTH,
                    Manifest.permission.BLUETOOTH_ADMIN,
                    Manifest.permission.BLUETOOTH_CONNECT,
                    Manifest.permission.BLUETOOTH_SCAN,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION
            };
            for (String perm : permissions) {
                if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(perm)) {
                    permissionsList.add(perm);
                }
            }
            if (!permissionsList.isEmpty()) {
                String[] strings = new String[permissionsList.size()];
                requestPermissions(permissionsList.toArray(strings), 0);
            }
        }
    }

打开蓝牙,扫描附近蓝牙设备,扫描到目标蓝牙设备 根据蓝牙MAC地址建立连接,需要配对,发送数据

private final static String TAG = "Scan";
    private Button scanButton;
    private BluetoothSocket bluetoothSocket;
    BluetoothAdapter bluetoothAdapter;
    boolean stopDiscover;
    private String CONNECT_BLUETOOTH_MAC = "22:22:56:3A:00:00";

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        registerReceiver(receiver, filter);

        if (bluetoothAdapter != null) {
            if (!bluetoothAdapter.isEnabled()) {
                bluetoothAdapter.enable();
            }
            bluetoothAdapter.startDiscovery();
        }


Thread mThread = new Thread(() -> {
        try {
            if (bluetoothAdapter != null) {
                //真我GT Neo6 SE [54:9A:8F:00:6E:18]
                String deviceAddress = CONNECT_BLUETOOTH_MAC; // 目标蓝牙设备的 MAC 地址
                // 使用设备的 MAC 地址获取设备对象
                BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(deviceAddress);
                if(bluetoothDevice == null){
                    Log.d(TAG, "bluetoothDevice  null");
                }

//                if (bluetoothDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
//                    bluetoothDevice.createBond();
//                } else {
//                    Log.d("Bluetooth", "设备已配对");
//                }

                // 创建一个 RFCOMM 传输通道
                bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                bluetoothAdapter.cancelDiscovery(); // 在连接之前,停止搜索设备
                bluetoothSocket.connect(); // 连接到蓝牙设备
                InputStream inputStream = bluetoothSocket.getInputStream();
                OutputStream outputStream = bluetoothSocket.getOutputStream();
                //Receive
                byte[] buffer = new byte[1024];
                int bytesRead;
//                while (true) {
//                    try {
//                        bytesRead = inputStream.read(buffer);
//                    } catch (IOException e) {
//                        break;
//                    }
//                }
                //Send
                String message = "Hello, Bluetooth Device!";
                outputStream.write(message.getBytes());
            }
        } catch (SecurityException e) {
            Log.d(TAG, e.toString());
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, e.toString());
        }
    });

    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, action);
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
                String deviceName = device.getName();
                String deviceAddress = device.getAddress(); // 设备的 MAC 地址
                Log.d(TAG, "找到设备:" + deviceName + " [" + deviceAddress + "]");
                if(CONNECT_BLUETOOTH_MAC.equals(deviceAddress)){
                    stopDiscover = true;
                    mThread.start();
                }
            }else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
                Log.d(TAG, "ACTION_DISCOVERY_STARTED");
            }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
                Log.d(TAG, "ACTION_DISCOVERY_FINISHED");
                if(!stopDiscover){
                    bluetoothAdapter.startDiscovery();
                }
            }
        }
    };


protected void onDestroy() {
        super.onDestroy();
        try {
            if (bluetoothSocket != null) {
                bluetoothSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (receiver != null){
            unregisterReceiver(receiver);
        }
        stopDiscover = false;
    }

Android服务端:

申请蓝牙权限,打开蓝牙,设置蓝牙可见性,根据UUID等待接受客户端scoket连接,读取数据

package com.itemp.ms66btreceiver;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {
    private String TAG = "BTReceiver";
    private StringBuilder incoming = new StringBuilder();
    private boolean listening;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestPermission();

    }

    @Override
    protected void onStart() {
        super.onStart();
        startServerSocket();
    }

    private void startServerSocket() {
        BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
        Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); // 300秒可见性
        startActivity(discoverableIntent);

        UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
        String name = "bluetoothserver";
        try {
            if (bluetoothAdapter != null) {
                if (!bluetoothAdapter.isEnabled()) {
                    bluetoothAdapter.enable();
                }
//            bluetoothAdapter.startDiscovery();
            }
            final BluetoothServerSocket btserver = bluetoothAdapter.listenUsingRfcommWithServiceRecord(name, uuid);
            Thread acceptThread = new Thread(() -> {
                final BluetoothSocket serverSocket;
                try {
                    serverSocket = btserver.accept();
                    runOnUiThread(() -> {
                        Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_LONG).show();
                    });
                    listenForMessages(serverSocket, incoming);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            acceptThread.start();
        } catch (SecurityException e) {
        } catch (IOException e) {
            Log.e(TAG, "Socket listener IO Exception", e);
        }
    }

    private void sendMessage(BluetoothSocket socket, String message) {
        OutputStream outStream;
        try {
            outStream = socket.getOutputStream();
            byte[] byteArray = (message + " ").getBytes();
            byteArray[byteArray.length - 1] = 0;
            outStream.write(byteArray);
        } catch (IOException e) {
        }
    }

    private void listenForMessages(BluetoothSocket socket, final StringBuilder incoming) {
        listening = true;
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        try {
            InputStream instream = socket.getInputStream();
            int bytesRead = -1;
            while (listening) {
                bytesRead = instream.read(buffer);
                if (bytesRead != -1) {
                    String result = "";
                    while ((bytesRead == bufferSize) && (buffer[bufferSize - 1] != 0)) {
                        result = result + new String(buffer, 0, bytesRead - 1);
                        bytesRead = instream.read(buffer);
                    }
                    result = result + new String(buffer, 0, bytesRead - 1);
                    incoming.append(result);
                    runOnUiThread(() -> {
                        Log.d(TAG, "BT Receiver:" + incoming.toString());
                    });
                }
            }
            socket.close();
        } catch (IOException e) {

        }
    }

    //22 22 d0 1f 05 00
    public void requestPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            ArrayList<String> permissionsList = new ArrayList<>();
            String[] permissions = {Manifest.permission.BLUETOOTH,
                    Manifest.permission.BLUETOOTH_ADMIN,
                    Manifest.permission.BLUETOOTH_CONNECT,
                    Manifest.permission.BLUETOOTH_SCAN,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.BLUETOOTH_ADVERTISE,
                    Manifest.permission.ACCESS_FINE_LOCATION};
            for (String perm : permissions) {
                if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(perm)) {
                    permissionsList.add(perm);
                }
            }
            if (!permissionsList.isEmpty()) {
                String[] strings = new String[permissionsList.size()];
                requestPermissions(permissionsList.toArray(strings), 0);
            }
        }
    }
}

查看服务端Logcat  收到客户端发送的字符串:Hello, Bluetooth Device

服务端创建BluetoothServerSocket ,BluetoothAdapter中提供了两种创建BluetoothServerSocket 方式,bluetoothDevice.createRfcommSocketToServiceRecord为创建安全的RFCOMM Bluetooth socket,该连接是安全的需要进行配对。而通过bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord创建的RFCOMM Bluetooth socket是不安全的,连接时不需要进行配对。其中的uuid需要服务器端和客户端进行统一。

客户端

客户端主要用来创建RFCOMM socket,并连接服务端。先扫描周围的蓝牙设备,如果扫描到指定设备则进行连接。mBlthChatUtil.connect(scanDevice)连接到设备,连接过程主要在ConnectThread线程中进行,先创建socket,方式有两种,如下代码中是安全的(createRfcommSocketToServiceRecord)。另一种不安全连接对应的函数是createInsecureRfcommSocketToServiceRecord。


http://www.kler.cn/a/452162.html

相关文章:

  • 【ES6复习笔记】Class类(15)
  • 【R语言遥感技术】“R+遥感”的水环境综合评价方法
  • Kubernetes(k8s)离线部署DolphinScheduler3.2.2
  • 写作词汇积累:见笑、尽显、稀疏、染指
  • 小程序租赁系统开发指南与实现策略
  • 移动端网页兼容适配方案小结
  • VR 动感单车身心调适系统的功能与作用
  • 前端 MYTED单篇TED词汇学习功能优化
  • Leetcode 695 Max Area of Island
  • Logback日志框架中的继承机制详解
  • 学习postman工具使用
  • 头歌-机器学习在 NLP 中的实战
  • Github 2024-12-25C开源项目日报 Top8
  • HTTP 协议、AJAX - 异步网络请求及跨域、同源策略
  • LabVIEW软件项目设计方案如何制定
  • 构建专属AI知识库:Obsidian Copilot + 硅基流动SiliconCloud API 实战指南
  • 汽车消费新旺季到来,联众优车年末冲刺把好服务关
  • 静态断言(Static Assertions)在 C++ 中的使用
  • PHP爬虫类的并发与多线程处理技巧
  • Sublime 安装 View in Browser 插件后,点击无反应的解决方法
  • linux命令中cp命令-rf与-a的差别
  • HTTP/2与HTTP1.X的对比及升级指南
  • win11+matlab2021a配置C-COT
  • 全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战训练三)
  • MySQL HA 方案 MMM、MHA、MGR、PXC 对比
  • Hive SQL 窗口函数 `ROW_NUMBER() ` 案例分析