一、相关的蓝牙API
所有蓝牙API都在android.bluetooth
包下.下面有一些类和接口的摘要,你可能需要它们来建立蓝牙连接:
BluetoothAdapter
代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。
BluetoothDevice
代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。
BluetoothSocket
代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。
BluetoothServerSocket
代表一个开放的服务器socket,它监听接受的请求(与TCP ServerSocket类似)。为了连接两台Android设备,一个设备必须使用这个类开启一个服务器socket。当一个远程蓝牙设备开始一个和该设备的连接请求,BluetoothServerSocket将会返回一个已连接的BluetoothSocket,接受该连接。
BluetoothClass
描述一个蓝牙设备的基本特性和性能。这是一个只读的属性集合,它定义了设备的主要和次要的设备类以及它的服务。但是,它没有描述所有的蓝牙配置和设备支持的服务,它只是暗示了设备的类型。
BluetoothProfile
一个表示蓝牙配置文件的接口。一个Bluetooth profile是一个基于蓝牙的通信无线接口定义。一个例子是Hands-Free profile。更多的讨论请见Working with Profiles。
BluetoothHeadset
提供对移动手机使用的蓝牙耳机的支持。它包含了Headset and Hands-Free (v1.5)配置文件。
BluetoothA2dp
定义高品质的音频如何通过蓝牙连接从一个设备传输到另一个设备。”A2DP“是Advanced Audio Distribution Profile的缩写。
BluetoothHealth
表示一个Health Device Profile代理,它控制蓝牙服务。
BluetoothHealthCallback
一个抽象类,你可以使用它来实现BluetoothHealth的回调函数。你必须扩展这个类并实现回调函数方法来接收应用程序的注册状态改变以及蓝牙串口状态的更新。
BluetoothHealthAppConfiguration
表示一个应用程序配置,Bluetooth Health第三方应用程序注册和一个远程Bluetooth Health设备通信。
BluetoothProfile.ServiceListener
一个接口,当BluetoothProfile IPC客户端从服务器上建立连接或断开连接时,它负责通知它们(也就是,运行在特性配置的内部服务)。
二、使用蓝牙API完成建立蓝牙连接
必要四步:1.打开蓝牙;2.查找附近已配对或可用的设备;3.连接设备;4.设备间数据交换。
(1)Bluetooth Permissions
为了在应用中使用蓝牙特性,需要声明蓝牙权限:BLUETOOTH 和BLUETOOTH_ADMIN。执行任何蓝牙通信,例如请求一个连接、接受一个连接以及传输数据,必须请求BLUETOOTH 权限。
为了初始化设备查找或控制蓝牙设置,你必须请求BLUETOOTH_ADMIN权限。大多数应用需要这个权限,仅仅是为了可以发现本地蓝牙设备。这个权限授权的其他功能不应该被使用,除非该应用是一个“强大的控制器”,来通过用户请求修改蓝牙设置。注意:如果你使用BLUETOOTH_ADMIN权限,那么必须拥有BLUETOOTH权限。
//允许程序连接到已配对的蓝牙设备。
//允许程序发现和配对蓝牙设备。
(2)设置蓝牙
有的蓝牙活动都需要请求BluetoothAdapter。为了得到BluetoothAdapter,调用静态的getDefaultAdapter()方法。它返回一个BluetoothAdapter,代表设备本身的蓝牙适配器(蓝牙无线电)。一个完整的系统只有一个蓝牙适配器,而且你的应用可以使用BluetoothAdapter与它进行交互。
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
接下来,你需要保证蓝牙是开启的。调用isEnabled()来检查蓝牙最近是否是开启的。如果这个方法返回false,那么蓝牙没有开启。为了请求开启蓝牙,调用startActivityForResult()并使用ACTION_REQUEST_ENABLE方法Intent。这将发出一个请求来利用系统设置开启蓝牙(不需要停止你的应用)
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
如果开启蓝牙成功,你的activity在onActivityResult()回调函数中接受一个RESULT_OK结果代码。如果蓝牙因为一个错误(或者用户相应”否“)没有开启,那么结果代码就是RESULT_CANCELED。
(3)查找设备
使用BluetoothAdapter,你可以通过设备检测或者查询已配对的设备来找到远程蓝牙设备。设备检测是一个浏览流程,它查找附近的蓝牙可用设备,然后请求每个设备的相关信息(这有时被称为“检测”“查询”或“浏览”等)。虽然,附近的蓝牙设备仅在它目前是可被检测的状态下时才会回应发现请求。如果一个设备是可被检测的,它将通过分享一些数据来相应检测请求,例如设备名称,类,以及他的唯一的MAC地址。使用这个信息,进行检测的设备可以选择和检测到的的设备初始化一个连接。
查找已配对设备
Set pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
查找未配对设备
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Register for broadcasts when a device is discovered.
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
...
// Don't forget to unregister the ACTION_FOUND receiver.
unregisterReceiver(receiver);
}
(4)作为服务器端
当你想要连接两台设备时,一个必须通过持有一个打开的 BluetoothServerSocket 来作为服务器端。服务器socket的目的是为了监听外来的连接请求,当一个请求被接受后,提供一个连接的BluetoothSocket。当该BluetoothSocket被BluetoothServerSocket请求时,BluetoothServerSocket 可以(而且应当)被舍弃,除非你想要接收更多的连接。
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code.
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) {
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
// Closes the connect socket and causes the thread to finish.
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
(5)作为客户端
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);
}
// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
}
三、运行结果截图
四、代码仓库
https://github.com/zljdgit/MyBluetooth.git