1.dfu升级功能要借助第三方库 所以我们首先要依赖
implementation 'no.nordicsemi.android:dfu:1.9.0'
2.然后第二步,我们需要创建两个类,具体如下
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();
}
}
public 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();
}
}
3:接下里第三步就是升级逻辑了 这里整理了一个工具类
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); //监听升级进度
}
//开始升级
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));
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
*/
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:到这里主要升级逻辑就完成了,不过还有注意事项!!!
1)权限的添加
<!-- 在android6.0以后,蓝牙BLE还需要需要获得位置权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
有的版本高 升级前需要动态获取
//检测蓝牙扫描权限
@Override
public void checkSelfPermission() {
if (ContextCompat.checkSelfPermission(Objects.requireNonNull(this), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 申请定位授权
ActivityCompat.requestPermissions(Objects.requireNonNull(this),
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
} else {
//处理升级逻辑
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//处理升级逻辑
}
} else{
ToastUtils.showShort(this,getResources().getString(R.string.scan_no_location));
}
break;
}
}
2)还有一点别忘记在manifests文件注册dfu服务
<service android:name=".dfu.DfuService"
android:exported="true">
<intent-filter>
<action android:name="no.nordicsemi.android.action.DFU_UPLOAD" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
5:最后一步 就是简单使用 在你使用的类里面 implements DfuProgressListener
//先注册进度以及升级状态回调
DfuUtils.getInstance().setmDfuProgressListener(mContext,this);//升级状态回调
//开始正式升级
DfuUtils.getInstance().startUpdate(mContext,mac,deviceName,mDevicePath);
//实现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 是进度 在这里可以展示进度条
}
@Override
public void onFirmwareValidating(String deviceAddress) {
}
@Override
public void onDeviceDisconnecting(String deviceAddress) {
}
@Override
public void onDeviceDisconnected(String deviceAddress) {
}
@Override
public void onDfuCompleted(String 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.
}
@Override
public void onError(String deviceAddress, int error, int errorType, String message) {
//升级错误
}
6.end 有问题可以留言 看见了回复。