最近做蓝牙通讯,需要app层静默连接通讯,记录近几天的心酸摸索。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {//不支持蓝牙或者蓝牙不可用
Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();
} else {
if (!bluetoothAdapter.isDiscovering()) bluetoothAdapter.startDiscovery();
}
蓝牙发现新设备会发出广播:BluetoothDevice.ACTION_FOUND
蓝牙搜索结束会发出广播:BluetoothAdapter.ACTION_DISCOVERY_FINISHED
//自定义蓝牙搜索状态广播接收器,找到设备后更新自己的列表
private class BlueDeviceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_FOUND)) {//发现新设备
BluetoothDevice btd = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (!deviceList.contains(btd.getName() + "\n" + btd.getAddress())) {
deviceList.add(btd.getName() + "\n" + btd.getAddress());
deviceAdapter.notifyDataSetChanged();
}
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
//搜索结束
}
}
}
}
注意添加权限:尖括号输入不了,囧。
uses-permission android:name=”android.permission.BLUETOOTH”
uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”
如果是android6.0系统需要额外添加权限,否则无法搜索设备:
uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”
uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!bluetoothAdapter.checkBluetoothAddress(deviceAddress)) {//检查是否是有效的蓝牙地址
Toast.makeText(LauncherDemoActivity.this, "蓝牙设备地址无效", Toast.LENGTH_SHORT).show();
return false;
}
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
if (device != null) {
Boolean returnValue = null;
try {
returnValue = ClsUtils.createBond(BluetoothDevice.class, device);
} catch (Exception e) {
e.printStackTrace();
}
if (returnValue) {//发起配对成功,并不代表配对成功,因为可能被拒绝
return true;
}
}
class MyActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothDevice.ERROR);
if (bondState == BluetoothDevice.BOND_BONDED) {//有新的配对设备
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
Set pairedDevices = adapter.getBondedDevices();
BluetoothDevice device1 = null;
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
if(device.getAddress().equals("55:44:33:22:11:00")) {//如果连接的设备中有特定的设备则发起socket连接请求
device1 = device;
break;
}
}
}
if(device1!=null) {//发起socket连接请求
try2ConnectDevice(device1);
}
}
}
}
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
BluetoothSocket mmSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
this.device = device;
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
return;
} new CommunicateThread(mmSocket).start();
// 其中CommunicateThread,即和服务器交互线程如下:
//客户端交互线程
class CommnicateThread extends Thread {
private final BluetoothSocket mmSocket;
private InputStream mmInStream;
private OutputStream mmOutStream;
private DataOutputStream dataOutputStream;
private DataInputStream dataInputStream;
public CommnicateThread(BluetoothSocket socket) {
mmSocket = socket;
// Get the BluetoothSocket input and output streams
try {
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
dataOutputStream = new DataOutputStream(mmOutStream);
dataInputStream = new DataInputStream(mmInStream);
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
}
public void run() {
// Keep listening to the InputStream while connected
while (true) {
try {
int type = dataInputStream.readByte();
// System.out.println(type);
} catch (IOException e) {
e.printStackTrace();
cancel();
connectionLost();
break;
}
}
}
//发送一个比特数组
public void write(byte[] buffer) {
try {
dataOutputStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
//发送一个int整型数据
public void writeInt(int i) {
try {
dataOutputStream.writeInt(i);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
//发送一个byte
public void writeByte(byte b) {
try {
dataOutputStream.writeByte(b);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
if (mmSocket != null)
mmSocket.close();
if(dataInputStream!=null)dataInputStream.close();
if(dataOutputStream!=null)dataOutputStream.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
BluetoothServerSocket bluetoothServerSocket;
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter==null){
Log.d("BluetoothServerService","设备不支持蓝牙");
return;
}
try {
bluetoothServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("ServerListener", MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
/**
* 阻塞式等待接入线程
*/
class AcceptThread extends Thread {
@Override
public void run() {
setName("acceptThread");
BluetoothSocket socket = null;
if (bluetoothServerSocket == null) return;
setState(DISCONNECT);
// Listen to the server socket if we're not connected
while (mState != CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = bluetoothServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
setState(CONNECTED);
commnicateThread = new CommnicateThread(socket);
commnicateThread.start();
}
}
}
public void cancel() {
try {
if (null != bluetoothServerSocket) {
bluetoothServerSocket.close();
}
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
//服务器端的交互线程
class CommnicateThread extends Thread {
private final BluetoothSocket mmSocket;
private InputStream mmInStream;
private OutputStream mmOutStream;
private DataInputStream dataInputStream;
private DataOutputStream dataOutputStream;
public CommnicateThread(BluetoothSocket socket) {
mmSocket = socket;
// Get the BluetoothSocket input and output streams
try {
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
dataInputStream = new DataInputStream(mmInStream);
dataOutputStream = new DataOutputStream(mmOutStream);
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
}
public void run() {
// Keep listening to the InputStream while connected
while (true) {
try {
int type = dataInputStream.readByte();
if (type == 1) {
short length = dataInputStream.readShort();
int what = dataInputStream.readByte();
System.out.println("1号类型:指令");
sendOrderBroadcast(what);
} else if (type == 2) {
System.out.println("2号类型:javabean");
byte[] data;
int flag;
synchronized (this) {
flag = dataInputStream.readInt();
int length = dataInputStream.readInt();
data = new byte[length];
dataInputStream.readFully(data);
}
System.out.println(data.length);
InstantNotificationItem i = (InstantNotificationItem) ByteUtil.toObject(data);
if (i == null) System.out.println("null");
else {
sendNotificationChangeBroadcast(i, flag);
}
}
writeAbyte((byte) 1);//回执给客户端的字符,暂时没有使用
} catch (IOException e) {
Log.e(TAG, "连接中断", e);
cancel();
connectionLost();
break;
}
}
}
/**
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void writeAbyte(byte what){
try {
dataOutputStream.writeByte(what);
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() {
try {
if (mmSocket != null)
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
**
**
公司要求在app层自定义蓝牙配对弹框,自动连接,网上搜了半天,没有很好的代码,今天把自己写的代码分享出来。话不多说,原理很简单,就是那个配对和取消的弹框是通过广播弹出来的,我们需要做的就是,自定义广播将其拦截,做自己的逻辑判断就可以了。下边是自动匹配所有蓝牙请求的代码,记得设置最大优先级哦,将IntentFilter的优先级或者静态注册的话android:priority=”2147483647”。自定义透明activity当做弹出框,点击某一个按钮的时候再device.setPairingConfirmation(true),简单吧。
public class BluetoothConnectActivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
try {
// 广播接收者的优先者为最高 收到广播后 停止广播向下传递
// TODO: 16/8/9 判断device是否是自己的设备,是的话拦截,否则不处理。
device.setPairingConfirmation(true);
abortBroadcast();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
**
**
import android.bluetooth.BluetoothDevice;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ClsUtils {
/**
* 与设备配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
*/
static public boolean createBond(Class btClass, BluetoothDevice btDevice)
throws Exception {
Method createBondMethod = btClass.getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
return returnValue.booleanValue();
}
/**
* 与设备解除配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
*/
static public boolean removeBond(Class btClass, BluetoothDevice btDevice)
throws Exception {
Method removeBondMethod = btClass.getMethod("removeBond");
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
return returnValue.booleanValue();
}
static public boolean setPin(Class btClass, BluetoothDevice btDevice,
String str) throws Exception {
try {
Method removeBondMethod = btClass.getDeclaredMethod("setPin",
new Class[]
{
byte[].class
});
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
new Object[]
{
str.getBytes()
});
Log.e("returnValue", "" + returnValue);
} catch (SecurityException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (IllegalArgumentException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
static public boolean setPassKey(Class btClass, BluetoothDevice btDevice,
String str) throws Exception {
try {
Method removeBondMethod = btClass.getDeclaredMethod("setPasskey",
new Class[]
{
byte[].class
});
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
new Object[]
{
str.getBytes()
});
Log.e("returnValue", "" + returnValue);
} catch (SecurityException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (IllegalArgumentException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
// 取消用户输入
static public boolean cancelPairingUserInput(Class btClass,
BluetoothDevice device)
throws Exception {
Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
// cancelBondProcess()
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
return returnValue.booleanValue();
}
// 取消配对
static public boolean cancelBondProcess(Class btClass,
BluetoothDevice device)
throws Exception {
Method createBondMethod = btClass.getMethod("cancelBondProcess");
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
return returnValue.booleanValue();
}
/**
*
* @param clsShow
*/
static public void printAllInform(Class clsShow) {
try {
// 取得所有方法
Method[] hideMethod = clsShow.getMethods();
int i = 0;
for (; i < hideMethod.length; i++) {
Log.e("method name", hideMethod[i].getName() + ";and the i is:"
+ i);
}
// 取得所有常量
Field[] allFields = clsShow.getFields();
for (i = 0; i < allFields.length; i++) {
Log.e("Field name", allFields[i].getName());
}
} catch (SecurityException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (IllegalArgumentException e) {
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static boolean isWantedMac(String macStr) {
if (macStr == null || macStr.isEmpty()) return false;
if (macStr.equals("55:44:33:22:11:00")) {
return true;
} else return false;
}
}