• android nordic OTA 升级


    根据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

     

    根据NORDIC官方Android-DFU-Library实现,具体步骤如下:

    1、build.gradle配置

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

    2、AndroidMainfest.xml中申请BLE的相关权限、读写权限、定位等。

    1.  
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    2.  
      <uses-permission android:name="android.permission.CAMERA" />
    3.  
      <uses-permission android:name="android.permission.BLUETOOTH" />
    4.  
      <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    5.  
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    6.  
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    7.  
      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    3、创建DfuService,实现 getNotificationTarget() 方法, 在进行DFU时,该方法会返回一个活动类 ,该活动通过Intent ,FLAG_ACTIVITY_NEW_TASK标志开启,下面步骤是定义的具体活动类。

    1.  
      public class DfuService extends DfuBaseService {
    2.  
       
    3.  
       
    4.  
      public DfuService() {
    5.  
      }
    6.  
       
    7.  
      @Nullable
    8.  
      @Override
    9.  
      protected Class<? extends Activity> getNotificationTarget() {
    10.  
      /*
    11.  
      * As a target activity the NotificationActivity is returned, not the MainActivity. This is because
    12.  
      * the notification must create a new task:
    13.  
      *
    14.  
      * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    15.  
      *
    16.  
      * when you press it. You can use NotificationActivity to check whether the new activity
    17.  
      * is a root activity (that means no other activity was open earlier) or that some
    18.  
      * other activity is already open. In the latter case the NotificationActivity will just be
    19.  
      * closed. The system will restore the previous activity. However, if the application has been
    20.  
      * closed during upload and you click the notification, a NotificationActivity will
    21.  
      * be launched as a root activity. It will create and start the main activity and
    22.  
      * terminate itself.
    23.  
      *
    24.  
      * This method may be used to restore the target activity in case the application
    25.  
      * was closed or is open. It may also be used to recreate an activity history using
    26.  
      * startActivities(...).
    27.  
      */
    28.  
      return NotificationActivity.class;
    29.  
      }
    30.  
       
    31.  
      @Override
    32.  
      public IBinder onBind(Intent intent) {
    33.  
      // TODO: Return the communication channel to the service.
    34.  
      throw new UnsupportedOperationException("Not yet implemented");
    35.  
      }
    36.  
      }

    4、创建NotificationActivity类,继承自Activity,该类主要用于组织APP的其他实例启动。

    1.  
      public class NotificationActivity extends Activity {
    2.  
      @Override
    3.  
      protected void onCreate(@Nullable Bundle savedInstanceState) {
    4.  
      super.onCreate(savedInstanceState);
    5.  
       
    6.  
      // If this activity is the root activity of the task, the app is not running
    7.  
      if (isTaskRoot()) {
    8.  
      // Start the app before finishing
    9.  
      final Intent intent = new Intent(this, MineDfuActivity.class);
    10.  
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    11.  
      intent.putExtras(getIntent().getExtras()); // copy all extras
    12.  
      startActivity(intent);
    13.  
      }
    14.  
       
    15.  
      // Now finish, which will drop you to the activity at which you were at the top of the task stack
    16.  
      finish();
    17.  
       
    18.  
       
    19.  
      }
    20.  
      }

    5、开启DFU服务

    1.  
      final DfuServiceInitiator starter = new DfuServiceInitiator(MineDeviceActivity.bleDevice.getMac())
    2.  
      .setDeviceName(MineDeviceActivity.bleDevice.getName());
    3.  
      // If you want to have experimental buttonless DFU feature supported call additionally:starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
    4.  
      String fileName = urlDfuPackage.substring(urlDfuPackage.lastIndexOf("/"));
    5.  
      String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
    6.  
       
    7.  
      starter.setZip(directory + fileName);
    8.  
      final DfuServiceController controller = starter.start(MyApplication.getContext(), DfuService.class);
    9.  
       
    10.  
      //以下是NORDIC DEMO分文件包的格式进行不同处理,我的直接是在固定存储路径下压缩包文件,所以就按照以上写了,以下供参考
    11.  
      // Init packet is required by Bootloader/DFU from SDK 7.0+ if HEX or BIN file is given above.
    12.  
      // In case of a ZIP file, the init packet (a DAT file) must be included inside the ZIP file.
    13.  
      if (mFileType == DfuService.TYPE_AUTO)
    14.  
      starter.setZip(mFileStreamUri, mFilePath);
    15.  
      else {
    16.  
      starter.setBinOrHex(mFileType, mFileStreamUri, mFilePath).setInitFile(mInitFileStreamUri, mInitFilePath);
    17.  
      }
    18.  
      final DfuServiceController controller = starter.start(this, DfuService.class);
    19.  
      // You may use the controller to pause, resume or abort the DFU process.

    6、以上步骤完成了DFU过程,但是我们拿单板和APP测试也看不到DFU的过程,所以还需要创建DFU进度监听器,可以掌握DFU的动态情况,比如可以在界面显示DFU进度等。

    1.  
      //DFU进度监听器
    2.  
      private final DfuProgressListener mDfuProgressListener = new DfuProgressListenerAdapter(){
    3.  
       
    4.  
      @Override
    5.  
      public void onDeviceConnecting(final String deviceAddress) {
    6.  
      relativeDfuProgress.setVisibility(View.VISIBLE);
    7.  
       
    8.  
      }
    9.  
       
    10.  
      @Override
    11.  
      public void onDfuProcessStarting(final String deviceAddress) {
    12.  
      relativeDfuProgress.setVisibility(View.VISIBLE);
    13.  
      }
    14.  
       
    15.  
      @Override
    16.  
      public void onEnablingDfuMode(final String deviceAddress) {
    17.  
      relativeDfuProgress.setVisibility(View.VISIBLE);
    18.  
       
    19.  
      }
    20.  
       
    21.  
      @Override
    22.  
      public void onFirmwareValidating(final String deviceAddress) {
    23.  
      relativeDfuProgress.setVisibility(View.VISIBLE);
    24.  
       
    25.  
      }
    26.  
       
    27.  
      @Override
    28.  
      public void onDeviceDisconnecting(final String deviceAddress) {
    29.  
      relativeDfuProgress.setVisibility(View.VISIBLE);
    30.  
       
    31.  
      }
    32.  
       
    33.  
      @Override
    34.  
      public void onDfuCompleted(final String deviceAddress) {
    35.  
      Toast.makeText(MineDfuActivity.this,"固件升级成功",Toast.LENGTH_SHORT).show();
    36.  
      // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
    37.  
      new Handler().postDelayed(new Runnable() {
    38.  
      @Override
    39.  
      public void run() {
    40.  
      // onTransferCompleted();
    41.  
       
    42.  
      // if this activity is still open and upload process was completed, cancel the notification
    43.  
      final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    44.  
      manager.cancel(DfuService.NOTIFICATION_ID);
    45.  
      }
    46.  
      }, 200);
    47.  
      }
    48.  
       
    49.  
      @Override
    50.  
      public void onDfuAborted(final String deviceAddress) {
    51.  
      // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again.
    52.  
      new Handler().postDelayed(new Runnable() {
    53.  
      @Override
    54.  
      public void run() {
    55.  
      // onUploadCanceled();
    56.  
       
    57.  
      // if this activity is still open and upload process was completed, cancel the notification
    58.  
      final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    59.  
      manager.cancel(DfuService.NOTIFICATION_ID);
    60.  
      }
    61.  
      }, 200);
    62.  
      }
    63.  
       
    64.  
      @Override
    65.  
      public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) {
    66.  
       
    67.  
      int temp = (percent * 360)/100;
    68.  
      circleDfuProgress.update(temp,"");
    69.  
       
    70.  
      // if (partsTotal > 1)
    71.  
      // mTextUploading.setText(getString(R.string.dfu_status_uploading_part, currentPart, partsTotal));
    72.  
      // else
    73.  
      // mTextUploading.setText(R.string.dfu_status_uploading);
    74.  
      }
    75.  
       
    76.  
      @Override
    77.  
      public void onError(final String deviceAddress, final int error, final int errorType, final String message) {
    78.  
      // showErrorMessage(message);
    79.  
       
    80.  
      // We have to wait a bit before canceling notification. This is called before DfuService creates the last notification.
    81.  
      new Handler().postDelayed(new Runnable() {
    82.  
      @Override
    83.  
      public void run() {
    84.  
      // if this activity is still open and upload process was completed, cancel the notification
    85.  
      final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    86.  
      manager.cancel(DfuService.NOTIFICATION_ID);
    87.  
      }
    88.  
      }, 200);
    89.  
      }
    90.  
      };

    7、在当前活动中重写onResume及onPause方法,分别进行监听器的注册和取消注册。

    1.  
      @Override
    2.  
      protected void onResume() {
    3.  
      super.onResume();
    4.  
      DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener);
    5.  
       
    6.  
      }
    7.  
       
    8.  
      @Override
    9.  
      protected void onPause() {
    10.  
      super.onPause();
    11.  
      DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener);
    12.  
       
    13.  
      }

    【参考】

    https://github.com/NordicSemiconductor/Android-DFU-Library/tree/release/documentation

  • 相关阅读:
    php知识点
    CommonsChunkPlugin知识点
    待学习
    svn知识点
    es6知识点
    webpack2新特性
    排序算法
    交流措辞
    js继承
    多行编辑软件
  • 原文地址:https://www.cnblogs.com/rocksmall/p/14252695.html
Copyright © 2020-2023  润新知