Android——NORDIC nRF5x系列 DFU升级 APP实现
时间:2022-07-25
本文章向大家介绍Android——NORDIC nRF5x系列 DFU升级 APP实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
根据NORDIC官方Android-DFU-Library实现,具体步骤如下:
1、build.gradle配置
implementation 'no.nordicsemi.android:dfu:1.9.0'
2、AndroidMainfest.xml中申请BLE的相关权限、读写权限、定位等。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
3、创建DfuService,实现 getNotificationTarget()
方法, 在进行DFU时,该方法会返回一个活动类 ,该活动通过Intent ,FLAG_ACTIVITY_NEW_TASK标志开启,下面步骤是定义的具体活动类。
public class DfuService extends DfuBaseService {
public DfuService() {
}
@Nullable
@Override
protected Class<? extends Activity> getNotificationTarget() {
/*
* As a target activity the NotificationActivity is returned, not the MainActivity. This is because
* the notification must create a new task:
*
* intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
*
* when you press it. You can use NotificationActivity to check whether the new activity
* is a root activity (that means no other activity was open earlier) or that some
* other activity is already open. In the latter case the NotificationActivity will just be
* closed. The system will restore the previous activity. However, if the application has been
* closed during upload and you click the notification, a NotificationActivity will
* be launched as a root activity. It will create and start the main activity and
* terminate itself.
*
* This method may be used to restore the target activity in case the application
* was closed or is open. It may also be used to recreate an activity history using
* startActivities(...).
*/
return NotificationActivity.class;
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
4、创建NotificationActivity类,继承自Activity,该类主要用于组织APP的其他实例启动。
public class NotificationActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot()) {
// Start the app before finishing
final Intent intent = new Intent(this, MineDfuActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtras(getIntent().getExtras()); // copy all extras
startActivity(intent);
}
// Now finish, which will drop you to the activity at which you were at the top of the task stack
finish();
}
}
5、开启DFU服务
final DfuServiceInitiator starter = new DfuServiceInitiator(MineDeviceActivity.bleDevice.getMac())
.setDeviceName(MineDeviceActivity.bleDevice.getName());
// If you want to have experimental buttonless DFU feature supported call additionally:starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
String fileName = urlDfuPackage.substring(urlDfuPackage.lastIndexOf("/"));
String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
starter.setZip(directory + fileName);
final DfuServiceController controller = starter.start(MyApplication.getContext(), DfuService.class);
//以下是NORDIC DEMO分文件包的格式进行不同处理,我的直接是在固定存储路径下压缩包文件,所以就按照以上写了,以下供参考
// Init packet is required by Bootloader/DFU from SDK 7.0+ if HEX or BIN file is given above.
// In case of a ZIP file, the init packet (a DAT file) must be included inside the ZIP file.
if (mFileType == DfuService.TYPE_AUTO)
starter.setZip(mFileStreamUri, mFilePath);
else {
starter.setBinOrHex(mFileType, mFileStreamUri, mFilePath).setInitFile(mInitFileStreamUri, mInitFilePath);
}
final DfuServiceController controller = starter.start(this, DfuService.class);
// You may use the controller to pause, resume or abort the DFU process.
6、以上步骤完成了DFU过程,但是我们拿单板和APP测试也看不到DFU的过程,所以还需要创建DFU进度监听器,可以掌握DFU的动态情况,比如可以在界面显示DFU进度等。
//DFU进度监听器
private final DfuProgressListener mDfuProgressListener = new DfuProgressListenerAdapter(){
@Override
public void onDeviceConnecting(final String deviceAddress) {
relativeDfuProgress.setVisibility(View.VISIBLE);
}
@Override
public void onDfuProcessStarting(final String deviceAddress) {
relativeDfuProgress.setVisibility(View.VISIBLE);
}
@Override
public void onEnablingDfuMode(final String deviceAddress) {
relativeDfuProgress.setVisibility(View.VISIBLE);
}
@Override
public void onFirmwareValidating(final String deviceAddress) {
relativeDfuProgress.setVisibility(View.VISIBLE);
}
@Override
public void onDeviceDisconnecting(final String deviceAddress) {
relativeDfuProgress.setVisibility(View.VISIBLE);
}
@Override
public void onDfuCompleted(final String deviceAddress) {
Toast.makeText(MineDfuActivity.this,"固件升级成功",Toast.LENGTH_SHORT).show();
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// onTransferCompleted();
// if this activity is still open and upload process was completed, cancel the notification
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(DfuService.NOTIFICATION_ID);
}
}, 200);
}
@Override
public void onDfuAborted(final String deviceAddress) {
// let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// onUploadCanceled();
// if this activity is still open and upload process was completed, cancel the notification
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(DfuService.NOTIFICATION_ID);
}
}, 200);
}
@Override
public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) {
int temp = (percent * 360)/100;
circleDfuProgress.update(temp,"");
// if (partsTotal > 1)
// mTextUploading.setText(getString(R.string.dfu_status_uploading_part, currentPart, partsTotal));
// else
// mTextUploading.setText(R.string.dfu_status_uploading);
}
@Override
public void onError(final String deviceAddress, final int error, final int errorType, final String message) {
// showErrorMessage(message);
// We have to wait a bit before canceling notification. This is called before DfuService creates the last notification.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// if this activity is still open and upload process was completed, cancel the notification
final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(DfuService.NOTIFICATION_ID);
}
}, 200);
}
};
7、在当前活动中重写onResume及onPause方法,分别进行监听器的注册和取消注册。
@Override
protected void onResume() {
super.onResume();
DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener);
}
@Override
protected void onPause() {
super.onPause();
DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener);
}
【参考】
https://github.com/NordicSemiconductor/Android-DFU-Library/tree/release/documentation
- 【Java学习笔记之十二】Java8增强的工具类:Arrays的用法整理总结
- 利用insert,update和delete注入获取数据
- 【机器学习笔记之二】决策树的python实现
- 【Java学习笔记之十三】初探Java面向对象的过程及代码实现
- 洛谷 P1308 统计单词数【字符串+模拟】
- 【Java学习笔记之十四】Java中this用法小节
- Codeforces 839E Mother of Dragons【__builtin_popcount()的使用】
- 【Java学习笔记之十五】Java中的static关键字解析
- Codeforces 839D Winter is here【数学:容斥原理】
- Codeforces 839C Journey【DFS】
- Facebook的漏洞可以让攻击者在分分钟内重置用户账户密码
- 【Java学习笔记之十七】Java中普通代码块,构造代码块,静态代码块区别及代码示例分析
- 【机器学习笔记之六】Bagging 简述
- 洛谷 P1553 数字反转(升级版)【字符串+STL stack】
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Nodejs 一些细节 (持续更新)
- Jenkins 凭据使用
- React源码解读【一】API复习与基础
- choco 安装 和 mkcert 本地https
- js 函数柯里化(Currying)
- GPS数据Python解析及地图可视化
- 文稿:Ant Design从无到有,带你体悟大厂前端开发范式
- 在React中实现和Vue一样舒适的keep-alive
- uniapp获取接口数据,渲染在picker选择器里面
- 我们是这样一步一步实现分布式锁的
- 缓存并发神技,如何通过双 key 来解决缓存并发问题?
- LRU缓存淘汰算法实现方案,这次没人再说你不会开发
- JVM技术总结之三——类加载机制
- 为什么你每次被问到HashMap底层原理都一知半解,搞定它
- 要想精通java,你必须得知道java的内存模型,不忽悠