目录
2. BluetoothAdapter(与BluetoothManager)
Android中使用的蓝牙分为两种,蓝牙2.0和BLE(蓝牙4.0及以上版本)。
蓝牙2.0有效距离为小于等于10米,传输速度最大375KB/s,连接建立时间6s。
BLE有效距离为小于等于100米,传输速度最大3MB/s,连接建立时间2s。
1. 权限
使用蓝牙需申请蓝牙权限及蓝牙管理权限;建议限制仅在支持BLE(蓝牙4.0)的设备运行;如果Android6.0蓝牙搜索不到设备需要补充定位权限。
<!--蓝牙,无需动态申请-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--蓝牙管理,无需动态申请-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--开启可被搜索到的蓝牙时需要该权限,需要动态申请-->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!--开启不可被搜索到的蓝牙时需要该权限,需要动态申请-->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!--仅在支持BLE(蓝牙4.0)的设备上运行-->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<!--如果Android6.0蓝牙搜索不到设备需要补充定位权限,需要动态申请-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2. BluetoothAdapter(与BluetoothManager)
Android提供的蓝牙模块管理工具为BluetoothAdapter(蓝牙适配器);蓝牙2.0使用BluetoothAdapter的静态方法(getDefaultAdapter方法)获取蓝牙适配器;BLE(蓝牙4.0)可使用BluetoothManager(蓝牙管理器)的getAdapter方法获取蓝牙适配器。无论使用哪种方法获得的BluetoothAdapter均为一个。
BluetoothAdapter实际上干的是管理器的工作,以下是BluetoothAdapter的常用方法:
- getDefaultAdapter:获取默认的蓝牙适配器。该方法为静态方法。
- getState:获取蓝牙的开关状态。STATE_ON表示已开启,STATE_TURNING_ON表示正在开启,STATE_OFF表示已关闭,STATE_TURNING_OFF表示正在关闭。
- enable:启用蓝牙功能。使用本方法启动蓝牙无法被其他设备检测到。
- disable:禁用蓝牙功能。
- isEnabled:判断蓝牙功能是否启用。返回true表示已启用,返回false表示未启用。
- getBondedDevices:获取已配对(已绑定)的设备集合。
- getRemoteDevice:根据设备地址获取远程的设备对象。
- startDiscovery:开始搜索周围的蓝牙设备。
- cancelDiscovery:取消搜索周围的蓝牙设备。
- isDiscovering:判断是否正在搜索周围的蓝牙设备。
由于BluetoothAdapter实际干了管理器的活,因此Android从4.3开始引入了正牌的管理器 BluetoothManager,调用BluetoothManager对象的getAdapter方法也可获得蓝牙适配器。但Android 4.3对蓝牙的增强补充,不只是添加BluetoothManager,更是为了支持最新的BLE(即蓝牙低能耗“Bluetooth Low Energy”),BLE对应的是蓝牙4.0及以上版本。因为BLE采取非常快速的连接方式,所以平时处于“非连接”状态,此时链路两端仅是知晓对方,只有在必要时才开启链路,完成传输后会尽快关闭链路。BLE技术与之前版本的蓝牙标准相比, 主要有三个方面的改进:更省电、连接速度更快、传输距离更远。
3. 蓝牙的使用
检测蓝牙设备并配对的功能可得分成4个步骤:初始化(获取蓝牙适配器并判断该设备是否有蓝牙功能)、开启蓝牙、搜索蓝牙设备、与指定设备配对。下面分别进行详细说明。
(1) 初始化蓝牙适配器
如果App会用到BLE的特性,则需增加对 Android版本的判断,对于4.3及以上版本要从BluetoothManager中获取蓝牙适配器。如果仅仅是普通的蓝牙连接,则调用getDefaultAdapter获取蓝牙适配器就行了。
- 获取蓝牙适配器。
- 判断设备是否有蓝牙功能。
//获取蓝牙适配器
BluetoothAdapter bluetoothAdapter=null;
//Android4.3以上支持BLE技术(即蓝牙4.0版本及以上)
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR2){
//如需要使用BLE特性,需使用蓝牙管理器获取蓝牙适配器
BluetoothManager bluetoothManager= (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
bluetoothAdapter=bluetoothManager.getAdapter();
}
else {
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
}
//判断是否拥有蓝牙功能
if(bluetoothAdapter!=null){
//该设备有蓝牙功能
}
else {
//该设备无蓝牙功能
}
(2) 开启蓝牙
- 使用getState方法获取蓝牙适配器状态判断蓝牙是否已开启或正在开启。
- 使用startActivityForResult方法弹出是否允许扫描蓝牙界面。
- 重写onActivityResult方法获取申请结果。
private int mRequestCode=123456;//请求码
//获取蓝牙状态
int bluetoothState=bluetoothAdapter.getState();
//蓝牙状态不为打开状态且不为正在打开状态
if(bluetoothState!=BluetoothAdapter.STATE_ON&&bluetoothState!=BluetoothAdapter.STATE_TURNING_ON){
//弹出是否允许扫描蓝牙界面(本action开启的蓝牙允许被搜索到)
//需要BLUETOOTH_ADVERTISE权限
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//弹出打开蓝牙界面(本action开启的蓝牙不会被搜索到)
//需要BLUETOOTH_CONNECT权限
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,mRequestCode);
}
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//由蓝牙弹出窗返回
if(requestCode==mRequestCode){
if(resultCode==RESULT_OK){
//蓝牙开启
}
else if(resultCode==RESULT_CANCELED) {
//不允许蓝牙开启
//弹出是否允许扫描蓝牙界面
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent,mRequestCode);
}
}
}
(3) 搜索/取消搜索蓝牙设备
- 使用isDiscovery方法判断蓝牙是否在搜索中。
- 使用startDiscovery方法开启蓝牙搜索。
- 使用cancelDiscovery方法取消蓝牙搜索。
- 蓝牙设备搜索通过广播异步返回结果,创建广播接收者并注册。
- 发现蓝牙设备后获取intent中包含的蓝牙设备(BluetoothDevice)对象。
BluetoothDevice类常用方法如下:
- getName:获取设备的名称。
- getAddress:获取设备的MAC地址。
- getBondState:获取设备的配对状态。BOND_NONE表示未绑定,BOND_BONDING表示正在绑定,BOND_BONDED表示已绑定。
- createBond:建立该设备的配对信息。该方法为隐藏方法,需要通过反射调用。
- removeBond:移除该设备的配对信息。该方法为隐藏方法,需要通过反射调用。
//蓝牙适配器未在搜索中
if(!bluetoothAdapter.isDiscovering()){
//开始蓝牙搜索
bluetoothAdapter.startDiscovery();
}
//蓝牙适配器搜索中
if(bluetoothAdapter.isDiscovering()){
//取消蓝牙搜索
bluetoothAdapter.cancelDiscovery();
}
//自定义广播接收者
public class MyReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//获取活动
String action=intent.getAction();
//发现蓝牙设备
if(action.equals(BluetoothDevice.ACTION_FOUND)){
//获取蓝牙设备 Parcelable-打包的
BluetoothDevice bluetoothDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
}
}
}
private MyReceiver myReceiver=null;
protected void onStart() {
super.onStart();
//创建过滤器
IntentFilter intentFilter=new IntentFilter();
//添加发现蓝牙设备活动
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
//创建广播接收者对象
myReceiver=new MyReceiver();
//注册广播接收者
registerReceiver(myReceiver,intentFilter);
}
protected void onStop() {
super.onStop();
//注销广播接收者
unregisterReceiver(myReceiver);
}
(4) 与指定的蓝牙设备配对
在发现蓝牙设备后,可获取到蓝牙设备(BluetoothDevice)对象。从上面的方法说明可以看出,搜索获得新设备后,即可调用设备对象的createBond方法建立配对。但配对成功与否的结果同样不是立即返回的,因为系统会弹出配对确认框供用户选择。只有用户在两部手机都选择了“配对”按钮,才算是双方正式搭配好了。由于配对请求需要在界面上手工确认,因此配对结果只能通过异步机制返回,此处的结果返回仍然采取广播形式,即系统会发出广播BluetoothDevice.ACTION_BOND_STATE_CHANGED通知App。故而前面第三步的广播接收器需增加过滤配对状态的变更动作,接收器内部也要补充更新蓝牙设备的配对状态了。
//自定义广播接收者
public class MyReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//获取活动
String action=intent.getAction();
//发现蓝牙设备
if(action.equals(BluetoothDevice.ACTION_FOUND)){
//获取蓝牙设备 Parcelable-打包的
BluetoothDevice bluetoothDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
}
//绑定蓝牙状态改变
else if(action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
//获取蓝牙设备 Parcelable-打包的
BluetoothDevice bluetoothDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//获取绑定状态
int bondState=bluetoothDevice.getBondState();
//判断绑定状态
if(bondState==BluetoothDevice.BOND_BONDED){
//已绑定
}
else if(bondState==BluetoothDevice.BOND_BONDING){
//正在绑定
}
else if (bondState==BluetoothDevice.BOND_NONE) {
//未绑定
}
}
}
}
private MyReceiver myReceiver=null;
protected void onStart() {
super.onStart();
//创建过滤器
IntentFilter intentFilter=new IntentFilter();
//添加发现蓝牙设备活动
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
//添加绑定状态改变活动
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//创建广播接收者对象
myReceiver=new MyReceiver();
//注册广播接收者
registerReceiver(myReceiver,intentFilter);
}
protected void onStop() {
super.onStop();
//注销广播接收者
unregisterReceiver(myReceiver);
}
4. 案例代码一览
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter=null;
private Button button=null;
@SuppressLint("MissingInflatedId")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件
button=findViewById(R.id.button);
//获取蓝牙适配器
//Android4.3以上支持BLE技术(即蓝牙4.0版本及以上)
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR2){
//如需要使用BLE特性,需使用蓝牙管理器获取蓝牙适配器
BluetoothManager bluetoothManager= (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
bluetoothAdapter=bluetoothManager.getAdapter();
}
else {
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
}
//判断是否拥有蓝牙功能
if(bluetoothAdapter!=null){
//该设备有蓝牙功能
openBluetooth();
//为按钮设置扫描监听器
button.setOnClickListener(new View.OnClickListener() {
@SuppressLint("MissingPermission")
public void onClick(View view) {
//蓝牙适配器未在搜索中
if(!bluetoothAdapter.isDiscovering()){
//开始蓝牙搜索
bluetoothAdapter.startDiscovery();
}
//定时停止蓝牙搜索
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//蓝牙适配器搜索中
if(bluetoothAdapter.isDiscovering()){
//取消蓝牙搜索
bluetoothAdapter.cancelDiscovery();
}
}
}).start();
}
});
}
else {
//该设备无蓝牙功能
}
}
private int mRequestCode=123456;
/**
* 打开蓝牙
*/
@SuppressLint("MissingPermission")
private void openBluetooth(){
//获取蓝牙状态
int bluetoothState=bluetoothAdapter.getState();
//蓝牙状态不为打开状态且不为正在打开状态
if(bluetoothState!=BluetoothAdapter.STATE_ON&&bluetoothState!=BluetoothAdapter.STATE_TURNING_ON){
//弹出是否允许扫描蓝牙界面
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent,mRequestCode);
}
}
@SuppressLint("MissingPermission")
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//由蓝牙弹出窗返回
if(requestCode==mRequestCode){
if(resultCode==RESULT_OK){
//蓝牙开启
}
else if(resultCode==RESULT_CANCELED) {
//不允许蓝牙开启
//弹出是否允许扫描蓝牙界面
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent,mRequestCode);
}
}
}
private MyReceiver myReceiver=null;
protected void onStart() {
super.onStart();
//创建过滤器
IntentFilter intentFilter=new IntentFilter();
//添加发现蓝牙设备活动
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
//添加绑定状态改变活动
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//创建广播接收者对象
myReceiver=new MyReceiver();
//注册广播接收者
registerReceiver(myReceiver,intentFilter);
}
protected void onStop() {
super.onStop();
//注销广播接收者
unregisterReceiver(myReceiver);
}
public class MyReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//获取活动
String action=intent.getAction();
//发现蓝牙设备
if(action.equals(BluetoothDevice.ACTION_FOUND)){
//获取蓝牙设备 Parcelable-打包的
BluetoothDevice bluetoothDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
}
//绑定蓝牙状态改变
else if(action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
//获取蓝牙设备
BluetoothDevice bluetoothDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//获取绑定状态
int bondState=bluetoothDevice.getBondState();
//判断绑定状态
if(bondState==BluetoothDevice.BOND_BONDED){
//已绑定
}
else if(bondState==BluetoothDevice.BOND_BONDING){
//正在绑定
}
else if (bondState==BluetoothDevice.BOND_NONE) {
//未绑定
}
}
}
}
tag:蓝牙,bluetooth,Bluetooth,BLE,BluetoothDevice