赞
踩
一些解释
设备列表:是指附近的可见蓝牙设备,但是还没匹配
匹配设备列表:是指已经完成匹配的列表
设备类型分为:【未匹配状态】、【匹配状态】、【配对状态】
未匹配,就是指从来没有匹配过的设备
匹配状态,就是指设备间已经相互完成了身份验证,处于待配对(待建立Socket)状态
以前蓝牙配对的时候,手机会弹出一个对话框,提示输入pin码,其实也就是提前约定的一个配对码,到后来,手机与与手机之间的连接就不需要配对码了(实际上是程序内部完成了配对的过程)
当然,手机与一些蓝牙硬件(例如单片机+蓝牙模块的组合)配对时,还是需要输入pin码(不过也能通过程序自动完成验证)
配对的过程,其实就是Socket通信的一个过程,两个蓝牙设备仅仅匹配是还不能够传递数据的,只有当二者建立了Socket通道之后,才能进行数据的传递
<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--模糊定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精准定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
后边的模糊定位和精准定位是必须的,没有这两个权限,注册BroadcastReceiver 监听扫描结果时,不会成功的,不走扫描开始之类的方法
Android的蓝牙开发有涉及到不同的蓝牙种类,例如低功耗蓝牙(BluetoothGatt)、蓝牙健康(BlueToothHealth)等,这里介绍的依然是常规的蓝牙开发API
这个类代表着本地的蓝牙适配器,让你可以从事各种与蓝牙相关的操作,例如开始和停止设备的查找;查询已匹配的设备并以集合的形式返回;通过已知的设备地址,实例化一个BlueToothDevice;创建一个BluetoothServerSocket来监听来自其他设备的链接请求等等,总之要想使用本机的蓝牙,这个类是极其重要的
//获取本地蓝牙适配器
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
/**
* 设备是否支持蓝牙 true为支持
* @return
*/
public boolean isSupportBlue(){
return bluetoothAdapter!= null;
}
//获取BluetoothAdapter对象 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //判断设备是否支持蓝牙,如果mBluetoothAdapter为空则不支持,否则支持 if (mBluetoothAdapter == null) { Toast.makeText(this, "这台设备不支持蓝牙", Toast.LENGTH_SHORT).show(); } else { // If BT is not on, request that it be enabled. // setupChat() will then be called during onActivityResult //判断蓝牙是否开启,如果蓝牙没有打开则打开蓝牙 if (!mBluetoothAdapter.isEnabled()) { //请求用户开启 Intent enableIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { getDeviceList(); } }
判断请求后是否开启
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_OK) {
// bluetooth is opened
//可以获取列表操作等
} else {
// bluetooth is not open
Toast.makeText(this, "蓝牙没有开启", Toast.LENGTH_SHORT).show();
}
}
}
获取已经匹配的设备列表,并以set集合的方式返回
/*
*获取已经配对的设备
*/
private void setPairingDevice() {
Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
if (devices.size() > 0) { //存在已配对过的设备
//利用for循环读取每一个设备的信息
for (Iterator<BluetoothDevice> it = devices.iterator(); it.hasNext(); ) {
BluetoothDevice btd = it.next();
```````
}
}else{
//不存在已经配对的蓝牙设备
}
}
判断当前是否正在查找设备,是返回true
取消查找设备
这里需要注意一下,由于搜素是一个耗时操作,所以这个方法应该在线程中去调用,同时需要配合着广播去使用
开始查找设备,一般的调用代码如下:
private void doDiscovery() {
new Thread(new Runnable() {
@Override
public void run() {
if(bluetoothAdapter.isDiscovering()){
bluetoothAdapter.cancelDiscovery();
}
bluetoothAdapter.startDiscovery();
}
}).start();
}
这里再注意一个细节,那就是如果当前的adapter正在查找,那么必须停止当前查找,然后再重新查找,这是因为查找操作占用很多的系统资源,我们需要避免重复的查找
getAddress()获取本地蓝牙地址
getName()获取本地蓝牙名称
getState()获取本地蓝牙适配器当前状态
这个类代表一个远程设备,它能够让我们与一个其他相关设备创建连接,或者查询与此设备相关的信息,例如名称(name)、地址(address)、连接状态(boud state)
getAddress()获取Address设备的蓝牙地址
getName()获取Address设备的地蓝牙名称
getState()获取Address设备的蓝牙适配器当前状态,是匹配状态,不是连接状态
这部分代码之前已经写过
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
bluetoothAdapter.startDiscovery();
//搜索开始的过滤器 IntentFilter filter1 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED); //搜索结束的过滤器 IntentFilter filter2 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //寻找到设备的过滤器 IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_FOUND); //绑定状态改变 IntentFilter filer4 = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //配对请求 IntentFilter filter5 = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST) registerReceiver(mFindBlueToothReceiver ,filter1); registerReceiver(mFindBlueToothReceiver ,filter2); registerReceiver(mFindBlueToothReceiver ,filter3); registerReceiver(mFindBlueToothReceiver ,filter4); registerReceiver(mFindBlueToothReceiver ,filter5);
//广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行 private final BroadcastReceiver mFindBlueToothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (action){ case BluetoothAdapter.ACTION_DISCOVERY_STARTED: Log.d(TAG, "开始扫描..."); callBack.onScanStarted(); break; case BluetoothAdapter.ACTION_DISCOVERY_FINISHED: Log.d(TAG, "结束扫描..."); callBack.onScanFinished(); break; case BluetoothDevice.ACTION_FOUND: Log.d(TAG, "发现设备..."); callBack.onScanning(device); break; case BluetoothDevice.ACTION_BOND_STATE_CHANGED: Log.d(TAG, "设备绑定状态改变..."); callBack.onStateChanged(device); break; } } };
其中布尔值returnValue
为true,表示配对成功,配对成功后,可能会输入PIN码
当输入完成正确PIN码后,才会配对完成。就可以通过广播的方式接收配对结果
/** * 配对蓝牙设备 */ private void pinTargetDevice(int position) { //在配对之前,停止搜索 cancelDiscovery(); //获取要匹配的BluetoothDevice对象,后边的deviceList是你本地存的所有对象 BluetoothDevice device = deviceList.get(position); if (device.getBondState() != BluetoothDevice.BOND_BONDED) {//没配对才配对 try { Log.d(TAG, "开始配对..."); Method createBondMethod = BluetoothDevice.class.getMethod("createBond"); Boolean returnValue = (Boolean) createBondMethod.invoke(device); if (returnValue){ Log.d(TAG, "配对成功..."); showToast("配对成功"); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
/** * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败) * @param device */ public void cancelPinBule(BluetoothDevice device){ Log.d(TAG, "attemp to cancel bond:" + device.getName()); try { Method removeBondMethod = device.getClass().getMethod("removeBond"); Boolean returnValue = (Boolean) removeBondMethod.invoke(device); returnValue.booleanValue(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e(TAG, "attemp to cancel bond fail!"); } }
经测试,不管用,貌似只有在系统设置里才能取消配对?所以我的做法是跳转了蓝牙设置
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
/** * 广播接收器 * 当远程蓝牙设备被发现时,回调函数onReceiver()会被执行 */ private final BroadcastReceiver mFindBlueToothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (action){ ...... case BluetoothDevice.ACTION_BOND_STATE_CHANGED: Log.d(TAG, "设备绑定状态改变..."); switch (device.getBondState()) { case BluetoothDevice.BOND_BONDING: Log.w(TAG, "正在配对......"); break; case BluetoothDevice.BOND_BONDED: Log.w( TAG, "配对完成"); break; case BluetoothDevice.BOND_NONE: Log.w(TAG, "取消配对"); default: break; } break; } } };
蓝牙配对和连接是两个不同的东西
经典蓝牙连接相当于socket连接,是个非常耗时的操作,所以应该放到子线程中去完成
/** * 蓝牙连接线程 */ public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> { private BluetoothDevice bluetoothDevice; private ConnectBlueCallBack callBack; public ConnectBlueTask(ConnectBlueCallBack callBack){ this.callBack = callBack; } @Override protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) { bluetoothDevice = bluetoothDevices[0]; BluetoothSocket socket = null; try{ Log.d(TAG,"开始连接socket,uuid:00001101-0000-1000-8000-00805F9B34FB"); socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); if (socket != null && !socket.isConnected()){ socket.connect(); } }catch (IOException e){ Log.e(TAG,"socket连接失败"); try { socket.close(); } catch (IOException e1) { e1.printStackTrace(); Log.e(TAG,"socket关闭失败"); } } return socket; } @Override protected void onPreExecute() { Log.d(TAG,"开始连接"); if (callBack != null) callBack.onStartConnect(); } @Override protected void onPostExecute(BluetoothSocket bluetoothSocket) { if (bluetoothSocket != null && bluetoothSocket.isConnected()){ Log.d(TAG,"连接成功"); if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket); }else { Log.d(TAG,"连接失败"); if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败"); } } }
/**
* 连接 (在配对之后调用)
* @param device
*/
public void connect(BluetoothDevice device, ConnectBlueCallBack callBack){
//连接之前把扫描关闭
if (mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
new ConnectBlueTask(callBack).execute(device);
}
其中ConnectBlueCallBack
是个接口,用于连接之后回调
public interface ConnectBlueCallBack{
void onStartConnect();
void onConnectSuccess(BluetoothDevice device,BluetoothSocket bluetoothSocket);
void onConnectFail(BluetoothDevice device,String string);
}
所以在真正调用以上conn方法时是这样写的,传入一个连接的device,并且new一个刚才定义的接口
connect(device, new ConnectBlueCallBack() { @Override public void onStartConnect() { Log.w( TAG, "开始连接"); } @Override public void onConnectSuccess(BluetoothDevice device, BluetoothSocket bluetoothSocket) { Log.w( TAG, "连接成功"); } @Override public void onConnectFail(BluetoothDevice device, String string) { Log.w( TAG, "连接失败"); } });
值得注意的是,如果你不知道UUID也不用担心,一些常见的蓝牙服务协议已经有约定的 UUID。比如我们连接热敏打印机是基于 SPP 串口通信协议,其对应的 UUID 是 “00001101-0000-1000-8000-00805F9B34FB”,所以上边的一串数字被我写死了
/**
* 蓝牙是否连接
* @return
*/
public boolean isConnectBlue(){
return mBluetoothSocket != null && mBluetoothSocket.isConnected();
}
/** * 断开连接 * @return */ public boolean cancelConnect(){ if (mBluetoothSocket != null && mBluetoothSocket.isConnected()){ try { mBluetoothSocket.close(); } catch (IOException e) { e.printStackTrace(); return false; } } mBluetoothSocket = null; return true; }
参考文章
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。