DFU升级应该是常见固件升级方式里最简单的一种,直接使用Nordic官方提供的库。
实现步骤:
-
implementation 'no.nordicsemi.android:dfu:2.4.1'
- 创建NotificationActivity
public class NotificationActivity extends Activity { @Override protected void onCreate(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 } // Now finish, which will drop the user in to the activity that was at the top // of the task stack finish(); } }
-
创建DfuService
public class DfuService extends DfuBaseService { @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 user press it. Using NotificationActivity we can check whether the new activity is a root activity (that means no other activity was open before) * or that there is other activity already open. In the later case the notificationActivity will just be closed. System will restore the previous activity. * However if the application has been closed during upload and user 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 (see NotificationActivity). */ return NotificationActivity.class; } }
- 在AndroidManifest中配置
<service android:name="${packageName}.DfuService" android:exported="true" android:label="nRF Toolbox DFU Proxy"> <intent-filter> <action android:name="no.nordicsemi.android.action.DFU_UPLOAD" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> <activity android:name="${packageName}.NotificationActivity" android:label="DFU" />
- 开始升级
/** * @param mac 设备mac地址 * @param path 已经下载好的zip升级文件本地路径 */ fun addDeviceAndStartUpdate(mac: String, path: String) { if (mac.isNotEmpty() && BleManager.instance.mContext != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { DfuServiceInitiator.createDfuNotificationChannel(BleManager.instance.mContext!!) } DfuServiceListenerHelper.registerProgressListener( MdBleManager.instance.mContext!!, this ) val starter = DfuServiceInitiator(mac) .setKeepBond(true) .setForceDfu(false) .setPacketsReceiptNotificationsEnabled(false) .setPacketsReceiptNotificationsValue(12) .setPrepareDataObjectDelay(300) .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true) starter.setZip(path) starter.start(BleManager.instance.mContext!!, DfuService::class.java) } else { updateFail("mac或BleManager.instance.mContext为空") } }
- 实现DfuProgressListener接口的回调,监听升级过程、结果、异常上报。
注意:Android targetSdkVersion适配到30及以上,集成版本必须大于等于V2.4.1,否则调用升级会有闪退现象,并且启动升级service的时候,需要主动开启通知。