Android 普通蓝牙学习
需要的权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
类
蓝牙有关的所有的类如下:
普通蓝牙用到的几个关键的类:
BluetoothAdapter 蓝牙适配器
Represents the local device Bluetooth adapter. The BluetoothAdapter lets you perform fundamental Bluetooth tasks, such as initiate device discovery,
query a list of bonded (paired) devices, instantiate a BluetoothDevice using a known MAC address, and create a BluetoothServerSocket to listen for
connection requests from other devices, and start a scan for Bluetooth LE devices.
根据官方文档的说明,BluetoothAdapter可以执行基本的蓝牙任务,比如启动设备发现,查询已配对的蓝牙列表,使用已知的地址实例化一个BluetoothDevice,创建一个BluetoothServerSocket
监听链接请求等。
BluetoothDevice 蓝牙设备
Represents a remote Bluetooth device. A BluetoothDevice lets you create a connection with the respective device or query information about it,
such as the name, address, class, and bonding state.
代表一个远程蓝牙设备。BluetoothDevice允许创建一个连接的设备或查询相关信息,如名称、地址、阶级和配对的状态。
BluetoothSocket
The interface for Bluetooth Sockets is similar to that of TCP sockets: Socket and ServerSocket.
顾名思义蓝牙连接
BluetoothServerSocket
The interface for Bluetooth Sockets is similar to that of TCP sockets: Socket and ServerSocket.
蓝牙服务链接,后两者都是和TCP端口类似的一个socket。
BluetoothAdapter
首先打开蓝牙开始搜索等;
主要用到的几个方法:
getDefaultAdapter() 获取一个适配器对象
getName() 获取本地蓝牙名称
getAddress() 获取本地蓝牙的地址
enable() 打开本地蓝牙(低版本中不会提示用户)
isEnabled() 判断蓝牙是否已经打开
disable() 关闭本地蓝牙
startDiscovery() 开始搜索(发现)
cancelDiscovery() 取消设备搜索(发现)
isDiscovering() 返回当前是否是在搜索设备
listenUsingRfcommWithServiceRecord(String name, UUID uuid) 创建一个安全的BluetoothServerSocket
打开蓝牙
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//打开蓝牙 方法一
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();
}
//方法二 推荐
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler, REQUEST_ENABLE);
开始搜索设备
调用startDiscovery()开始搜索设备,但是仅仅调用此方法是没有任何作用的,startDiscovery()是异步调用,立即返回,需要注册一个广播接收者
来接受搜索的结果。整个搜索过程持续12秒。
//注册
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, intentFilter);
//广播接收者
BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//找到设备
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d("MainActivity", "搜索到设备");
//在列表中显示搜索出的设备
adapter.add("name : " + device.getName() + "\n address : " + device.getAddress());
bluetoothDevices.add(device);
}
//搜索完成
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
Log.d("MainActivity", "搜索结束");
} else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Log.d("MainActivity", "开始搜索");
}
}
};
连接设备
建立连接,Android sdk支持的蓝牙连接是通过BluetoothSocket建立连接,服务器端(BluetoothServerSocket)和客户端(BluetoothSocket)需指定同样的UUID,才能建立连接,因为建立连接的方法会阻塞线程,所以服务器端和客户端都应启动新线程连接。
UUID的格式如下:
String uuid = "a60f35f0-b93a-11de-8a39-08002009c666";
建立服务器端代码如下:
首先建立服务器,获取BluetoothServerSocket对象,通过BluetoothAdapter的listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)方法和listenUsingRfcommWithServiceRecord(String name, UUID uuid)方法,其中前者是不安全的链接,后者是安全的链接。
然后使用BluetoothServerSocket.accept()方法接受客户端连接,当连接成功返回一个BluetoothSocket对象。
private class ServiceThread extends Thread {
@Override
public void run() {
BluetoothServerSocket serverSocket = null;
try {
serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("my_test_lianjie", UUID.fromString(uuid));
Log.d("ServiceThread", "建立服务器成功");
} catch (IOException e) {
e.printStackTrace();
Log.d("ServiceThread", "建立服务器失败");
}
try {
socket = serverSocket.accept();
Log.d("ServiceThread", "客户端连接成功");
new ReadThread().start();
} catch (IOException e) {
e.printStackTrace();
Log.d("ServiceThread", "客户端连接失败");
}
}
}
建立客户端链接代码如下:
这里需要注意的是要对首先检测设备是否进行了配对,只有首先进行配对才能进行连接。蓝牙配对是通过反射的方法调用BluetoothDevice.creMethod()方法。
建立连接首先获取BluetoothSocket对象,调用BluetoothDevice的createInsecureRfcommSocketToServiceRecord(UUID uuid)或者createRfcommSocketToServiceRecord(UUID uuid)方法,其中前者是不安全的链接,后者是安全的链接。
然后调用BluetoothSocket.connect()方法进行连接。
private class ConnectThread extends Thread {
BluetoothDevice device;
public ConnectThread(BluetoothDevice device) {
this.device = device;
}
@Override
public void run() {
try {
socket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
} catch (IOException e) {
e.printStackTrace();
}
if (device.getBondState() == BluetoothDevice.BOND_BONDED) { //已配对设备 直接进行链接
connectSocket();
} else if (device.getBondState() == BluetoothDevice.BOND_NONE) { //未配对设备 先配对再链接
Method creMethod = null;
try {
creMethod = BluetoothDevice.class.getMethod("createBond");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Log.e("TAG", "开始配对");
try {
creMethod.invoke(device);
} catch (IllegalAccessException e) {
e.printStackTrace();
Log.e("TAG", "配对失败");
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
private void connectSocket() {
try {
socket.connect();
Log.e("TAG", "连接成功");
new ReadThread().start();
} catch (IOException e) {
e.printStackTrace();
Log.e("TAG", "连接失败");
}
}
public void cancel() {
try {
socket.close();
socket = null;
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
客户端建立连接的方式有很多种,这里使用的是先获得一个socket然后再检查是否需要进行配对,再建立连接。
还可以通过反射的方法,通过端口进行连接。
进行通讯
蓝牙通讯是通过流的方式进行的:
OutputStream outS = socket.getOutputStream();
InputStream inS = socket.getInputStream();
发送的方法如:
OutputStream os = null;
try {
os = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
os.write("你好".getBytes());
Log.d("MainActivity", "发送成功");
} catch (IOException e) {
e.printStackTrace();
Log.d("MainActivity", "发送失败");
}
接受的方法如:
private class ReadThread extends Thread {
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
try {
mmInStream = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
try {
// Read from the InputStream
if ((bytes = mmInStream.read(buffer)) > 0) {
byte[] buf_data = new byte[bytes];
for (int i = 0; i < bytes; i++) {
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
Log.d("ReadThread", s);
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
}
至此,普通蓝牙的基本发现、连接、通讯功能就完成了,当然还有许多需要完善的地方。