You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android蓝牙数据传输开发求助:Java新手需实现跨设备数字文本传输

嘿,作为刚入门时被Android蓝牙官方指南绕晕过的过来人,我太懂你的感受了!官方文档全是大段概念,新手根本抓不住重点。咱们直接针对你的需求——传输4-5个数字和2-3段文本——一步一步来,都是接地气的Java代码,看完就能上手~

一、先把权限补全(你可能漏了关键部分)

你已经加了基础蓝牙权限,但Android不同版本的权限要求不一样,尤其是12+的新权限,补全你的Manifest代码:

<!-- 基础蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<!-- Android 12+ 新增的细分权限,必须加 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

<!-- Android 11及以下版本,需要位置权限才能扫描蓝牙设备 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 声明App依赖蓝牙硬件 -->
<uses-feature android:name="android.hardware.bluetooth" android:required="true" />

另外,Android 6+还要动态申请权限(比如BLUETOOTH_CONNECT、位置权限),不然会直接报错。

二、核心逻辑:蓝牙传输本质是Socket通信

Android蓝牙传输用的是RFCOMM协议,和普通网络Socket逻辑一样——分「服务端(等待连接的设备)」和「客户端(主动连的设备)」。你要传的数字、文本,本质就是把数据转成字节流发送,再解析回来。

1. 服务端:等待客户端连接并发送数据

先开个线程(绝对不能在主线程做!会卡死App)监听连接:

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

// 重点!服务端和客户端必须用同一个UUID,我用的是标准SPP服务UUID
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothAdapter bluetoothAdapter;

// 启动服务端的方法,在你需要的地方调用(比如点击按钮)
private void startBluetoothServer() {
    bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    // 先检查蓝牙是否开启
    if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
        // 这里可以弹出提示让用户开蓝牙,比如调用Intent开启蓝牙设置
        return;
    }

    // 用线程处理阻塞操作
    new Thread(() -> {
        BluetoothServerSocket serverSocket = null;
        try {
            // 创建服务器Socket,参数是服务名称和UUID
            serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("MyTextNumberService", MY_UUID);
            // 等待客户端连接(这是阻塞方法,会一直等直到有设备连进来)
            BluetoothSocket socket = serverSocket.accept();
            
            // 连接成功!现在发送你的数据
            // 推荐把数字和文本打包成字符串,比如用逗号分隔数字,换行分隔文本
            sendData(socket, "123,456,789,101,202"); // 4-5个数字
            sendData(socket, "第一段文本内容");
            sendData(socket, "第二段文本内容");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 用完记得关闭Socket
            try {
                if (serverSocket != null) serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

// 通用发送数据方法
private void sendData(BluetoothSocket socket, String data) throws IOException {
    OutputStream outputStream = socket.getOutputStream();
    outputStream.write(data.getBytes()); // 把字符串转成字节发送
    outputStream.flush();
}

2. 客户端:扫描并连接服务端,接收数据

客户端要先找到服务端设备,然后发起连接:

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import java.io.IOException;
import java.io.InputStream;

// 连接指定蓝牙设备的方法,参数是你扫描到的服务端设备
private void connectToServerDevice(BluetoothDevice serverDevice) {
    new Thread(() -> {
        BluetoothSocket socket = null;
        try {
            // 创建客户端Socket,必须用和服务端一样的UUID
            socket = serverDevice.createRfcommSocketToServiceRecord(MY_UUID);
            // 发起连接(阻塞方法)
            socket.connect();
            
            // 连接成功!接收数据
            String numbersStr = receiveData(socket);
            String text1 = receiveData(socket);
            String text2 = receiveData(socket);

            // 解析数字:把逗号分隔的字符串转成int数组
            String[] numArray = numbersStr.split(",");
            int[] numbers = new int[numArray.length];
            for (int i = 0; i < numArray.length; i++) {
                numbers[i] = Integer.parseInt(numArray[i]);
            }

            // 现在你就拿到了数字数组和两段文本,随便处理啦
            // 比如更新UI的话,要切回主线程:runOnUiThread(() -> { ... });

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

// 通用接收数据方法
private String receiveData(BluetoothSocket socket) throws IOException {
    InputStream inputStream = socket.getInputStream();
    byte[] buffer = new byte[1024]; // 缓冲区大小足够装你的文本和数字
    int bytesRead = inputStream.read(buffer);
    return new String(buffer, 0, bytesRead);
}
三、进阶小技巧:用JSON打包数据更清晰

如果觉得用逗号、换行分隔数据太麻烦,推荐用JSON格式打包,解析起来更不容易出错。比如:

{
    "numbers": [123, 456, 789, 101],
    "texts": ["第一段文本", "第二段文本"]
}

你可以用Gson库把Java对象转成JSON字符串发送,接收后再转成对象。Gson的依赖在build.gradle里加:

implementation 'com.google.code.gson:gson:2.10.1'

示例代码:

// 定义一个数据类
public class BluetoothData {
    public int[] numbers;
    public String[] texts;
}

// 服务端发送:
BluetoothData dataToSend = new BluetoothData();
dataToSend.numbers = new int[]{123,456,789};
dataToSend.texts = new String[]{"文本1", "文本2"};
String json = new Gson().toJson(dataToSend);
sendData(socket, json);

// 客户端接收:
String jsonReceived = receiveData(socket);
BluetoothData receivedData = new Gson().fromJson(jsonReceived, BluetoothData.class);
// 直接用receivedData.numbers和receivedData.texts就行
四、新手必避的坑
  • 绝对不能在主线程操作蓝牙Socket:所有连接、收发数据的操作都要放在子线程,不然会触发ANR(应用无响应)。
  • UUID必须完全一致:服务端和客户端的UUID差一个字符都连不上,我给的是标准SPP服务UUID,直接用就行。
  • 动态申请权限:除了Manifest里的权限,Android 6+必须在代码里动态申请BLUETOOTH_CONNECT、位置权限(旧版本),不然会被系统拒绝操作。
  • 蓝牙状态检查:操作前一定要检查蓝牙是否开启,没开启的话引导用户去设置开启。

内容的提问来源于stack exchange,提问作者Manos Rasidakis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:31:52