首页 > 技术文章 > Android蓝牙固件升级 DFU-OTA 固件升级

finn21 2021-09-23 14:40 原文

1、添加 依赖包:

implementation 'no.nordicsemi.android:dfu:1.11.0'

2、DfuService类继承  DfuBaseService

package com.example.ycblesdkdemo.dfu;

import android.app.Activity;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import no.nordicsemi.android.dfu.DfuBaseService;

/**
 * @author Finn_ZENGYUAN
 * Blog:https://www.cnblogs.com/finn21/
 * @date :2021/9/23 11:49
 * @description:
 */
public class DfuService extends DfuBaseService {


    @Override
    protected Class<? extends Activity> getNotificationTarget() {
        return NotificationActivity.class;
    }

    @Override
    protected boolean isDebug() {
        return true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

 class NotificationActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        if (isTaskRoot()) {
//            // Start the app before finishing
//            final Intent intent = new Intent(this, UpdateZipActivity.class);
//            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//            intent.putExtras(getIntent().getExtras()); // copy all extras
//            startActivity(intent);
//        }
//
//        finish();
    }
}
View Code

3、添加工具类  DfuUtils

package com.example.ycblesdkdemo.dfu;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;


import no.nordicsemi.android.dfu.DfuProgressListener;
import no.nordicsemi.android.dfu.DfuServiceController;
import no.nordicsemi.android.dfu.DfuServiceInitiator;
import no.nordicsemi.android.dfu.DfuServiceListenerHelper;

import static android.content.Context.ACTIVITY_SERVICE;

/**
 * @author Finn_ZENGYUAN
 * Blog:https://www.cnblogs.com/finn21/
 * @date :2021/9/23 11:45
 * @description:
 */
public class DfuUtils {

    private static DfuUtils dfuUtils;
    private DfuServiceController serviceController;
    private DfuServiceInitiator starter;

    public static DfuUtils getInstance() {
        if (dfuUtils == null) {
            synchronized (DfuUtils.class) {
                if (dfuUtils == null) {
                    dfuUtils = new DfuUtils();

                }
            }
        }
        return dfuUtils;
    }

    public void setmDfuProgressListener(Context mContext, DfuProgressListener dfuProgressListener) {
        DfuServiceListenerHelper.registerProgressListener(mContext, dfuProgressListener); //监听升级进度
    }

    //开始升级

    /**
     *
     * @param mContext
     * @param deviceMac  蓝牙mAC地址
     * @param deviceName 蓝牙名称
     * @param mDeviceZipFilePath  要升级的固件的地址
     */
    public void startUpdate(Context mContext, String deviceMac, String deviceName, String mDeviceZipFilePath) {
        if (mDeviceZipFilePath == null) {
//            ToastUtils.showShort(mContext, mContext.getResources().getString(R.string.update_no_path));
            Log.e("升级","开始升级");
            return;
        }
        //闪退问题解决 兼容   启动前台通知的问题,因为这个库在升级的时候会在通知栏显示进度,
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            DfuServiceInitiator.createDfuNotificationChannel(mContext);
        }

        starter = new DfuServiceInitiator(deviceMac)
                .setDeviceName(deviceName)//设备名称
                .setKeepBond(false)//保持设备绑定 官方demo为false
                .setForceDfu(false)
                .setPacketsReceiptNotificationsEnabled(false)
                .setPacketsReceiptNotificationsValue(12)
                .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);//官方ndemo为true
        // If you want to have experimental buttonless DFU feature supported call additionally:
        starter.setZip(mDeviceZipFilePath);
        serviceController = starter.start(mContext, DfuService.class); //启动升级服务
    }

    //暂停升级
    public void pauseDevice(Context mContext) {
        if (isDfuServiceRunning(mContext) && serviceController != null) {
            serviceController.pause();
        }
    }

    //销毁升级
    public void abortDevice(Context mContext) {
        if (isDfuServiceRunning(mContext) && serviceController != null) {
            serviceController.abort();
        }
    }

    /**
     * 判断dfu状态
     *
     * @return
     */
    @SuppressLint("NewApi")
    private boolean isDfuServiceRunning(Context mContext) {
        final ActivityManager manager = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (DfuService.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    //退出 dfu
    public void dispose(Context mContext,DfuProgressListener dfuProgressListener) {
        DfuServiceListenerHelper.unregisterProgressListener(mContext, dfuProgressListener);
        if (isDfuServiceRunning(mContext)) {
            if (serviceController != null) {
                serviceController.abort();
                mContext.stopService(new Intent(mContext, DfuService.class));
            }
        }
        if (starter != null) {
            starter = null;
        }
        if (serviceController != null) {
            serviceController = null;
        }
    }

}

 

4、当前Activity  继承  DfuProgressListener 实现方法如下

    //实现DfuProgressListener的回调函数
    @Override
    public void onDeviceConnecting(String deviceAddress) {
    }

    @Override
    public void onDeviceConnected(String deviceAddress) {
    }


    @Override
    public void onDfuProcessStarting(String deviceAddress) {
    }

    @Override
    public void onDfuProcessStarted(String deviceAddress) {

    }

    @Override
    public void onEnablingDfuMode(String deviceAddress) {

    }

    @Override
    public void onProgressChanged(String deviceAddress, int percent, float speed, float avgSpeed, int currentPart, int partsTotal) {
        //percent 是进度 在这里可以展示进度条
        Log.e("升级",deviceAddress+"升级进度 "+percent+"===="+speed+"===="+avgSpeed+"===="+currentPart+"===="+partsTotal);
    }

    @Override
    public void onFirmwareValidating(String deviceAddress) {

    }

    @Override
    public void onDeviceDisconnecting(String deviceAddress) {

    }

    @Override
    public void onDeviceDisconnected(String deviceAddress) {

    }

    @Override
    public void onDfuCompleted(String deviceAddress) {
        //升级成功
        Log.e("升级",deviceAddress+"升级成功");
    }

    @Override
    public void onDfuAborted(String deviceAddress) {
        //升级流产,失败
        // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
        //升级错误
        Log.e("升级",deviceAddress+"升级失败");
    }

    @Override
    public void onError(String deviceAddress, int error, int errorType, String message) {
        //升级错误
        Log.e("升级",deviceAddress+"升级错误"+error+"===="+errorType+"===="+message);
    }

5、开始,退出升级调用:

 private void DfuLoad(){//开始升级
      //先注册进度以及升级状态回调
      DfuUtils.getInstance().setmDfuProgressListener(mContext,this);//升级状态回调
//开始正式升级
      DfuUtils.getInstance().startUpdate(mContext,macVal,localName,filepathval);

  }
    private void OutDfuLoad(){//退出升级
        DfuUtils.getInstance().dispose(mContext,this);//升级状态回调

    }

 

加油!

推荐阅读