Android藍牙固件升級 DFU-OTA 固件升級


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);//升級狀態回調

    }

 

加油!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM