与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设备进行通信,如接近传感器、心率传感器等低功耗设备。
声明蓝牙权限 6.0以上
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
如果想让你的App适用于不支持BLE的设备,只需要将required="true"
改为required="false"
然后在代码中通过以下方法来判断设备是否支持BLE。
private void checkIsSupportBLE() { if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } }
扫描周边的蓝牙设备
扫描BLE设备
注:扫描蓝牙设备可以通过 startLeScan(BluetoothAdapter.LeScanCallback)和startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法,这两种扫描BLE设备的区别如下。
startLeScan(BluetoothAdapter.LeScanCallback)方法扫描的是周围所有的BLE设备。
startLeScan(UUID[], BluetoothAdapter.LeScanCallback)只扫描和UUID相匹配的设备。
1自定义 一个对话框BluetoothDeviceDialog
public class BluetoothDeviceDialog extends Dialog implements BluetoothDeviceAdapter.BelInfoAdapterListener { private static final String TAG ="BluetoothDeviceDialog" ; private RelativeLayout rlTop; private TextView tvAddress; private RelativeLayout rlClose; private RecyclerView rvDevices; BluetoothAdapter mBluetoothAdapter = null; BluetoothManager mBluetoothManager = null; BluetoothLeScanner mBluetoothLeScanner = null; private BleDevice bleDevice; BluetoothChoiceListener mBluetoothChoiceListener; public BleDevice getBleDevice() { return bleDevice; } private void setBleDevice(BleDevice bleDevice) { this.bleDevice = bleDevice; } List<BleDevice> mBleDeviceList; Context mContext; public BluetoothDeviceDialog(@NonNull Context context , BluetoothChoiceListener bluetoothChoiceListener ) { super(context, R.style.style_dialog); mBleDeviceList=new ArrayList<>(); this.mBluetoothChoiceListener=bluetoothChoiceListener; this.mContext=context; startScanBle(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_bluetooth_device); initView(); setCanceledOnTouchOutside(false);; // PublicUtils.getInstance().settingDialogPostion(mContext); } BluetoothDeviceAdapter bluetoothDeviceAdapter=null; private void initView() { rlTop = findViewById(R.id.rl_top); tvAddress = findViewById(R.id.tv_address); rlClose = findViewById(R.id.rl_close); rvDevices = findViewById(R.id.rv_devices); bluetoothDeviceAdapter=new BluetoothDeviceAdapter(mBleDeviceList,this); LinearLayoutManager linearLayoutManager=new LinearLayoutManager(mContext); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); rvDevices.setLayoutManager(linearLayoutManager); rvDevices.setAdapter(bluetoothDeviceAdapter); rlClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); } @Override public void dismiss() { if(scanCallback!=null) { stopScanBle(); } super.dismiss(); } /** * 常量初始化 * @return false */ public boolean initialize() { // For API level 18 and above, get a reference to BluetoothAdapter through if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) mContext. getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Toast.makeText(mContext, "设备不支持蓝牙功能", Toast.LENGTH_SHORT).show(); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.i(TAG, "Unable to obtain a BluetoothAdapter."); return false; } mBluetoothLeScanner=mBluetoothAdapter.getBluetoothLeScanner(); return true; } private void startScanBle() { mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = mBluetoothManager.getAdapter(); mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); if(mBluetoothManager==null) { Toast.makeText(mContext, "设备不支持蓝牙功能", Toast.LENGTH_SHORT).show(); } // 打开蓝牙 else if (!mBluetoothAdapter.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); // 设置蓝牙可见性,最多300秒 intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); mContext.startActivity(intent); } else if(mBluetoothLeScanner!=null) { mBluetoothLeScanner.startScan(scanCallback); } } private void stopScanBle() { if (null != scanCallback && null != mBluetoothLeScanner) { mBluetoothLeScanner.stopScan(scanCallback); } } // 蓝牙扫描回调 private ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, final ScanResult result) { super.onScanResult(callbackType, result); BleDevice bleDevice = new BleDevice(false, result.getRssi(),result.getDevice()); if (!TextUtils.isEmpty(result.getDevice().getName())) { Log.i("textLog", "result.getRssi is " + result.getRssi()); Log.i("textLog", "result.getRssi is " + bleDevice.toString()); bluetoothDeviceAdapter.updateBluetoothDeviceList(bleDevice); bluetoothDeviceAdapter.notifyDataSetChanged(); } if(mBleDeviceList.size()==0) { rvDevices.setVisibility(View.GONE); } else{ rvDevices.setVisibility(View.VISIBLE); } } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); Log.i("textLog", "results is " + results.size()); for (int i = 0; i < results.size(); i++) { Log.i("textLog", "results is " + results.get(i).getDevice().getName() + ""); } } @Override public void onScanFailed(int errorCode) { Log.i("textLog", "errorCode is " + errorCode); super.onScanFailed(errorCode); } }; @Override public void onClickBleItem(int position) { mBluetoothChoiceListener.choiceBluetoothDevice(mBleDeviceList.get(position)); setBleDevice(mBleDeviceList.get(position)); tvAddress.setText(mBleDeviceList.get(position).getBluetoothDevice().getAddress()); PreferencesUtils.putString(mContext, PubConstants.BLE_DEVICES_ADDRESS, mBleDeviceList.get(position).getBluetoothDevice().getAddress()); PreferencesUtils.putString(mContext, PubConstants.BLE_NAME, mBleDeviceList.get(position).getBluetoothDevice().getName()); dismiss(); } public interface BluetoothChoiceListener { void choiceBluetoothDevice(BleDevice bleDevice); }
2.获取蓝牙,定义蓝牙管理器,可用简单的门店模式,也可自己简单封装。
public class BleManager { private static final String TAG ="BleManager" ; private volatile static BleManager instance=null; BleSocketService mService=null; public static BleManager getDefault() { if(instance==null) { synchronized (BleManager.class){ if(instance==null) { instance=new BleManager(); } } return instance; } return instance; } /** * 启动服务,扫描蓝牙 */ public void start(Context mContext) { Intent bindIntent = new Intent(mContext, BleSocketService.class); mContext. bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE); } public void stop(Context mContext) { mContext. unbindService( mServiceConnection); } /** * 断开链接 */ public void disconnect() { if(null!=mService) { mService.disconnect(); } } public void sendMessage(byte[] data) { Log.i(TAG," 发送消息给数据 : " + HexDump.getInstance().bytesToHexString(data)) ; BleMessage bleMessage=new BleMessage(false,data); mService.clear(); mService.addMessage(bleMessage); mService.requestBLEData(); } /** * 检测蓝牙是否链接 */ public boolean isCheckBleConnect(Context context, String devicesAddress ) { boolean isConnect= false; if(mService!=null) { if(!TextUtils.isEmpty(devicesAddress)){ isConnect = mService.connect(context,devicesAddress); return isConnect; } } else{ Log.i(TAG, " :bleSocketService is null "); } return isConnect; } public void onDestroy() { try { if(mService!=null) { mService.clear(); mService=null; } else{ Log.i(TAG, "onDestroy ==> 蓝牙资源回收异常: " ); } } catch (Exception e){ mService=null; } } private ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder rawBinder) { mService = ((BleSocketService.LocalBinder) rawBinder).getService(); } public void onServiceDisconnected(ComponentName classname) { mService.disconnect(mDevice); mService = null; } }; } [点击并拖拽以移动]
3.开启定义一个后台连接蓝牙的service
注:连接BLE设备
要进行BLE设备之间的通讯,首先应该进行设备之间的连接,可以通过device.connectGatt (Context context,boolean autoConnect, BluetoothGattCallback callback)方法来连接设备。
autoConnect是设置当BLE设备可用时是否自动进行连接。
device就是通过扫描BLE设备获得的。
callback则是连接指定设备后的回掉,可以在回掉中知道是否建立连接、连接断开、以及获取设备之间传输的数据。以下是BluetoothGattCallback类中具体的方法
下面我会介绍几个比较常用的方法:
onConnectionStateChange此方法的作用是可以获得设备连接的状态,如“成功连接”、“断开连接”。
onServicesDiscovered当远程设备的服务,特性和描述符列表已更新时(即发现新服务),调用此方法。
onCharacteristicChanged远程特征变化会调用此方法,即BLE设备的状态发生了变化会调用此方法。onCharacteristicChanged方法就是相当于BLE设备对你操作的回应,如打开BLE设备成功等,然后在此方法回掉之后,便可以继续下一步操作了。
public class BleSocketService extends Service { private final static String TAG = "BleSocketService"; BluetoothManager mBluetoothManager=null; BluetoothAdapter mBluetoothAdapter=null; private List<BleMessage> bleMessageList=new ArrayList<>(); private BluetoothGatt mBluetoothGatt; private boolean isStartThread=true; @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { return super.bindService(service, conn, flags); } @Override public void unbindService(ServiceConnection conn) { super.unbindService(conn); } public void addMessage(BleMessage bleMessage) { bleMessageList.add(bleMessage); } public void clear() { if(null!=bleMessageList) { bleMessageList.clear(); } } @Override public void onDestroy() { Log.i(TAG, " onDestroy "); if(null!=mBluetoothGatt) { mBluetoothGatt.close(); } super.onDestroy(); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate "); initialize(this); } /** * 常量初始化 * @return */ private boolean initialize(Context context) { // For API level 18 and above, get a reference to BluetoothAdapter through if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.i(TAG, "Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.i(TAG, "Unable to obtain a BluetoothAdapter."); return false; } else{ Log.i(TAG, "mBluetoothManager.getAdapter().getAddress : ."+mBluetoothManager.getAdapter().getAddress()); } return true; } /** * 检测蓝牙蓝牙操作 * @param address * @return */ public boolean connect(Context context, final String address) { final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.i("textLog", "Device not found. Unable to connect."); return false; } mBluetoothGatt = device.connectGatt(context, true, mGattCallback); if(mBluetoothGatt.connect()){ Log.i("textLog", " 管道链接成功 "); isStartThread=true; if(mBluetoothGatt.discoverServices()){ Log.i("textLog", "管道discoverServices已经开始了"); mBluetoothGatt.discoverServices(); return true; }else{ Log.i("textLog", "管道discoverServices没有开始"); } } else{ Log.i("textLog", "链接失败! "+mBluetoothGatt.discoverServices()); } return true; } boolean isConnectFlag=false; private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { Log.i(TAG," 蓝牙已链接" ); mBluetoothGatt.discoverServices(); isStartThread=true; EventBus.getDefault().post(true); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.i(TAG," 断开链接" ); EventBus.getDefault().post(false); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { try { Thread.sleep(1000); Log.i(TAG," 链接蓝牙管道建立成功" ); onRestartBluetoothGattService(); isStartThread=true; EventBus.getDefault().post(true); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { Log.i(TAG, "onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.i(TAG, "onCharacteristicRead"); if (status == BluetoothGatt.GATT_SUCCESS) { EventBus.getDefault().post(characteristic.getValue()); String callBackCmd= HexDump.getInstance().bytesToHexString(characteristic.getValue()); EventBus.getDefault().post(callBackCmd); Log.i(TAG," 蓝牙回调数据:" + callBackCmd); } else if(status== BluetoothGatt.GATT_FAILURE) { Log.i(TAG," 蓝牙回调数据:GATT_FAILURE " ); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // eventBusPost(ACTION_DATA_AVAILABLE, characteristic); String callBackCmd=HexDump.getInstance().bytesToHexString(characteristic.getValue()); EventBus.getDefault().post(characteristic.getValue()); EventBus.getDefault().post(callBackCmd); Log.i(TAG," 蓝牙回调数据:" + callBackCmd); } }; /** * Disconnects an existing connection or cancel a pending connection. The disconnection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.i(TAG, "BluetoothAdapter not initialized"); return; } bleMessageList.clear(); mBluetoothGatt.disconnect(); isStartThread=false; } /** * After using a given BLE device, the app must call this method to ensure resources are * released properly. */ public void close() { if (mBluetoothGatt == null) { return; } Log.i(TAG, "mBluetoothGatt closed"); mBluetoothGatt.close(); mBluetoothGatt = null; } /** * 蓝牙读取数据 * @param characteristic */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.i(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); } /** * Enables or disables notification on a give characteristic. * * @param characteristic Characteristic to act on. * @param enabled If true, enable notification. False otherwise. */ public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.i(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); // 这是专门针对心率测量服务 // if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { // BluetoothGattDescriptor descriptor = characteristic.getDescriptor( // UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG)); // descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // mBluetoothGatt.writeDescriptor(descriptor); // } } /** * 获取蓝牙长链接服务 * @return */ public List<BluetoothGattService> getSupportedGattServices() { if (mBluetoothGatt == null) return null; return mBluetoothGatt.getServices(); } /** * 重新快开始蓝牙长链接服务 */ public void onRestartBluetoothGattService() { try { BluetoothGattService RxService = mBluetoothGatt.getService(PubConstants.RX_SERVICE_UUID); if (RxService == null) { Log.i(TAG,"Rx service not found!"); return; } BluetoothGattCharacteristic TxChar = RxService.getCharacteristic(PubConstants.TX_CHAR_UUID); if (TxChar == null) { Log.i(TAG,"Tx charateristic not found!"); return; } mBluetoothGatt.setCharacteristicNotification(TxChar,true); List<BluetoothGattDescriptor> mDescriptors=TxChar.getDescriptors(); for (int i = 0; i < mDescriptors.size(); i++) { BluetoothGattDescriptor descriptor = mDescriptors.get(i); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } } catch (Exception e){ Log.i(TAG, "Exception :"+e); } } boolean isWriteCharacteristic=false; public boolean writeRXCharacteristic(byte[] value) { Log.d(TAG, "蓝牙 读取数据 :writeRXCharacteristic: "+ HexDump.getInstance().bytesToHexString(value)); BluetoothGattService RxService = mBluetoothGatt.getService(PubConstants.RX_SERVICE_UUID); List<BluetoothGattService> mServices=mBluetoothGatt.getServices(); Log.e(TAG, "service size : "+mServices.size()); for (BluetoothGattService service : mServices) { Log.e(TAG, "service uuid : "+service.getUuid()); } if (RxService == null) { Log.e(TAG, "Rx charateristic not found!"); return false; } BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(PubConstants.RX_CHAR_UUID); if (RxChar == null) { Log.e(TAG, "Rx charateristic not found!"); return false; } RxChar.setValue(value); isWriteCharacteristic = mBluetoothGatt.writeCharacteristic(RxChar); // boolean isReadCharacteristic = mBluetoothGatt.readCharacteristic(RxChar); // Log.i(TAG, "isReadCharacteristic: "+isReadCharacteristic ); Log.i(TAG, "isWriteCharacteristic: "+ isWriteCharacteristic); return isWriteCharacteristic; } public void requestBLEData() { Log.i(TAG, "isStartThread :"+isStartThread); try { Log.i(TAG, "bleMessageList :"+bleMessageList.size()); for (int i = 0; i < bleMessageList.size(); i++) { BleMessage bleMessage= bleMessageList.get(i); if(bleMessage.getData()==null) { Log.i(TAG, "bleMessageList :"+i); return; } Log.i(TAG, "发送数据给蓝牙 :"+ HexDump.getInstance().dumpHexString(bleMessage.getData())); //发送蓝牙 boolean isLinkBle=writeRXCharacteristic(bleMessage.getData()); EventBus.getDefault().post(new BleMessage(isLinkBle,bleMessage.getData())); Log.i(TAG, "蓝牙是否可以读取数据 :"+ isLinkBle ); } Thread.sleep(70); } catch (InterruptedException e) { e.printStackTrace(); } } public class LocalBinder extends Binder { public BleSocketService getService() { return BleSocketService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public boolean onUnbind(Intent intent) { // After using a given device, you should make sure that BluetoothGatt.close() is called // such that resources are cleaned up properly. In this particular example, close() is // invoked when the UI is disconnected from the Service. close(); return super.onUnbind(intent); } private final IBinder mBinder = new LocalBinder(); }
最后 ,简单的代码调用
public class BleMainActivity extends BaseLibActivity implements View.OnClickListener, BluetoothDeviceDialog.BluetoothChoiceListener ,FirmwareInfoImp.FirmwareInfoImpLister { private static final String TAG =BleMainActivity.class.getSimpleName() ; private Button mBtnOpen; private Button mBtnSend; private Button mBtnClosed; private TextView mTvName; private TextView mTvBelAddress; private TextView mTxBleCallback; private String address="",devicesName=""; private Button mBtnUpgrade; private TextView mTvState; private TextView mTvYunState; private RelativeLayout mRlUpgrade; public ProgressBar mProgressBar; public TextView mTvProgress; public TextView mTvVersion; public TextView mTxBleRequest; //总帧数 int frameTotalNum=0; private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WAKE_LOCK}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_ble_main); mTvState = findViewById(R.id.tv_state); BleManager.getDefault().start(mContext); initView(); mFirmwareInfoImp=new FirmwareInfoImp(BleMainActivity.this,this); requestPermission(); address= PreferencesUtils.getString(BleMainActivity.this, PubConstants.BLE_DEVICES_ADDRESS,""); devicesName= PreferencesUtils.getString(BleMainActivity.this, PubConstants.BLE_NAME,""); } UiHandler uiHandler; public void initView(){ uiHandler=new UiHandler(BleMainActivity.this); mBtnOpen = findViewById(R.id.btn_open); mBtnSend = findViewById(R.id.btn_send); mBtnClosed = findViewById(R.id.btn_closed); mTvVersion = findViewById(R.id.tv_version); mRlUpgrade = findViewById(R.id.rl_upgrade); mProgressBar = findViewById(R.id.progressBar); mTvProgress = findViewById(R.id.tv_progress); mBtnUpgrade = findViewById(R.id.btn_upgrade); mTvName = findViewById(R.id.tv_name); mTvBelAddress = findViewById(R.id.tv_bel_address); mTxBleRequest = findViewById(R.id.tx_ble_request); mTxBleCallback = findViewById(R.id.tx_ble_callback); mTvYunState = findViewById(R.id.tv_yun_state); findViewById(R.id.btn_Connection).setOnClickListener(this); mBtnOpen.setOnClickListener(this); mBtnClosed.setOnClickListener(this); mBtnSend.setOnClickListener(this); mBtnUpgrade.setOnClickListener(this); } private void requestPermission() { PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(BleMainActivity.this, permissions, new PermissionsResultAction() { @Override public void onGranted() { Log.i("textLog","initBle >>>>>"); if(address.length()!=0) { try { mTvBelAddress.setText(address); mTvName.setText(devicesName); Log.i(TAG, "address : " +address + " devicesName : "+devicesName); icConnection = BleManager.getDefault().isCheckBleConnect(BleMainActivity.this, address); } catch (Exception e) { Log.i(TAG, "Exception : " +e); } } } @Override public void onDenied(String permission) { Log.i("textLog","permission >>>>>" + permission ); Toast.makeText(BleMainActivity.this, " 请申请:"+permission+"权限", Toast.LENGTH_SHORT).show(); } }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults); } FirmwareInfoImp mFirmwareInfoImp=null; @Override public void onClick(View v) { if(v.getId()==R.id.btn_closed) { if(!icConnection) { Toast.makeText(BleMainActivity.this, " 蓝牙未连接!", Toast.LENGTH_SHORT).show(); return; } if(bluetoothDeviceDialog!=null){ bluetoothDeviceDialog.dismiss(); } if(address.length()==0){ Toast.makeText(BleMainActivity.this, " 请选择蓝牙设备", Toast.LENGTH_SHORT).show(); return; } BleManager.getDefault().disconnect(); } else if(v.getId()==R.id.btn_open){ bluetoothDeviceDialog=new BluetoothDeviceDialog(BleMainActivity.this,this); bluetoothDeviceDialog.show(); } else if(v.getId()==R.id.btn_Connection){ if(address.length()==0) { Toast.makeText(BleMainActivity.this, " 请选择蓝牙设备", Toast.LENGTH_SHORT).show(); } else{ mTvState.setText("当前连接状态:连接中...."); mTxBleRequest.setText("发送等待发送。。。"); } icConnection= BleManager.getDefault().isCheckBleConnect(BleMainActivity.this,address); } else if(v.getId()==R.id.btn_send){ if(!icConnection) { Toast.makeText(BleMainActivity.this, " 蓝牙未连接!", Toast.LENGTH_SHORT).show(); return; } if(address.length()==0){ Toast.makeText(BleMainActivity.this, " 请选择蓝牙设备", Toast.LENGTH_SHORT).show(); return; } BleManager.getDefault().sendMessage(requestData ); } else if(v.getId()==R.id.btn_upgrade){ if(!icConnection) { Toast.makeText(BleMainActivity.this, " 蓝牙未连接!", Toast.LENGTH_SHORT).show(); return; } if(requestData!=null) { BleManager.getDefault().sendMessage(requestData); mFirmwareInfoImp.firmwareInfoToString(); } } } //发送的数据 @Subscribe(threadMode = ThreadMode.MAIN) public void onGetMessage(String requestCmdTxt) { Message message=uiHandler.obtainMessage(); Bundle bundle=new Bundle(); bundle.putString("requestCmdTxt",requestCmdTxt ); message.setData(bundle); message.what=UiHandler.UPGRADE_TXT_CMD; uiHandler.sendMessage(message); mRlUpgrade.setVisibility(View.VISIBLE); } //蓝牙回调数据 @Subscribe(threadMode = ThreadMode.MAIN) public void onGetMessage(byte[] data) { mTxBleCallback.setText(" 返回的串口指令: : " + HexDump.getInstance().toHexString(data) ); Log.i(TAG," 接收 当前指令:: : " + mTxBleCallback.getText().toString() ); int totalSize=data.length; int index=totalSize-4; //aa 55 07 00 84 e0 ff 6a ff if((data.length>4)&&(data[0]== BleControlConstant.HEADER_ONE)&&(data[1]== BleControlConstant.HEADER_TWO)&&(data[data.length-1]== BleControlConstant.REQUEST_FOOTER)) { StringBuilder stringBuilder=new StringBuilder(); byte cmd=data[index]; Log.i(TAG, "当前指令: " +HexDump.getInstance().toHexString(cmd) ); switch (cmd) { // aa 55 09 00 aa 55 07 00 84 e0 ff 6a ff case BleControlConstant.REQUEST_UPGRADE_CMD: if(data[index+1]==BleControlConstant.REQUEST_SUCCESS) { stringBuilder.append("请求成功"); Log.i(TAG, "请求成功 " ); } else{ Log.i(TAG, "请求失败! " ); stringBuilder.append("请求失败"); } break; case BleControlConstant.REQUEST_OAT_CMD: //aa 55 07 00 84 e3 00 6e ff byte currentFrameIndex=data[index+1]; int currentFrame= HexDump.getInstance().hexToInteger(currentFrameIndex); sendFrameData(currentFrame); break; } stringBuilder.append("发送指令格式正确"); mTvYunState.setText(stringBuilder.toString()); } else{ mTvYunState.setText("发送指令格式不正确"); Log.i(TAG, "发送指令格式不正确" ); } } /** * 发送每帧数据 * @param currentFrameIndex */ public void sendFrameData(int currentFrameIndex) { Log.i(TAG, "currentFrameIndex :"+currentFrameIndex+"frameTotalNum :"+frameTotalNum); if(currentFrameIndex < frameTotalNum ) { Message message=uiHandler.obtainMessage(); Bundle bundle=new Bundle(); EveryFrameMessage everyFrameMessage=mFrameHashMap.get(String.valueOf(currentFrameIndex)); bundle.putParcelable("everyFrameMessage",everyFrameMessage ); message.setData(bundle); message.what=UiHandler.UPGRADE_OTA; uiHandler.sendMessage(message); mRlUpgrade.setVisibility(View.VISIBLE); } else{ Log.i(TAG, "升级完成。。。"); mRlUpgrade.setVisibility(View.GONE); } } boolean icConnection=false; @Subscribe(threadMode = ThreadMode.MAIN) public void onGetMessage(Boolean flag) { this.icConnection=flag; String stateText =flag?"已连接":"已断开"; String stateText1 =flag?"可以发送数据。。。":"停止发送。。。"; mTxBleRequest.setText(stateText1); mTvState.setText("当前连接状态:" + stateText); } @Override protected void onResume() { super.onResume(); mTvState.setText("当前连接状态:" + "未链接"); mTxBleRequest.setText("等待发送。。。"); } BluetoothDeviceDialog bluetoothDeviceDialog=null; @Override public void choiceBluetoothDevice(BleDevice bleDevice) { address = bleDevice.getBluetoothDevice().getAddress(); devicesName = bleDevice.getBluetoothDevice().getName(); mTvBelAddress.setText(bleDevice.getBluetoothDevice().getAddress()); mTvName.setText(bleDevice.getBluetoothDevice().getName()); } @Override protected void onDestroy() { super.onDestroy(); uiHandler.removeCallbacksAndMessages(this); EventBus.getDefault().unregister(this); } @Override public void getFrameTotalNum(int totalNum) { setFrameTotalNum(totalNum); Log.i(TAG," frameTotalNum ==> " + frameTotalNum); } @Override public void getFilSize(long fileSize) { Log.i(TAG," fileSize ==> " + fileSize); } @Override public void getFileContentSize(long fileContentSize) { Log.i(TAG," fileContentSize ==> " + fileContentSize); } byte [] requestData=null; @Override public void getUpgradeRequest(String versionNum, byte[] data) { Message message=uiHandler.obtainMessage(); Bundle bundle=new Bundle(); bundle.putString("versionTxt", versionNum); message.setData(bundle); message.what=UiHandler.GET_VERSION; uiHandler.sendMessage(message); this.requestData=data; } HashMap<String, EveryFrameMessage> mFrameHashMap; @Override public void getFrameHashMap(HashMap<String, EveryFrameMessage> frameHashMap) { this.mFrameHashMap=frameHashMap; Log.i(TAG," frameHashMap.size ==> " +frameHashMap.size() ); } @Override public void firmwareInfoToString(StringBuilder stringBuilder) { Log.i(TAG," firmwareInfo ==> " +stringBuilder.toString() ); } @Override public void firmwareInfoException(Exception e) { Log.i(TAG, " Exception ==> " + e); } /** * 获取文件总帧数 * @param */ public int getFrameTotalNum() { return frameTotalNum; } private void setFrameTotalNum(int frameTotalNum) { this.frameTotalNum = frameTotalNum; } }
结束语:为了方便下伙伴快速上手蓝牙项目,我做上述代码封装一个蓝牙库,方便小伙伴使用
文中展示了主要代码,获取源码请:点击这里