前段时间因为项目须要,针对部分热敏蓝牙打印机作了开发,原本刚开始是要用佳博的,结果开发完了说要换成汉印的打印机(此时心里一万只草泥马奔腾而过)。好了,言归正传。既然是蓝牙打印机,那么首先要作的就是进行蓝牙开发。先贴一个别人推荐的一个开源库:https://github.com/Jasonchenlijian/FastBle 话说在15年的时候有接触过原生的蓝牙开发,可是那时候并无运用到项目中,当时给个人一个感受就是不再要作这个玩意儿了。没想到从今年(2019年)开始,一直在作这方面的项目,为了养家糊口只能硬着头皮上了。各类Google各类百度,最后仍是没搞明白,那就放弃吧(怎么阔能,我是那么容易放弃的人吗(●'◡'●))。最后仍是得感谢老天眷顾,我朋友他们也都在作这个,那就一块儿约个饭出来聊波技术咯~java
其实对于蓝牙开发,最难的不是网上能找到的那些东西,它的一个关键点就是它须要的那几个UUID怎么获取?从何而来?一样这也是困惑我良久的一个问题。(serviceUuid、 writeCharactUuid 、 notifyCharactUuid 这三个)。我问了好多人他们都说不知道,实际上这个应该是厂家那边应该提供过来的,可是厂家不是技术,他们根本都不知道这是什么玩意儿,好吧 ,我跪了。那是否是真的没有办法了?并非,虽然个人办法有点不太靠谱,可是对于菜的要死又无知的本身来讲,固然要抱着试一试的态度咯。android
链接成功后拿到UUID集合而后进行遍历,将遍历获得的这些UUID一个一个赋值去试,终于皇天不负有心人,守得云开见月明,成功啦。o(* ̄▽ ̄*)ブ(PS:这么长时间的头发总算没有白掉)。git
下面介绍一下完整步骤。github
首先,清单文件中给权限(6.0以上必定要加定位权限):api
<!-- 使用蓝牙的权限 --> <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" />
还有要添加app
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" /> <service android:name="com.inuker.bluetooth.library.BluetoothService" />
而后就根据以前贴出的开源库进行开发就行了,我在这里贴一个工具类:ide
public class BleUtil { private static final String TAG = "BleUtil-->"; private static BleUtil bleUtil; public List<BleDevice> bleDevices; private OnBleListener listener; private String uuid_service = "本身获取的"; //接受数据特征UUID private String uuid_characteristic_receive = "本身获取的"; //发送数据特征UUID(视状况而定,本人不须要发送数据功能) // private String uuid_characteristic_send = "本身获取的"; private boolean isStandByBle; private boolean isEnableBle; private Context context; private Handler handler = new Handler(Looper.getMainLooper()); private final int START_SCAN = 100; private final int RESET_CONNECT = 101; // private final UUID[] serviceUuids; private BleDevice connectedBleDevice; private BleScanRunnable bleScanRunnable; private BleResetConnectRunnable bleConnectRunnable; private BleManager bleManager; private BleConnectedRunnable bleConnectedRunnable; private boolean isResetConnect = false; private boolean isScaning; private final ReturnTimeOutRunnable returnTimeOutRunnable; private String currentData = ""; private final ReceiveDataRunnable receiveDataRunnable; private BleUtil(Context context) { this.context = context.getApplicationContext(); bleManager = BleManager.getInstance(); isStandByBle = bleManager.isSupportBle(); isEnableBle = bleManager.isBlueEnable(); // //根据指定的UUID扫描特定的设备 // UUID serviceUuid = UUID.fromString(uuid_service); // serviceUuids = new UUID[]{serviceUuid}; bleScanRunnable = new BleScanRunnable(); bleConnectRunnable = new BleResetConnectRunnable(); bleConnectedRunnable = new BleConnectedRunnable(); returnTimeOutRunnable = new ReturnTimeOutRunnable(); receiveDataRunnable = new ReceiveDataRunnable(); } public static BleUtil getInstance(Context context) { if (bleUtil == null) { synchronized (BleUtil.class) { if (bleUtil == null) { bleUtil = new BleUtil(context); } } } return bleUtil; } public void startBle() { if (!isStandByBle) { Toast.makeText(context, "该设备不支持蓝牙功能", Toast.LENGTH_SHORT).show(); return; } bleDevices = new ArrayList<>(); BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder() // .setServiceUuids(serviceUuids) // .setAutoConnect(true) // .setDeviceMac("链接到的蓝牙MAC地址") .setScanTimeOut(15000) .build(); bleManager.initScanRule(scanRuleConfig); if (!bleManager.isBlueEnable()) { bleManager.enableBluetooth(); } handler.postDelayed(bleScanRunnable, 2 * 100); } private void startScan() { if (isResetConnect && listener != null) { listener.onResetConnect(); isResetConnect = false; } bleManager.scan(new BleScanCallback() { @Override public void onScanFinished(List<BleDevice> list) { isScaning = false; } @Override public void onScanStarted(boolean b) { isScaning = true; } @Override public void onScanning(BleDevice bleDevice) { Log.e(TAG, bleDevice.getName() + " " + bleDevice.getMac()); bleDevices.add(bleDevice); if (listener != null) { listener.onScaningBle(bleDevice); } } }); } //中止扫描 public void stopScan() { if (isScaning) bleManager.cancelScan(); } //断开链接 public void disConnect() { handler.removeCallbacks(bleScanRunnable); handler.removeCallbacks(bleConnectedRunnable); handler.removeCallbacks(bleConnectRunnable); handler.removeCallbacks(returnTimeOutRunnable); handler.removeCallbacks(receiveDataRunnable); if (connectedBleDevice != null && bleManager.isConnected(connectedBleDevice)) { stopIndicate(); bleManager.clearCharacterCallback(connectedBleDevice); bleManager.disconnect(connectedBleDevice); } } //判断是否链接 public boolean isConnected() { if (connectedBleDevice == null) { return false; } else { return bleManager.isConnected(connectedBleDevice); } } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) public void connectBle(BleDevice bleDevice) { stopScan(); bleManager.connect(bleDevice, new BleGattCallback() { @Override public void onStartConnect() { } @Override public void onConnectFail(BleDevice bleDevice, BleException e) { //链接失败,需作好重连措施 connectedBleDevice = bleDevice; handler.postDelayed(bleConnectRunnable, 200); Log.e("链接失败:", e.toString()); } @Override public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt bluetoothGatt, int i) { Log.e(TAG, "链接成功"); receiveData(bleDevice); connectedBleDevice = bleDevice; handler.postDelayed(bleConnectedRunnable, 200); //设备的服务信息及特征信息 // List<BluetoothGattService> serviceList = bluetoothGatt.getServices(); // for (BluetoothGattService service : serviceList) { // UUID uuid_service = service.getUuid(); // Log.e(TAG, "onConnectSuccess:service---- " + uuid_service); // List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics(); // for (BluetoothGattCharacteristic characteristic : characteristicList) { // UUID uuid_chara = characteristic.getUuid(); // Log.e(TAG, "onConnectSuccess: chara" + uuid_chara); // } // } } @Override public void onDisConnected(boolean b, BleDevice bleDevice, BluetoothGatt bluetoothGatt, int i) { //链接断开,需区分异常断开与主动断开(b=true),异常断开的重连操做,需作好时间间隔操做,否者可能致使长时间链接不上的状况 if (b) { Log.e(TAG, "正常断开"); bleManager.clearCharacterCallback(bleDevice); bluetoothGatt.connect(); bleManager.clearCharacterCallback(connectedBleDevice); if (listener != null) { listener.onDisConnected(); } } else { isResetConnect = true; Log.e(TAG, "异常断开"); if (!bleManager.isBlueEnable()) { bleManager.enableBluetooth(); handler.postDelayed(bleScanRunnable, 200); } else { //重连 handler.postDelayed(bleConnectRunnable, 200); } } } }); } //链接蓝牙 public void connectBle(String MAC) { bleManager.connect(MAC, new BleGattCallback() { @Override public void onStartConnect() { } @Override public void onConnectFail(BleDevice bleDevice, BleException e) { //链接失败,需作好重连措施 connectedBleDevice = bleDevice; handler.postDelayed(bleConnectRunnable, 200); Log.e("链接失败:", e.toString()); } @Override public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) { Log.e(TAG, "链接成功"); receiveData(bleDevice); connectedBleDevice = bleDevice; handler.postDelayed(bleConnectedRunnable, 200); } @Override public void onDisConnected(boolean b, BleDevice device, BluetoothGatt gatt, int status) { //链接断开,需区分异常断开与主动断开(b=true),异常断开的重连操做,需作好时间间隔操做,否者可能致使长时间链接不上的状况 if (b) { Log.e(TAG, "正常断开"); bleManager.clearCharacterCallback(device); gatt.connect(); bleManager.clearCharacterCallback(connectedBleDevice); if (listener != null) { listener.onDisConnected(); } } else { isResetConnect = true; Log.e(TAG, "异常断开"); if (!bleManager.isBlueEnable()) { bleManager.enableBluetooth(); handler.postDelayed(bleScanRunnable, 200); } else { //重连 handler.postDelayed(bleConnectRunnable, 200); } } } }); } //接受数据 private void receiveData(final BleDevice bleDevice) { final StringBuilder stringBuilder = new StringBuilder(); bleManager.indicate(bleDevice, uuid_service, uuid_characteristic_receive, new BleIndicateCallback() { @Override public void onIndicateSuccess() { //订阅通知成功 handler.postDelayed(returnTimeOutRunnable, 5 * 1000); Log.e(TAG, "onIndicateSuccess: 订阅成功"); } @Override public void onIndicateFailure(BleException e) { Log.e("接收数据异常------------>", e.toString()); } @Override public void onCharacteristicChanged(byte[] bytes) { handler.removeCallbacks(returnTimeOutRunnable); //接收到的数据 String s = BinaryConversionUtils.byte2hex(bytes); String resultData = BinaryConversionUtils.hexString2String(s); Pattern pattern = Pattern.compile("\n|\r"); Matcher matcher = pattern.matcher(resultData); resultData = matcher.replaceAll(""); stringBuilder.append(resultData); Log.e("接收数据成功------------>", stringBuilder.toString()); // Toast.makeText(context, resultData+"--", Toast.LENGTH_SHORT).show(); if (listener != null) { if (TextUtils.isEmpty(stringBuilder.toString()) || stringBuilder.toString().contains("ERROR")) { //空返回 handler.postDelayed(returnTimeOutRunnable, 200); } else if (resultData.contains("")) { //成功返回 currentData = resultData; handler.postDelayed(receiveDataRunnable, 200); // stopIndicate(); } } } }); } //发送数据 // public void sendData(final BleDevice bleDevice, final String str) { // byte[] data = BinaryConversionUtils.hex2byte(str); // bleManager.write(bleDevice, // uuid_service, // uuid_characteristic_send, // data, // true, // new BleWriteCallback() { // @Override // public void onWriteSuccess(int current, int total, byte[] justWrite) { // // 发送数据到设备成功(分包发送的状况下,能够经过方法中返回的参数能够查看发送进度) // Log.e("发送数据成功------------>", str); // receiveData(bleDevice); // bleManager.removeWriteCallback(bleDevice, uuid_characteristic_send); // } // // @Override // public void onWriteFailure(BleException exception) { // // 发送数据到设备失败 // Log.e("发送数据异常------------>", exception.toString()); // } // }); // } public void stopIndicate() { if (connectedBleDevice != null) { bleManager.stopIndicate(connectedBleDevice, uuid_service, uuid_characteristic_receive); bleManager.removeIndicateCallback(connectedBleDevice, uuid_characteristic_receive); } } //扫描设备的实时回调 public interface OnBleListener { //扫描结果 void onScaningBle(BleDevice bleDevice); //链接成功 void onConnected(BleDevice bleDevice); //异常重连 void onResetConnect(); //返回数据 void onReceiveData(String data); //返回数据超时 void onTimeOutReturn(); //蓝牙正常断开 void onDisConnected(); } public void setOnBleListener(OnBleListener listener) { this.listener = listener; } public class BleScanRunnable implements Runnable { @Override public void run() { startScan(); } } public class BleResetConnectRunnable implements Runnable { @Override public void run() { if (connectedBleDevice != null) { if (listener != null) listener.onResetConnect(); connectBle(connectedBleDevice); } else { Toast.makeText(context, "未扫描到蓝牙,请退出重连", Toast.LENGTH_SHORT).show(); } } } public class BleConnectedRunnable implements Runnable { @Override public void run() { if (listener != null) listener.onConnected(connectedBleDevice); } } public class ReturnTimeOutRunnable implements Runnable { @Override public void run() { if (listener != null) { listener.onTimeOutReturn(); } } } public class ReceiveDataRunnable implements Runnable { @Override public void run() { if (listener != null) { listener.onReceiveData(currentData); } } } }
记得添加依赖哦工具
到这里蓝牙链接功能结束了。效果以下(gif图传不上去,委屈你们看看图片咯~):oop
确实是有点丑的要死哈~ post
到这里对于蓝牙开发就结束了,下篇文章将给出上文中提到的佳博和汉印两款打印机的开发历程。敲重点啦哈~若是对于获取UUID有好的方法的,能够留言讨论一下哈,互相学习嘛(*  ̄3)(ε ̄ *),本文的Demo有须要能够留下你的邮箱哟~