详解Android——蓝牙技术 带你实现终端间数据传输
发布时间 - 2026-01-10 21:50:40 点击率:次蓝牙技术在智能硬件方面有很多用武之地,今天我就为大家分享一下蓝牙在Android系统下的使用方法技巧,并实现一下两个终端间数据的传输。

蓝牙(Bluetooth)是一种短距离的无线通信技术标准,蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。
这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。
1.打开和关闭蓝牙
第一种方法相对简单,直接调用系统对话框启动蓝牙:
在AndroidManifest文件中添加需要的权限,高版本也不需要动态授权:
<uses-permission android:name="android.permission.BLUETOOTH" />
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
如果不想让用户看到这个对话框,那么我们还可以选择第二种方法,进行静默开启蓝牙。
第二种方法,静默开启,不会有方法一的对话框:
在AndroidManifest文件中添加需要的权限:
<!-- 已适配Android6.0 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <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_le" android:required="true" />
由于蓝牙所需要的权限包含Dangerous Permissions,所以我们需要在Java代码中进行动态授权处理:
private static final int REQUEST_BLUETOOTH_PERMISSION=10;
private void requestBluetoothPermission(){
//判断系统版本
if (Build.VERSION.SDK_INT >= 23) {
//检测当前app是否拥有某个权限
int checkCallPhonePermission = ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION);
//判断这个权限是否已经授权过
if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){
//判断是否需要 向用户解释,为什么要申请该权限
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION))
Toast.makeText(this,"Need bluetooth permission.",
Toast.LENGTH_SHORT).show();
ActivityCompat.requestPermissions(this ,new String[]
{Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_BLUETOOTH_PERMISSION);
return;
}else{
}
} else {
}
}
接下来我们就可以静默开启蓝牙了:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothAdapter.enable(); //开启 //mBluetoothAdapter.disable(); //关闭
下面我们来看一下如何通过代码搜索蓝牙设备。
2.通过代码搜索蓝牙设备
搜索分为主动搜索和被动搜索。
我们开始进行主动搜索:
(1)创建BluetoothAdapter对象
TextView tvDevices = (TextView)findViewById(R.id.tv_devices); BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
(2)我们先获取并显示一下已经配对的蓝牙设备列表
//获取已经配对的蓝牙设备
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
tvDevices.append(device.getName() + ":" + device.getAddress());
}
}
(3)下面我们定义广播接收器
// 设置广播信息过滤 IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一个设备就会发送一个该广播 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//当全部搜索完后发送该广播 filter.setPriority(Integer.MAX_VALUE);//设置优先级 // 注册蓝牙搜索广播接收者,接收并处理搜索结果 this.registerReceiver(receiver, filter);
蓝牙设备的广播接收器如下:
/**
* 定义广播接收器
*/
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) {
tvDevices.append(device.getName() + ":"+ device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//已搜素完成
}
}
};
(4)我们创建一个Button按钮,当点击Button时进行搜索,Button点击事件如下:
//如果当前在搜索,就先取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
//开启搜索
mBluetoothAdapter.startDiscovery();
3.蓝牙的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
4.蓝牙终端间数据传输
通过蓝牙传输数据与Socket类似。在网络中使用Socket和ServerSocket控制客户端和服务端的数据读写。而蓝牙通讯也由客户端和服务端Socket来完成。蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket。这两个类都在android.bluetooth包中。
无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,Universally Unique Identifier),UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。
我们开始进行模拟一个蓝牙数据的传输:
首先来看客户端:
(1)定义全局常量变量
private ListView lvDevices;
private BluetoothAdapter mBluetoothAdapter;
private List<String> bluetoothDevices = new ArrayList<String>();
private ArrayAdapter<String> arrayAdapter;
private final UUID MY_UUID = UUID
.fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//随便定义一个
private BluetoothSocket clientSocket;
private BluetoothDevice device;
private OutputStream os;//输出流
(2)在onCreate方法中做初始化操作
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
lvDevices = (ListView) findViewById(R.id.lv_devices);
//获取已经配对的蓝牙设备
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);
蓝牙设备的广播接收器如下:
/**
* 定义广播接收器
*/
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)) {
//已搜素完成
}
}
};
(4)我们创建一个Button按钮,当点击Button时进行搜索,Button点击事件如下:
//如果当前在搜索,就先取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
//开启搜索
mBluetoothAdapter.startDiscovery();
(5)接下来我们设置列表的点击事件:
@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) {
}
if (os != null) {
//往服务端写信息
os.write("蓝牙信息来了".getBytes("utf-8"));
}
} catch (Exception e) {
}
}
接下来看服务端:
服务端使用的是另一部手机,接受上面手机通过蓝牙发送过来的信息并显示。
(1)定义全局常量变量:
private BluetoothAdapter mBluetoothAdapter;
private AcceptThread acceptThread;
private final UUID MY_UUID = UUID
.fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//和客户端相同的UUID
private final String NAME = "Bluetooth_Socket";
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
private InputStream is;//输入流
(2)定义服务端线程类:
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), String.valueOf(msg.obj),
Toast.LENGTH_LONG).show();
super.handleMessage(msg);
}
};
//服务端监听客户端的线程类
private class AcceptThread extends Thread {
public AcceptThread() {
try {
serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (Exception e) {
}
}
public void run() {
try {
socket = serverSocket.accept();
is = socket.getInputStream();
while(true) {
byte[] buffer =new byte[1024];
int count = is.read(buffer);
Message msg = new Message();
msg.obj = new String(buffer, 0, count, "utf-8");
handler.sendMessage(msg);
}
}
catch (Exception e) {
}
}
}
(3)在onCreate方法中初始化线程类并开启
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); acceptThread = new AcceptThread(); acceptThread.start();
我们运行程序看一下效果图:
点击“搜索蓝牙设备”按钮,就会搜索到另一台手机的蓝牙信息,我们点击条目,另一台手机会出现如下变化:
弹出Toast,此时证明我们的蓝牙数据已经传输过来了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# android蓝牙开发
# Android蓝牙技术
# android
# 蓝牙
# 如何正确实现Android启动屏画面的方法(避免白屏)
# Android编程之简单启动画面实现方法
# Android简单实现启动画面的方法
# Android编程中调用Camera时预览画面有旋转问题的解决方法
# Android启动画面的实现方法
# Android开机画面的具体修改方法
# android Socket实现简单聊天功能以及文件传输
# Android实时获取摄像头画面传输至PC端思路详解
# 服务端
# 客户端
# 就会
# 对话框
# 链路
# 种方法
# 是一个
# 有很多
# 弹出
# 就先
# 完后
# 创建一个
# 的是
# 都是
# 另一台
# 我就
# 也不
# 来了
# 也有
# 是一种
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
高端云建站费用究竟需要多少预算?
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
详解jQuery中基本的动画方法
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
如何快速建站并高效导出源代码?
高防服务器租用如何选择配置与防御等级?
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】
HTML 中如何正确使用模板变量为元素的 name 属性赋值
Python自然语言搜索引擎项目教程_倒排索引查询优化案例
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
Laravel如何集成Inertia.js与Vue/React?(安装配置)
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
利用python获取某年中每个月的第一天和最后一天
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
Laravel怎么清理缓存_Laravel optimize clear命令详解
油猴 教程,油猴搜脚本为什么会网页无法显示?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
如何批量查询域名的建站时间记录?
如何在阿里云虚拟服务器快速搭建网站?
javascript基于原型链的继承及call和apply函数用法分析
Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
如何用西部建站助手快速创建专业网站?
个人网站制作流程图片大全,个人网站如何注销?
个人摄影网站制作流程,摄影爱好者都去什么网站?
制作电商网页,电商供应链怎么做?
Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
网站图片在线制作软件,怎么在图片上做链接?
Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
如何基于云服务器快速搭建个人网站?
Laravel怎么在Blade中安全地输出原始HTML内容
html5audio标签播放结束怎么触发事件_onended回调方法【教程】
如何在万网自助建站中设置域名及备案?
大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?
头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?
如何用AWS免费套餐快速搭建高效网站?
如何快速辨别茅台真假?关键步骤解析
Android 常见的图片加载框架详细介绍
微博html5版本怎么弄发超话_超话进入入口及发帖格式要求【教程】

