好记性不如烂笔头,既然不够聪明,就乖乖的做笔记,温故而知新。公司一代产品用的经典蓝牙通信,特点就是基于socket连接,传输速率快,缺点就是,额,,,耗电!虽然已经被取代了?,但还是记录一下经典蓝牙通信基本原理缅怀一下吧。
好了,全军出击!
蓝牙权限不属于危险权限,所以写在清单文件即可,Android6.0不需要动态申请。但是搜索周边蓝牙设备是需要定位权限的,而且要求gps打开。
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (null == mBluetoothAdapter) {
Toast.makeText(this.getApplicationContext(), R.string.not_support_bluetooth, Toast.LENGTH_SHORT).show();
return;
}
if(!mBluetoothAdapter.isEnabled()){
Toast.makeText(MainActivity.this, getString(R.string.open_bluetooth), 2000).show();
return;
}
或者
mBluetoothAdapter.enable()
mBluetoothAdapter.startDiscovery();
//TODO:搜索蓝牙之前需要判断定位权限和GPS开关 MIUI权限需要定制处理
if (PermissionUtil.getInstance().checkGPSPermission(MainActivity.this)) { if (!AppUtil.isGpsOPen(MainActivity.this) && PermissionUtil.getInstance().isOverMarshmallow()) { permissionDialog = new PermissionDialog(MainActivity.this, R.style.Dialog); permissionDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { permissionDialog.setTvContent(getResources().getString(R.string.forbid_tip_gps_open)); permissionDialog.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //跳转GPS设置界面 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, GPS_OPEN_CODE); } }); } }); permissionDialog.show(); return; } }
mBluetoothAdapter.cancelDiscovery();
//BluetoothAdapter.ACTION_DISCOVERY_FINISHED会回调
//扫描结束
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHEDD);
registerReceiver(mBluetoothReceiver, filter);//接受蓝牙状态信息并更新界面
private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case BluetoothDevice.ACTION_FOUND:
// TODO: 2017/11/3 需要请求位置权限才能弹对话框 在这里找到指定public address的蓝牙设备进行连接哦!
BluetoothDevice device1 = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
LogUtil.e(TAG, "address is " + device1.getAddress() + "\tname is " + device1.getName());
break;
case BluetoothDevice.ACTION_BOND_STATE_CHANGED: {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()) {
case BluetoothDevice.BOND_BONDING:
LogUtil.i(TAG, "正在与" + device.getName() + "__" + device.getAddress() + "配对");
break;
case BluetoothDevice.BOND_BONDED:
LogUtil.i(TAG, "与" + device.getName() + "__" + device.getAddress() + "完成配对");
HideDialog();
break;
case BluetoothDevice.BOND_NONE:
LogUtil.i(TAG, "取消与" + device.getName() + "__" + device.getAddress() + "配对");
default:
break;
}
break;
}
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
LogUtil.e(TAG, "扫描完成!!!");
if (!mFound) {
CToast.makeText(MainActivity.this, getString(R.string.please_set_bt_visiable), CToast.LIGHT_WHITE).show();
}
break;
}
}
};
前期的准备工作已经完成,来张美图消遣一下♨️
其实我还是觉得白衬衫有点长,哈哈。收起淫荡的笑容,咱们继续
只有设置当前蓝牙可见才能被其他设备搜索到,设置蓝牙可见也能提高部分机型配对对话框弹出概率。
if (mBluetoothAdapter.isEnabled()) {
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
startActivity(discoverableIntent);
}
}
Log.e(TAG, "sendMessage: 1");
if (null == mBluetoothDevice) {
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
}
Log.e(TAG, "sendMessage: 2");
if (mBluetoothSocket == null) {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
mBluetoothSocket.connect();
mOutputStream = mBluetoothSocket.getOutputStream();
}
private final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");//uuid 相当于端口号
private final String NAME = "bluetooth_socket";//serverSocket name
private class AcceptThread extends Thread {
private BluetoothServerSocket mBluetoothServerSocket;
private BluetoothSocket bluetoothSocket;
private InputStream is;
private OutputStream os;
private boolean isContinue;
AcceptThread() {
try {
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
if (mBluetoothServerSocket == null) {
return;
}
bluetoothSocket = mBluetoothServerSocket.accept();
Log.e(TAG, "run: accept");
is = bluetoothSocket.getInputStream();
os = bluetoothSocket.getOutputStream();
isContinue = true;
while (isContinue) {
byte[] buffer = new byte[128];
int count = is.read(buffer);
Message message = new Message();
message.obj = new String(buffer, 0, count, "utf-8");
mHandler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
isContinue = false;
} finally {
try {
if (bluetoothSocket != null) {
bluetoothSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
数据传输:
/**
* 发送信息到另一个蓝牙设备
*
* @param address 蓝牙设备地址
* @param message 信息
*/
private void sendMessage(String address, String message) {
try {
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
Log.e(TAG, "sendMessage: 1");
if (null == mBluetoothDevice) {
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
}
Log.e(TAG, "sendMessage: 2");
if (mBluetoothSocket == null) {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
mBluetoothSocket.connect();
mOutputStream = mBluetoothSocket.getOutputStream();
}
Log.e(TAG, "sendMessage: 3");
if (!mBluetoothSocket.isConnected()) {
resetSocket();
}
Log.e(TAG, "sendMessage: 4");
if (mOutputStream != null) {
try {
mOutputStream.write((message.getBytes("utf-8")));
Log.e(TAG, "onItemClick: " + mBluetoothAdapter.getName() + ":" + message);
} catch (Exception e) {
e.printStackTrace;
}
} } catch (Exception e) { e.printStackTrace(); } }
@Override
public void run() {
int dataType;
int requestType;
Utils.log(TAG, "start receive the message ---client >>>>>>>");
while (!mClosed) {
try {
dataType = mInput.read();
requestType = mInput.read();
Utils.log(TAG,"dataType = " + dataType + ", requestType ="+requestType);
switch (requestType) {
case WearableControlHelper.WCS_OPCODE_CONNECT:
//handleConnectRequest();
break;
case WearableControlHelper.WCS_OPCODE_DISCONNECT:
//handleDisconnectRequest();
break;
case WearableControlHelper.WCS_OPCODE_SEND:
case WearableControlHelper.WCS_OPCODE_SEND_FINAL:
//if (payload != null) {
handleSendRequest(requestType, dataType);
// }
break;
case WearableControlHelper.WCS_OPCODE_GET:
case WearableControlHelper.WCS_OPCODE_GET_FINAL:
//handleGetRequest(requestType);
break;
default:
break;
}
} catch (IOException e) {
Utils.log(TAG, "receive message error: " + e);
mClosed = true;
Message msg = Message.obtain(mCallBack, BluetoothWcsTransfer.MSG_RFCOMM_ERROR);//FIXME !!! disconnected
msg.sendToTarget();
return;
}
}