前言
14年时候做过一个可穿戴设备,对传统的蓝牙了解过一点,但是当我这次看android.bluetooth的官方文档的时候明白了,作为一个安卓程序员,关注安卓的发展;作为IT人员,关注科技发展的重要性
虽然当时也听说过BLE的蓝牙,但是可能是由于各厂商不同,所以也没有一个统一的文档,近些年穿戴设备越来越火,可能就是因为蓝牙的发展,
所以现在面对我的有传统蓝牙和低功耗蓝牙(ble),对低功耗蓝牙的介绍和使用会在以后更新,这一次先用传统的蓝牙文档吧
文档介绍
蓝牙可以使用无线的方式让两个不同的设备之间进行数据的传输.
BluetoothAdapter类:
代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。
- getDefaultAdapter():得到本地蓝牙适配器
- getBondedDevices():返回BluetoothDevice对象,里面包括与本机蓝牙所有绑定的远程蓝牙信息
- getName():获取蓝牙设备Name
- disable():关闭蓝牙(是关闭蓝牙而不是关闭此连接)
- enable():打开蓝牙
- isEnabled():判断蓝牙是否已启用并准备使用
- getAddress():得到蓝牙的MAC地址
- getRemoteDevice(byte[] address):以给定的MAC地址去创建一个 BluetoothDevice 类实例(代表远程蓝牙实例)。即使该蓝牙地址不可见,也会产生一个BluetoothDevice 类实例。
BluetoothDevice类:
代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。
- createRfcommSocketToServiceRecord(UUID uuid):由UUID得到待连接的BluetoothSocket对象,准备建立通道.UUID就是蓝牙设备串口号,具体UUID介绍请百度.
- getAddress():得到蓝牙的MAC地址
- getName():获取蓝牙设备Name
BluetoothSocket类:
代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。
- close():关闭通道,断开连接
- connect():使待连接的通道连接上
有了这些,建立连接就很简单了,
- 先创建一个空的BluetoothAdapter对象,mBluetoothAdapter.getDefaultAdapter()拿到本机蓝牙设备适配器
- mBluetoothAdapter.isEnabled()判断本机蓝牙是否已启用并准备使用,若没开启则startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));;若开启则继续
- mBluetoothAdapter.getBondedDevices()拿到与本机蓝牙所有绑定的远程蓝牙信息
- 用远程蓝牙信息(BluetoothDevice)调用getAddress()方法,获取远程蓝牙设备的MAC地址
- 再由这个地址调用getRemoteDevice(byte[] address)返回一个BluetoothDevice对象,就拿到远程设备实例.至此我们获得了远程的设备地址,接下来去连接他
- mBluetoothDevice.createRfcommSocketToServiceRecord(UUID);这个方法返回了BluetoothSocket对象,那么我们就由本机实例得到了UUID这个通道下的远程设备的Bluetoothsocket连接
- mBluetoothsocket.connect();
- ……
- mBluetoothsocket.close();
总结一下:类比一下socket连接,这里的mac地址呢,就类似于Ip地址,而UUID则类似于端口号,这样想就容易理解的多.
最后贴一下蓝牙部分的代码片段
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//获得本设备的蓝牙适配器实例
...
...
try {
if (mBluetoothAdapter == null) {
//做一个提示
} else if (mBluetoothAdapter.isEnabled()) {
String getName = mBluetoothAdapter.getName();//获取蓝牙设备Name
pairedDevices = mBluetoothAdapter.getBondedDevices();//获取与本机蓝牙所有绑定的远程蓝牙信息
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to
// show in a ListView
getName = device.getName() + "#" + device.getAddress();//获取蓝牙设备的硬件地址(MAC地址)
mpairedDeviceList.add(getName);
}
} else {
//做打开蓝牙的一个跳转
}
} catch (Exception e) {
}
public static int connBluetooth(BaseActivity v, String temString, BluetoothAdapter mBluetoothAdapter) {
mBluetoothSocket = ((ApplicationData) v.getApplication()).getSocket();
if (mBluetoothSocket != null) {
try {
mBluetoothSocket.close();
} catch (Exception e) {
} finally {
((ApplicationData) v.getApplication()).setSocket(null);
return 0;
}
}
temString = temString.substring(temString.length() - 17);
try {
//以给定的MAC地址去创建一个 BluetoothDevice 类实例(代表远程蓝牙实例)。即使该蓝牙地址不可见,也会产生一个BluetoothDevice 类实例。
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(temString);
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(SPP_UUID);
mBluetoothSocket.connect();
((ApplicationData) v.getApplication()).setSocket(mBluetoothSocket);
return 1;
} catch (Exception e) {
return 0;
}
}
可以看到,这里我把mBluetoothSocket对象设置成了全局变量,有两个原因,一是因为蓝牙打印模版很多,要在每个页面都获取这个BluetoothSocket,二是监听与打印机是否连接需要用他作为反馈.
public class ApplicationData extends Application {
private BluetoothSocket socket; //保存蓝牙通道
@Override
public void onCreate() {
super.onCreate();
socket = null;
setSocket(socket);
}
public BluetoothSocket getSocket() {
return socket;
}
public void setSocket(BluetoothSocket socket) {
this.socket = socket;
}
}
上面这是全局变量的保存,记着注册记着注册注册!
全局变量的设置还有一个考虑就是面对一些突发状况,和难处理的另类操作,和程序变为后台等等,这里我面要设置一个广播来随时监听我们的连接状况.下面就不单独介绍常量值的意义了,代码简单易懂.
/**
* Created by Qit
* 2017/8/8 0008.
*/
public class BluetoothReceiver extends BroadcastReceiver {
BluetoothSocket bluetoothSocket;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
bluetoothSocket = ((ApplicationData) context.getApplicationContext()).getSocket();
//Toast.makeText(context, "蓝牙状态改变广播", Toast.LENGTH_LONG).show();
Button btn_conn = ((BaseActivity) context).$(R.id.btn_conn);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Toast.makeText(context, device.getName() + " 设备已发现", Toast.LENGTH_LONG).show();
} else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
Toast.makeText(context, device.getName() + "已连接", Toast.LENGTH_LONG).show();
btn_conn.setText("已连接");
} else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
Toast.makeText(context, device.getName() + "正在断开蓝牙连接。。。", Toast.LENGTH_LONG).show();
} else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
Toast.makeText(context, device.getName() + "蓝牙连接已断开", Toast.LENGTH_LONG).show();
if (!((ApplicationData) context.getApplicationContext()).getSocket().equals(null)) {
((ApplicationData) context.getApplicationContext()).setSocket(null);
}
btn_conn.setText("未连接");
} else if (action.equals(BluetoothAdapter.STATE_OFF)) {
Toast.makeText(context, "蓝牙已关闭", Toast.LENGTH_LONG).show();
} else if (action.equals(BluetoothAdapter.STATE_ON)) {
Toast.makeText(context, "蓝牙打开", Toast.LENGTH_LONG).show();
}
}
}
比如打印机断电,那么蓝牙通道会关闭,此时要及时反映这个状况,可将APP内的按钮设为未连接状态和等等等…
至此蓝牙连接基本结束了,有什么没考虑到的请留言我,谢谢
蓝牙连接了,下面介绍使用ESC/POS指令集来设置打印机格式