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

Android 应用蓝牙连接通信实现

Android 应用蓝牙连接通信实现,主要包括如下步骤:


一.打开蓝牙


// 获取蓝牙适配器
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
1.判断蓝牙是否打开,
bluetoothAdapter.isEnabled()
2. 如果未打开,执行打开蓝牙,需要权限:Manifest.permission.BLUETOOTH
bluetoothAdapter.enable()
或者打开系统蓝牙设置界面让用户点击打开蓝牙。
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);


二.搜索蓝牙设备列表,配对需要连接的设备


1.启动设备发现
bluetoothAdapter.startDiscovery()
2.注册广播监听发现到的蓝牙设备
如果发现蓝牙设备可以获取BluetoothDevice对象

// 注册广播接收器监听设备发现
private final BroadcastReceiver findDeviceReceiver = 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 (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            Log.d("Bluetooth", "发现设备: " + device.getName() + " - " + device.getAddress());
            // 添加到设备列表(如 RecyclerView)
        }
    }
};
// 注册广播监听附近蓝牙设备
//IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
//registerReceiver(findDeviceReceiver, filter);


3.配对
3.1 客户端设备(主动发起连接的设备)发起配对(系统自动处理弹窗)
    device.createBond();    
    手机A系统弹窗显示配对码待用户点击确定,
3.2  服务端设备(等待连接的设备)处理配对
发起配对后,同时待连接蓝牙设备也会弹窗显示配对码待用户点击确定。
发起配对端和待连接蓝牙设备在配对界面点击确定后完成配对。如果超时未点击确定,会弹窗超时提醒。
这里可以 注册广播接收器监听ACTION_PAIRING_REQUEST来监听请求配对信息,该广播会在蓝牙配对时触发并携带设备信息。
ps:一般Android系统已经做了广播监听处理配对请求,无需用户自定义。

//广播监听蓝牙配对请求
BroadcastReceiver pairRequestReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
            if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_PIN) {
                // 处理PIN码请求,可以调用startSystemPairDialog打开系统蓝牙配对弹窗
                // 或者调用startUserPairDialog打开用户自定义蓝牙配对弹窗
            }
        }
    }
};
// 注册广播监听配对请求
//IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
//registerReceiver(pairRequestReceiver, filter);

/**
 * 打开系统蓝牙配对弹窗
 * @param context
 * @param device 通过action ACTION_PAIRING_REQUEST 获取到的请求配对的BluetoothDevice.
 */
private void startSystemPairDialog(Context context, BluetoothDevice device) {
    Intent pairingIntent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
    pairingIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
    pairingIntent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
    pairingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    context.startActivity(pairingIntent);
}

/**
 * 打开用户自定义蓝牙配对弹窗,点击确定完成配对请求。
 * @param context
 * @param device
 */
private void startUserPairDialog(Context context, BluetoothDevice device) {
    //todo 自定义弹窗 点击确定, 执行如下 调用setPin处理PIN码配对
    try {
        Method setPin = device.getClass().getMethod("setPin", byte[].class);
        setPin.invoke(device, "1234".getBytes()); // 替换为设备预设的PIN码
        Method createBond = device.getClass().getMethod("createBond");
        createBond.invoke(device);
    } catch (Exception e) {
        e.printStackTrace();
    }
}


3.3 如果是已经配对过,可获取已配对设备列表

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
    String macAddress = device.getAddress(); // 获取已连接设备的MAC地址
}


三. 连接设备,数据通信


1. 客户端设备(主动发起连接的设备)创建RFCOMM Socket并连接 连接远程设备
//配对过后,创建RFCOMM Socket并连接到服务:使用UUID指定服务标识符,创建RFCOMM Socket并连接到远程设备。

/**
 * 客户端设备(主动发起连接的设备)连接服务端获取 BluetoothSocket 和服务端socket数据通信
 *
 * @param context
 * @param device
 * @throws IOException
 */
private void clientConnect(Context context, BluetoothDevice device) throws IOException {
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    socket.connect(); // 阻塞式连接
    //连接之后就可以获取输入输出流进行 读写操作了
    InputStream inputStream = socket.getInputStream();
    OutputStream outputStream = socket.getOutputStream();
}

2.服务端设备(等待连接的设备)监听连接(BluetoothServerSocket)
连接之后就可以基于socket获取输入输出流进行 读写操作了。    

/**
 * 服务端设备(等待连接的设备)连接客户端后 获取BluetoothServerSocket 和客户端socket数据通信
 *
 * @param context
 * @param device
 * @throws IOException
 */
private void serverListen(Context context, BluetoothDevice device) throws IOException {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    //name:字符串参数,表示服务的名称,这个名称会被写入设备的SDP(服务发现协议)数据库。
    //uuid:UUID,用于标识服务,客户端和服务器必须使用相同的UUID才能建立连接。
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {

        return;
    }
    BluetoothServerSocket serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("MyBluetoothApp", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    BluetoothSocket socket;
    while (true) {
        try {
            socket = serverSocket.accept(); // 阻塞等待客户端连接
            if (socket != null) {
                // 连接成功,启动数据传输线程
                //客户端连接之后就可以获取输入输出流进行 读写操作了
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                serverSocket.close();
                break;
            }
        } catch (IOException e) {
            Log.e("Bluetooth", "ServerSocket异常", e);
            break;
        }
    }
}


    

相关文章:

  • 巧*书重大更新!商务标智能编写,标书一次成型!
  • 函数式编程在 Java:Function、BiFunction、UnaryOperator 你真的会用?
  • 研发效能实践:BDD(行为驱动开发)深度解毒手册:从「撕逼大会」到「人见人爱」的协作秘笈
  • chrome提示https不安全, 不能记住账号密码怎么办? 可以利用js输入账号
  • SQL:DML的基本语法
  • android wifi通过命令行打开2.4G热点
  • 网络安全·第二天·ARP协议安全分析
  • 从代码学习深度学习 - 注意力汇聚:注意力评分函数(加性和点积注意力) PyTorch 版
  • SQL问题分析与诊断(8)——其他工具和技术
  • ECMAScript 7~10 新特性
  • RLAgent note
  • 数据结构与算法-动态规划-线性动态规划,0-1背包,多重背包,完全背包,有依赖的背包,分组背包,背包计数,背包路径
  • 取消echarts地图悬浮时默认黄色高亮
  • Sigma-Delta ADC调制器的拓扑结构分类
  • java中的JNI调用c库
  • 若依微服务集成Flowable仿钉钉工作流
  • 【JavaScript】十八、页面加载事件和页面滚动事件
  • 基于AI的Web应用防火墙(AppWall)实战:漏洞拦截与威胁情报集成
  • 深入理解Java反射
  • 导入 Excel 批量替换文件名称及扩展名
  • 用什么软件做网站最好/百度一下你就知道百度一下
  • wordpress布置网站教程/seo优化服务商
  • 富源县建设局的网站是什么/seo搜索引擎优化课程
  • wordpress防止博客恶意采集/重庆seo整站优化效果
  • pageadmin仿站教程/最新实时大数据
  • 武夷山市建设局网站/营销策略包括哪些方面