蓝牙技术在智能硬件方面有很多用武之地,今天我就为大家分享一下蓝牙技术在Android系统下的使用方法技巧。蓝牙是一种短距离的无线通信技术标准,蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。

Android 支持的蓝牙协议栈有:

蓝牙协议栈 说明
Bluz Linux官方蓝牙协议栈,最成熟的开源蓝牙协议栈,灵活高效。
BlueDroid 从Android 4.2开始,Google在Android中推出了它和博通公司一起开发的BlueDroid以替代BlueZ,框架结构变得更为简洁和清晰。
BLE 低功耗蓝牙协议栈,传输距离远,速率快。

1.Android系统蓝牙本地操作

Android 系统本地蓝牙代表本地的蓝牙适配器,也是所有蓝牙交互的入口点,可以对本地或者其他终端设备进行操作。其中 BluetoothAdapter 是重要的类,代表本地蓝牙适配器。

1.判断本地蓝牙是否打开

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // null:表示不支持蓝牙
boolean enabled = mBluetoothAdapter.isEnabled(); // true:处于打开状态, false:处于关闭状态

2.调用系统对话框启动本地蓝牙

// 添加蓝牙权限,不需要动态授权
// <uses-permission android:name="android.permission.BLUETOOTH" />
// <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);

3.静默开启本地蓝牙 不会有对话框

在AndroidManifest文件中添加需要的权限:

<!-- 适配Android6.0/7.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" />
  • 1

由于蓝牙所需要的权限包含Dangerous Permissions,所以我们需要在Java代码中进行动态授权处理:

if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(context,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
  • 1

接下来我们就可以静默开启和关闭本地蓝牙了:

mBluetoothAdapter.enable(); // 开启
//mBluetoothAdapter.disable(); // 关闭

4.本地蓝牙主动搜索周边蓝牙

搜索分为主动搜索和被动搜索。我们开始进行主动搜索:

1.创建 BluetoothAdapter 对象,首先获取已经配对的蓝牙设备:

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices(); // 获取已经配对的蓝牙设备
  • 1

2.下面我们定义广播接收器

// 设置广播信息过滤
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一个设备就会发送一个该广播
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//当全部搜索完后发送该广播
filter.setPriority(Integer.MAX_VALUE);//设置优先级
// 注册蓝牙搜索广播接收者,接收并处理搜索结果
this.registerReceiver(receiver, filter);

3.开始搜索周边蓝牙:

//如果当前在搜索,就先取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
//开启搜索
mBluetoothAdapter.startDiscovery();

2.Android系统蓝牙远程操作

1.蓝牙的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

2.本地蓝牙与周边蓝牙间数据传输

通过蓝牙传输数据与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;//输出流
  • 1

(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);
  • 1

蓝牙设备的广播接收器如下:

/**
* 定义广播接收器
*/
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();
  • 1

(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) {
}
}

(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();
  • 1
  • 2
  • 3

我们运行程序看一下效果图:

点击“搜索蓝牙设备”按钮,就会搜索到另一台手机的蓝牙信息,我们点击条目,另一台手机会出现如下变化:

弹出Toast,此时证明我们的蓝牙数据已经传输过来了。

最新文章

  1. springmvc和struts2的差别
  2. Android Handler机制(二)---MessageQueue源码解析
  3. 【开源项目SugarSite】ASP.NET MVC+ Layui+ SqlSugar+RestSharp项目讲解
  4. jquery笔记(仅供个人参考)
  5. Java Socket常见异常处理 和 网络编程需要注意的问题
  6. android用shape给linearLayout设置边框,怎样只保留底部或顶部的边框,把其它三个方向的边框去掉呢?
  7. 深入解析字符串的比较方法:“==”操作符;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
  8. 浅谈对JIT编译器的理解。
  9. 浅析 JavaScript 组件编写
  10. Leetcode题解(二)
  11. 微信跳一跳辅助自动跳Python
  12. SqlSever数据库实践周
  13. JavaScript实现接口的三种经典方式
  14. ng跳转映射,被阿里云的云盾拦截,提示备案问题分析
  15. Javabean介绍
  16. 防范 SQL 注入攻击
  17. CS、IP和PC寄存器
  18. ajax 获取服务器返回的XML字符串
  19. JsonDataObjects 简单实用
  20. python 判断字符串是字母 数字 大小写还是空格

热门文章

  1. CSS滚动插件
  2. xcode6没有prefix.pch预编译文件解决办法
  3. 菜鸟之路——机器学习之BP神经网络个人理解及Python实现
  4. 贪吃蛇—C—基于easyx图形库(上):基本控制函数实现 画图程序
  5. 小谈Bing桌面、Bing助手的现状与发展
  6. [Python]Pandas简单入门(转)
  7. django学习——通过get_FOO_display 查找模型中的choice值
  8. python斐波那契数列复杂度
  9. POJ 2635 The Embarrassed Cryptographer (千进制,素数筛,同余定理)
  10. datatable导出到Word / Excel / PDF / HTML .NET