Nordic DFU安卓空中升级

  • 增加依赖库

api 'no.nordicsemi.android:dfu:1.6.1'

  • 增加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />

  • 安卓6以上动态申请权限

private void checkPermissions(){

    String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE
};
    List<String> permissionDeniedList = new ArrayList<>();
    for (String permission : permissions) {
        int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
        if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
            onPermissionGranted(permission);
        } else {
            permissionDeniedList.add(permission);
        }
    }
    if (!permissionDeniedList.isEmpty()) {
        String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
        ActivityCompat.requestPermissions(this, deniedPermissions, 12);
    }

  • }

  • 创建一个DFU服务继承于DfuBaseService
package com.google.jzhou.dfutest.dfu_service;

import android.app.Activity;
import android.content.Intent;
import android.os.IBinder;


import no.nordicsemi.android.dfu.BuildConfig;
import no.nordicsemi.android.dfu.DfuBaseService;

public class DfuService extends DfuBaseService {

    @Override
    protected Class<? extends Activity> getNotificationTarget() {
       return NotificationActivity.class;
    }

    @Override
    protected boolean isDebug() {
        return BuildConfig.DEBUG;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
       return null;
    }
}
  • 创建一个NotificationAcitivy
package com.google.jzhou.dfutest.dfu_service;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;


import com.google.jzhou.dfutest.BaseActivity;
import com.google.jzhou.dfutest.DfuUpdateActivity;

public class NotificationActivity extends BaseActivity {

    @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, DfuUpdateActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Bundle bundle = getIntent().getExtras();
            if(bundle != null) {
                intent.putExtras(bundle); // 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();
    }
}

  • 创建一个DfuUpdateActivity,使用按键加载升级文件

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 1);
  • 在onActivityResult中处理升级业务逻辑
 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            Uri uri = data.getData();

            if (uri == null)
                return;
            if ("file".equalsIgnoreCase(uri.getScheme())) {//使用第三方应用打开
                path = uri.getPath();

            } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后
                path = getPath(this, uri);

            } else {//4.4以下下系统调用方法
                path = getRealPathFromURI(uri);

            }
            tv_show.setText(path);
            if (requestCode == 1) {
                progressBar.setVisibility(View.VISIBLE);
                final DfuServiceInitiator starter = new DfuServiceInitiator(dfu_macAddress)
                        .setDeviceName(mBluetoothService.getName())
                        .setKeepBond(true);


// If you want to have experimental buttonless DFU feature supported call additionally:
                starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
// but be aware of this: https://devzone.nordicsemi.com/question/100609/sdk-12-bootloader-erased-after-programming/
// and other issues related to this experimental service.

// 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(uri, path);
//            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.


//            DfuServiceInitiator.createDfuNotificationChannel(this);
            }
        }
    }
  • 定义DFU升级监听
    private final DfuProgressListener dfuProgressListener = new DfuProgressListener() {
        @Override
        public void onDeviceConnecting(String deviceAddress) {
//          progressBar.setIndeterminate(true);
//          mTextPercentage.setText(R.string.dfu_status_connecting);
            Log.i("TEST", "onDeviceConnecting: " + deviceAddress);
        }

        @Override
        public void onDeviceConnected(String deviceAddress) {
            Log.i("TEST", "onDeviceConnected: " + deviceAddress);
        }

        @Override
        public void onDfuProcessStarting(String deviceAddress) {
//          progressBar.setIndeterminate(true);
//          mTextPercentage.setText(R.string.dfu_status_starting);
            Log.i("TEST", "onDfuProcessStarting: " + deviceAddress);


        }

        @Override
        public void onDfuProcessStarted(String deviceAddress) {
            Log.i("TEST", "onDfuProcessStarted: " + deviceAddress);
        }

        @Override
        public void onEnablingDfuMode(String deviceAddress) {
            Log.i("TEST", "onEnablingDfuMode: " + deviceAddress);
        }

        @Override
        public void onProgressChanged(String deviceAddress, int percent, float speed, float avgSpeed, int currentPart, int partsTotal) {
            Log.i("TEST", "onProgressChanged: " + deviceAddress + "百分比" + percent + ",speed "
                    + speed + ",avgSpeed " + avgSpeed + ",currentPart " + currentPart
                    + ",partTotal " + partsTotal);
            tv_show.setText("升级进度:" + percent + "%");
        }

        @Override
        public void onFirmwareValidating(String deviceAddress) {
            Log.i("TEST", "onFirmwareValidating: " + deviceAddress);
        }

        @Override
        public void onDeviceDisconnecting(String deviceAddress) {
            Log.i("TEST", "onDeviceDisconnecting: " + deviceAddress);
        }

        @Override
        public void onDeviceDisconnected(String deviceAddress) {
            Log.i("TEST", "onDeviceDisconnected: " + deviceAddress);
        }

        @Override
        public void onDfuCompleted(String deviceAddress) {
            Log.i("TEST", "onDfuCompleted: " + deviceAddress);
//          progressBar.setIndeterminate(true);
            progressBar.setVisibility(View.GONE);
        }

        @Override
        public void onDfuAborted(String deviceAddress) {
            Log.i("TEST", "onDfuAborted: " + deviceAddress);
            progressBar.setVisibility(View.GONE);
        }

        @Override
        public void onError(String deviceAddress, int error, int errorType, String message) {
            Log.i("TEST", "onError: " + deviceAddress + ",message:" + message);
            progressBar.setVisibility(View.GONE);
        }
    };
  • 在onResume中注册监听
@Override
protected void onResume() {
    super.onResume();
    DfuServiceListenerHelper.registerProgressListener(this, dfuProgressListener);
}
  • 在onPause中取消监听
@Override
protected void onPause() {
    super.onPause();
    DfuServiceListenerHelper.unregisterProgressListener(this, dfuProgressListener);
}

  • 总结:升级处理只需四步即可

  • final DfuServiceInitiator starter = new DfuServiceInitiator(dfu_macAddress)
            .setDeviceName(mBluetoothService.getName())
            .setKeepBond(true);
    参数dfu_macAddress:扫描到的蓝牙MAC地址
     参数mBluetoothService.getName():扫描到的蓝牙设备名称
     参数true/false: 是否保持设备绑定

  • starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
    调用此方法使Nordic nrf52832进入bootloader模式
  • starter.setZip(uri, path);
    调用此方法设置升级文件
  • final DfuServiceController controller = starter.start(this, DfuService.class);
     调用此方法启动升级服务进行升级

源码下载地址:https://download.csdn.net/download/mygod2008ok/10538088

猜你喜欢

转载自blog.csdn.net/mygod2008ok/article/details/80711243