BlueTooth
根据官方DOC翻译
(本人英语4级没过,看不懂请自行脑补)
Bluetooth API操作流程:
- 搜索其他蓝牙设备
- 查询本地匹配器已经匹配的蓝牙设备
- 建立RFCOMM通道
- 通过Service发现并连接其他设备
- 与其他蓝牙设备进行数据交互
- 管理多个连接
Permission:
- android.permission.BLUETOOTH:Allows applications to connect to paired bluetooth devices
- android.permission.BLUETOOTH_ADMIN:Allows applications to discover and pair bluetooth devices
Setting Up Bluetooth:
确保设备支持蓝牙模块,并已开启
- 获取BluetoothAdapter。整个系统只有一个BluetoothAdapter。如果返回null表示设备不支持蓝牙。
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 设备是否支持蓝牙
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.not_support, Toast.LENGTH_SHORT).show();
}
- 开启蓝牙:如果没用开启蓝牙,会弹出系统对话框,请求用户开启蓝牙功能。如果开启成功,则返回:Activity.RESULT_OK,否则返回:Activity.RESULT_CANCELED。
- 监听状态:你可以通过监听BluetoothAdapter. ACTION_STATE_CHANGED广播获得蓝牙状态变化信息。广播包含以下额外字段: EXTRA_STATE和EXTRA_PREVIOUS_STATE。常见值包括:STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF和STATE_OFF。
Finding Devices:
使用BluetoothAdapter,你可以找到远程蓝牙设备。通过查找设备,或查询配对(绑定)的设备列表。查找设备会搜索区域内的蓝牙设备,如果该设备设定为可被发现,则会返回一些信息,通过该信息则可连接设备。当首次建立连接,该设备信息会被保存并可通过API获得,使用MAC地址不需要重新搜索设备(假设设备在可连接范围内)。
- 配对(Pair): 意味着两个设备都知道彼此的存在,有一个共同的链路密钥,可用于进行认证,并且能够建立与彼此的加密连接的。
- 连接(Connect):该装置当前共享一个RFCOMM信道,并能够相互传送数据。Android Bluetooth API's要求设备配对前需要先建立RFCOMM连接(当你通过API建立加密连接配对会自动执行)。
Querying paired devices:
通过getBondedDevices()可返回一组蓝牙配对清单(BluetoothDevice)。
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { mDeviceInfoList = new ArrayList<HashMap<String, Object>>(); for (BluetoothDevice device : pairedDevices) { mDeviceInfoList.add(device.getName() + "\n" + device.getAddress()); } }
Discovering devices:
通过startDiscovery()可搜索设备,此方法会立即返回Boolean提示是否成功开始搜索。这是一个异步操作,搜索时间大约12秒然后会返回发现的蓝牙设备信息。对于每个搜索到的设备,系统会广播一个ACTION_FOUND Intent,装载的信息包括:EXTRA_DEVICE和EXTRA_CLASS(包含BluetoothDevice和BluetoothClass)。所以你需要注册BroadcastReceiver接收ACTION_FOUND Intent。
// 搜索到蓝牙设备时接收广播提示信息 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 搜索完成时接收广播提示信息 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter); private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 如果查找到设备 BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED .equals(action)) { // 查找完成 } } }; protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (mBluetoothAdapter != null) { // 停止搜索设备 mBluetoothAdapter.cancelDiscovery(); } // 注销广播监听 this.unregisterReceiver(mReceiver); }
需要注意的是,搜索蓝牙设备非常消耗资源,所以一旦找到对应设备,应该使用cancelDiscovery()停止搜索。如果你已有该设备的连接再执行搜索会节约带宽。
如果你想使本地设备能被其他设备检测到,调用startActivityForResult(Intent,INT)和ACTION_REQUEST_DISCOVERABLE action Intent.。这将发出一个请求,以使通过系统设置发现模式(无需停止应用程序)。默认可见时间为120秒,也可以能过EXTRA_DISCOVERABLE_DURATION Intent extra来修改可见时间(最大值为3600秒,0表示设备始终可见)。系统会弹出对话框提示用户设置可见,并调用onActivityResult()返回结果,如果用户选择确定,则返回时间,如果用户选择否或者出现错误,则返回RESULT_CANCELED。如果未开启蓝牙,使设备可见会自动开启。如果你希望监听到设备可见状态的改变,可以注册BroadcastReceiver ACTION_SCAN_MODE_CHANGED Intent,包含:EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE。
// 设置设备对外可见,持续30秒 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivityForResult(intent, REQUEST_DISCOVERABLE);
Connectting Devices:
服务器端创建Server Socket,客户端使用服务器端的MAC地址创建连接,当服务器端与与客户端连接时,双方的BluetoothSocket会在同一RFCOMM通道中。此时双方都各自拥有input和output stream,并能实现数据传输。服务器端和客户端分别以不同的方式获得BluetoothSocket。服务器端:当传入连接Accepted时,接收到BluetoothSocket;
客户端:当客户端打开RFCOMM通道时,接收到BluetoothSocket。
有一种实现方法是每台设备均准备作为服务器,均打开Server Socket并监听连接。然后其它设备则以客户端的形式创建连接。
注意:如果两个设备先前未配对,Android框架将发送配对请求通知对话框给用户,应用程序不需要关注的设备是否被配对。您的RFCOMM连接尝试将阻塞,直到用户成功配对,或者如果用户拒绝配对,或者如果配对失败或者超时就会失败。
Connecting as a server:
当你尝试连接两台设备,其中一台需要充当服务器端打开并持有BluetoothServerSocket。Server Socket目的是监听来自客户端的连接请求,当客户端的连接请求被通过,服务器端将提供BluetoothSocket。一旦取得BluetoothSocket,BluetoothServerSocket应该被移除,除非你打算接受更多连接。
设置Server Socket和接收连接请求的基本流程:
- 使用listenUsingRfcommWithServiceRecord(String, UUID)获得BluetoothServerSocket。String是服务器端的名称。UUID它是用来唯一标识应用程序的蓝牙服务。如果与蓝牙串口(Bluetooth serial board)连接可以尝试使用标准的SPP UUID:00001101-0000-1000-8000-00805F9B34FB。但是如果连接的是Android Peer,你需要生成自己的UUID。
- 通过accept()开始监听连接请求。这是一个阻塞调用,当任意连接被同意或者发生异常时则会退出。只有当客户端发送连接请求,并且请求数据中的UUID与Server Socket的UUID才能被同意。如果连接成功,则返回BluetoothSocket。
- 除非你打算接受其他的连接,否则连接成功后,调用close()。这将释放Server Socket及其所有资源,但不会关闭accept()返回的BluetoothSocket。RFCOMM只允许每个通道一个连接的客户端的时间,因此,在大多数情况下,在BluetoothServerSocket通过连接请求后立即调用close()。
- Accept()不能运行于主线程,应该创建子线程执行些方法,另外BluetoothServerSocket和BluetoothSocket所有方法都是线程安全的。
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; private String mSocketType; public AcceptThread(boolean secure) { BluetoothServerSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; // 创建一个新的server socket监听,secure表示是否使用加密方式 try { if (secure) { tmp = mAdapter.listenUsingRfcommWithServiceRecord( NAME_SECURE, MY_UUID_SECURE); } else { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord( NAME_INSECURE, MY_UUID_INSECURE); } } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // 保持监听,直到Socket返回,或者中止 while (true) { try { // 这是一个阻塞方法,只会返回成功,否则抛出异常 socket = mmServerSocket.accept(); } catch (IOException e) { break; } // 如果连接成功 if (socket != null) { // 新创建一个线程使用Socket manageConnectedSocket (socket); mmServerSocket.close(); break; } } } public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }
请注意,当accept()返回的BluetoothSocket,socket已经连接,所以客户端不需要调用connect()。manageConnectedSocket()用于启动线程传输数据。你可能还需要在线程里提供public方法用于关闭BluetoothSocket。
Connecting as a client:
客户端连接服务器端首先要从服务器端获得BluetoothDevice(参考Finding Devices),然后从BluetoothDevice中获得BluetoothSocket并创建连接。基本流程如下:
- 通过createRfcommSocketToServiceRecord(UUID)从BluetoothDevice中获得BluetoothSocket。UUID必须与服务器端的UUID一致。
- 通过connect()启动连接。connect()连接服务器时,服务器端会匹配UUID,如果匹配成功,服务器会同意连接请求并提供RFCOMM能道,此时connect()会返回。Connect()是阻塞方法,所以需要创建子线程执行,如果连接出现任何问题或者超时(12秒),将会抛出错误。需要注意的是,调用connect()时,确保已经停止搜索(cancelDiscovery()),否则性能会明显降低。也可以使用isDiscovering()检查是否正在搜索中。
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device, boolean secure) { mmDevice = device; BluetoothSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; // 通过BluetoothDevel和UUID获得BluetoothSocket try { if (secure) { // 使用加密方式 tmp = device .createRfcommSocketToServiceRecord(MY_UUID_SECURE); } else { // 不使用加密方式,需要API Level 10支持 tmp = device .createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE); } } catch (IOException e) { } mmSocket = tmp; } public void run() { // 停止搜索,搜索设备会占用大量资源 mAdapter.cancelDiscovery(); // 创建Bluetooth连接 try { // connect阻塞方法,只会返回成功, 否则抛出异常 mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { } return; } // 完成后重置线程 synchronized (BluetoothChatService.this) { mConnectThread = null; } // 创建一个独立的线程使用Sokcet manageConnectedSocket(mmSocket); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
当使用完BluetoothSocket,调用close()关闭连接释放资源。
Managing a Connection:
当两(多)台设备连接成功后,两台设备都持有BluetoothSocket,这时可以进行数据交互了。使用BluetoothSocket传输数据流程:
- 通过Socket使用InputStream和OutputStream数据。
- 通过read(byte[])和write(byte[])读写数据流。需要注意的是,你要为读写流创建线程,因为read(byte[])和write(byte[])是阻塞方法,read(byte[])会一直阻塞直到所有数据被读出;write(byte[])通常不会阻塞,但如果远和设备没有迅速调用read(byte[])又或者缓冲区已经满,则会造成阻塞。所以你的线程run主要用于读取InputStream。另外提供public方法,以启动写入输出流。
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // 获取输入和输出流,使用临时对象,因为成员流是final的 try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // 当连接成功后,一直监听InputStream while (true) { try { // 从InputStream读取数据 bytes = mmInStream.read(buffer); // 发送获得的数据至UI Activity mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); } catch (IOException e) { break; } } } // 写入数据并发送 public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { } } // 关闭连接 public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
Working with Profiles:
从Android 3.0开始,Bluetooth API包括了对Bluetooth Profiles的支持。Bluetooth Profile是一种基于设备间的蓝牙通信无线协议规范。其中一个例子是Hands-Free profile(免提模式),手机连接无线耳机,两个设备都必须要支持Hands-Free profile。你可以通过实现BluetoothProfile接口编写自己的类来支持特定的Bluetooth profiles。
- Headset:Headset profile提供对手机使用蓝牙耳机的支持。Android提供BluetoothHeadset类,通过进程通讯(IPC)代理控制蓝牙耳机服务。这里包括蓝牙耳机和免提(v1.5)模式。BluetoothHeadset包括支持AT命令。
- A2DP:The Advanced Audio Distribution Profile (A2DP高级音频传输模式)定义了多高质量的音频可以通过蓝牙传输。Android提供BluetoothA2dp类,通过进程通讯(IPC)代理控制蓝牙A2DP服务。
- Health Device:Android 4.0 (API level 14) 支持Bluetooth Health Device Profile (HDP)。它使你能够创建应用,通过蓝牙与Health Device通讯。例如:heart-rate monitors(心脏速率监视器),blood meters(血压计),thermometers(体温计),scales(身体均衡器),等等。
基本步骤如下:
- 获得Adapter(参考Setting Up Bluetooth)
- 通过方法getProfileProxy()建立与模式关联的理对象的连接。在下面的例子中,配置文件代理对象是BluetoothHeadset的一个实例。
- 设置BluetoothProfile.ServiceListener用于监听服务器端连接或断开连接的事件,并通知BluetoothProfile IPC。
- 在方法onServiceConnected()中获得profile proxy的handle对象。
- 一旦获得profile prox对象,你可以用它来监测连接状态,并进行其它相关的操作。
例如,以下代码显示了如何连接到一个BluetoothHeadset代理对象,这样就可以控制Headset profile:
BluetoothHeadset mBluetoothHeadset; // Get the default adapter BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // Establish connection to the proxy. mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET); private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = (BluetoothHeadset) proxy; } } public void onServiceDisconnected(int profile) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = null; } } }; // ... call functions on mBluetoothHeadset // Close proxy connection after use. mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
Vendor-specific AT commands:
从Android 3.0开始应用程序可以通过注册来接收来自耳机的pre-defined vendor-specific AT commands系统广播(例如:Plantronics +XEVENT command),例如应用程序可以通过广播接收所连接设备的电量水平,并通知用户。创建广播接收器并通过ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent处理来自耳机的vendor-specific AT commands。
Health Device Profile:
相关推荐
Bluetooth Core v5.4 Bluetooth Core v5.4是Bluetooth SIG(Bluetooth Special Interest Group)发布的一份专有的核心规范,用于定义创建可互操作的蓝牙设备所需的技术。该规范的版本号为v5.4,发布日期为2023年1月...
Bluetooth? Framework is a VCL and ActiveX components library, which allows you to add Bluetooth?, IrDA?, Serial and ActiveSync? support into your applications. The Bluetooth? Framework is not an end...
Java Bluetooth API.pdf文档可能包含了这些概念的详细解释、示例代码以及API参考,是学习和开发蓝牙应用的重要资源。建议仔细阅读该文档,结合实践来提升蓝牙编程能力。通过熟练掌握Java蓝牙API,你可以开发出各种...
在"ros_gps2bluetooth"项目中,其核心功能是实现从智能手机获取GPS数据并通过蓝牙将其传输到计算机上。这在机器人系统中非常有用,因为手机GPS模块通常比嵌入式计算机或机器人平台上的GPS接收器更便宜且易于获取。 ...
蓝牙低功耗(Bluetooth Low Energy, 简称BLE或Bluetooth LE)是一种现代通信技术,广泛应用于移动设备,如iOS和Android智能手机和平板电脑。在本文中,我们将深入探讨BLE在Unity3D环境中的应用,以及如何在iOS和...
该文档是一份关于Unity Bluetooth LE Plugin for Android的技术文档,主要针对的是在Unity中开发Android低功耗蓝牙功能。文档中介绍和解释了如何使用这个插件,提供了一些版本更新的详细信息,以及设置和安装插件的...
A radical new departure from conventional Bluetooth technology, Bluetooth Low Energy (BLE) will enable a whole new generation of wireless applications in industries ranging from healthcare to ...
- **Android Bluetooth框架层**:位于Java层,包含`android.bluetooth`包中的各种类,如`BluetoothAdapter`, `BluetoothDevice`, `BluetoothGatt`等,提供了开发者友好的API。 - **蓝牙应用程序**:使用Android蓝牙...
在Linux系统中,Bluetooth编程是一项重要的技能,尤其对于开发物联网(IoT)设备或需要无线通信的项目至关重要。本文将深入探讨"实战Linux Bluetooth编程"的主题,主要关注blueZ库的使用,它是一个官方支持的Linux ...
标题中的"Bluetooth_javascript_bluetooth_yearg9h_"暗示了我们将在JavaScript环境下探讨如何利用蓝牙技术进行设备交互。描述进一步证实了这个主题,说明我们将学习如何通过JavaScript来搜索、连接蓝牙设备,以及...
### Linux Bluetooth 编程介绍 #### 一、安装软件及环境配置 在开始Linux下的蓝牙编程之前,首先需要确保系统中已经安装了必要的软件。主要包括: 1. **GCC**: GCC (GNU Compiler Collection) 是用于编译C语言...
在Android系统中,Bluetooth OPP(Object Push Profile)是一种用于设备间传输小文件的协议,它允许用户方便地发送图片、联系人、日历事件等数据。这篇博客文章的附件是针对一个特定的Android设备(可能是Xiaomi设备...
Toshiba Bluetooth Stack v8.00.03(T) 补丁,Toshiba Bluetooth Stack v8.00.04(T)也可以用。 日发现东芝的蓝牙驱动软件升级到 v8.00.03(T) 版本了,新版本除了修复了一些BUG,更是增加了对蓝牙3.0的支持,建议使用...
Android Bluetooth 框架知识 Android Bluetooth 框架知识是指在 Android 系统中,关于 Bluetooth 技术的架构和实现细节。Android 4.2 和 4.3 中的 Bluetooth 框架知识是特别重要的,因为在这个版本中,Android 引入...
【Ellisys Bluetooth Analyzer】是专业级的蓝牙协议分析工具,专为开发者、测试工程师以及技术爱好者设计,用于深入理解、调试和优化蓝牙设备的性能。这款软件的强大之处在于其全面的功能,它不仅可以捕获蓝牙通信...
【VC2010 蓝牙(Bluetooth)设备查找】是关于利用Windows API进行蓝牙设备搜索和串口通信的编程实例。这个项目是专为Visual Studio 2010设计的,允许开发者通过C++语言来实现蓝牙设备的识别和通信功能。下面将详细介绍...
本文将深入探讨"windows蓝牙通信BluetoothApi接口功能说明",并结合提供的源代码文件`BlueTooth.cpp`、文档`Bluetooth.docx`以及头文件`BlueTooth.h`来阐述关键知识点。 首先,Windows Bluetooth API通常由Windows ...
在Windows操作系统中,蓝牙通信是通过一套名为Bluetooth API的接口实现的。这些API提供了与蓝牙设备交互的各种功能,包括搜索设备、建立连接、传输数据、管理服务等。本资源包含了一个文档和一个封装好的蓝牙通信...
通过`navigator.bluetooth.requestDevice()`方法,开发者可以获取到用户选择的蓝牙设备。 2. **Service Workers**:为了在没有页面活动时仍能与蓝牙设备保持连接,可能使用了Service Workers。Service Workers允许...
《C# Windows Bluetooth LE 应用开发详解——以BluetoothLEExplorer为例》 在现代物联网(IoT)领域,蓝牙低功耗(BLE, Bluetooth Low Energy)技术因其高效、低耗的特点,广泛应用于各种智能设备之间的小数据量通信。...