一、蓝牙发展历程
蓝牙(Bluetooth):是一种无线技术标准,可实现设备间短距离数据交换。 蓝牙可以以一定的周期发送广播,手机端接收到广播后,解析广播包,可做设备识别、配对,事件通知以及指令控制等。低精度定位根据设备的信号强度,可以估算出大概方位和距离。
蓝牙发展至今经历了多个版本的更新,其中,将1.x~3.0之间的版本称之为经典蓝牙,4.x开始的蓝牙称之为低功耗蓝牙,也就是蓝牙BLE。
根据应用、协议类型等,可以对蓝牙进行以下分类:
二、经典蓝牙API
1、BluetoothAdapter:代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作, 例如 : 启动设备发现,获取已配对设备,通过mac蓝牙地址获取蓝牙设备等。
- enable():打开蓝牙,需要 BLUETOOTH_ADMIN权限。
- disable():关闭蓝牙,需要 BLUETOOTH_ADMIN权限。
- checkBluetoothAddress(String address):验证蓝牙设备MAC地址是否有效。
- getAddress():获取本地蓝牙适配器的硬件地址(MAC地址)
- getBondedDevices():获取与本机蓝牙所有绑定的远程蓝牙信息。
- getName():获取本地蓝牙适配器的蓝牙名称。
- setName(String name):设置本地蓝牙适配器的蓝牙名称。
- isEnabled():判断当前蓝牙适配器是否打开。
- isDiscovering():判断蓝牙适配器是否正在处于扫描过程中。
- startDiscovery():开始扫描周边蓝牙设备。
- cancelDiscovery():取消蓝牙搜索操作。
- getScanMode():获取本地蓝牙适配器的当前蓝牙扫描模式。
蓝牙扫描模式:
SCAN_MODE_NONE: 该设备不能扫描以及被扫描。
SCAN_MODE_CONNECTABLE:该设备可以扫描其他蓝牙设备。
SCAN_MODE_CONNECTABLE_DISCOVERABLE:该设备既可以扫描其他设备,也可以被其他设备扫描发现。
- getState():获取本地蓝牙适配器的当前状态。
蓝牙适配器状态:
STATE_OFF:表示本地蓝牙适配器已关闭。
STATE_TURNING_ON:表示本地蓝牙适配器正在打开。
STATE_ON:表示本地蓝牙适配器已开启,并可供使用。
STATE_TURNING_OFF:表示本地蓝牙适配器正在关闭。
- getRemoteDevice(String address):获取给定蓝牙硬件地址的BluetoothDevice对象。
如果address中的MAC无效无效,将抛出IllegalArgumentException异常。
- listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid):创建不安全的蓝牙服务套接字。
- listenUsingRfcommWithServiceRecord(String name, UUID uuid):创建一个正在监听的安全的带有服务记录的无线射频通信(RFCOMM)蓝牙端口。
2、BluetoothDevice:代表了一个远程的蓝牙设备, 通过这个类可以查询远程设备的物理地址, 名称, 连接状态等信息。这个类实际上只是一个蓝牙硬件地址的简单包装,这个类的对象是不可变的。对这个类的操作, 会执行在远程蓝牙设备的硬件上。
- getName():获取远程蓝牙设备的蓝牙名称。
- getAddress():获取远程蓝牙设备的硬件地址。
- createBond():开始与远程蓝牙设备的绑定过程。
- getBondState():获取远程蓝牙设备的绑定状态。
蓝牙绑定状态:
BOND_NONE:远程设备未绑定。
BOND_BONDING:正在与远程设备进行绑定。
BOND_BONDED:远程设备已绑定。
- createInsecureRfcommSocketToServiceRecord(UUID uuid):创建不安全的蓝牙套接字。
- createRfcommSocketToServiceRecord(UUID uuid):创建安全的蓝牙套接字。
3、BluetoothServerSocket:侦听蓝牙服务套接字。使用BluetoothServerSocket可以创建一个监听服务端口, 使用accept方法阻塞, 当该方法监测到连接的时候, 就会返回一个BluetoothSocket对象来管理这个连接。BluetoothServerSocket是线程安全的,close方法始终会立即中止正在进行的操作并关闭蓝牙服务套接字。需要BLUETOOTH权限。
- accept():阻塞直到建立连接,成功连接时连接的BluetoothSocket对象。
- accept(int timeout):阻塞直到建立连接或超时,成功连接时连接的BluetoothSocket对象。
- close():关闭该监听服务端口,并释放所有关联的资源。
4、BluetoothSocket:蓝牙套接口。在服务器端,使用BluetoothServerSocket创建侦听服务器套接字。当连接被BluetoothServerSocket接受时,它将返回一个新的BluetoothSocket来管理连接。 在客户端,使用单个BluetoothSocket来启动连接并管理连接。BluetoothSocket是线程安全的,close方法始终会立即中止正在进行的操作并关闭套接字。需要BLUETOOTH权限。
- connect():尝试连接到远程蓝牙服务器。
- isConnected():获取此套接字的连接状态,即是否与远程蓝牙服务连接。
- getRemoteDevice():获取此套接字连接的远程蓝牙设备。
- getInputStream():获取与此套接字关联的输入流。
即使套接字尚未连接,输入流也会返回,但对该流的操作将抛出IOException异常,直到关联的套接字连接。
- getOutputStream():获取与此套接字关联的输出流。
即使套接字尚未连接,输出流也会返回,但对该流的操作将抛出IOException异常,直到关联的套接字连接。
- close():关闭此流并释放与其关联的所有系统资源。如果流已经关闭,则调用此方法不起作用。
三、经典蓝牙开发
1、在工程清单文件AndroidManifest.xml中添加权限:
<!--如果使用了BLUETOOTH_ADMIN权限,那么必须使用BLUETOOTH权限-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--android6.0后需要搜索周边蓝牙设备,需要添加以下两个权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--要求设备硬件必须支持蓝牙-->
<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
2、获取本地蓝牙适配器
BluetoothAdapter有两种方式获取,方式二要求Android4.3以上才可以用,建议使用方式一,比较通用。
//第一种方式
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//第二种方式
BluetoothManager manager = (BluetoothManager) Context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = manager.getAdapter();
3、打开蓝牙
方式一:通过Intent来向用户弹框请求打开蓝牙,可以重写onActivityResult来监听打开蓝牙的请求结果.
public void openBluetooth(){
if (mBluetoothAdapter==null) {
//自定义方法,用来往TextView上添加提示信息
showTip("当前设备不支持蓝牙功能!");
return;
}
if (mBluetoothAdapter.isEnabled()) {
showTip("蓝牙已打开");
return;
}
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,GlobalDef.REQ_CODE_OPEN_BT);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==GlobalDef.REQ_CODE_OPEN_BT) {
if (resultCode == Activity.RESULT_OK) {
showTip("蓝牙打开成功");
} else {
showTip("蓝牙打开失败");
}
}
}
方式二:通过enable方法静默打开蓝牙,无需用户同意(部分Android系统使用该方法依然会弹框提示,向用户请求打开蓝牙)
mBluetoothAdapter.enable();
4、关闭蓝牙
关闭蓝牙,无需用户同意(部分Android系统使用该方法依然会弹框提示)
mBluetoothAdapter.disable();
5、允许蓝牙可被发现
如果开发的外围设备如音箱,需要被中心设备发现扫描到,需要该功能。有两种实现方式:
方式一:通过Intent方式向用户请求允许蓝牙被搜索。如果蓝牙没有开启,用户点击确定后,会首先开启蓝牙,继而设置蓝牙能被扫描。
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//设置蓝牙可见性的时间,默认持续时间为120秒,每个请求的最长持续时间上限为300秒
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
startActivity(intent);
方式二:通过反射的方式来设置蓝牙可见性,且不会出现弹框,如果蓝牙没有开启,通过此方式并不会直接打开蓝牙。
/**
* 设置蓝牙可见
* @param adapter
* @param timeout 超时为0时,永久可见
*/
public static void setDiscoverableTimeout(BluetoothAdapter adapter, int timeout) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
try {
Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
setDiscover