Android 低功耗蓝牙详解

与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许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;
    }

}

结束语:为了方便下伙伴快速上手蓝牙项目,我做上述代码封装一个蓝牙库,方便小伙伴使用

       文中展示了主要代码,获取源码请:点击这里

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值