蓝牙ble实现空中升级功能

这阵子比较懒也比较忙,回到家里就不想弄代码0.0   博客也好久没更新。实在抱歉。这阵子公司App需要实现空中升级的功能。在网上也找了好久毫无头绪。偶然看到了nRF 工具箱的源码。翻了翻,终于把它实现了。今天就来说说空中升级的实现。

首先我们需要往项目的build.gradle文件中导入我们空中升级所需要的第三方包:

加入如下代码即可compile “no.nordicsemi.android:dfu:0.6.2”

然后我们先看下布局




    

        

            

            
        

        



    

    
        
        
    
    
        
        
    
    

    


这里只是一个显示文件名和文件大小的TextView 和一个progress进度条和一个开始空中升级的TextView。

这里的话是点击开始升级,然后发指令给手环,之后手环返回确认升级的指令,收到之后才开始空中升级,这里的话收到手环返回的指令我是用广播来弄的。

具体看下面代码:

/**
 * Created by Administrator on 2016/11/15.
 */
public class AirUpgradeActivity extends BaseActivity {

    private static final String TAG = "AirUpgradeActivity";
    private TextView fileName,fileSize,airUpgrade;
    private ProgressBar proBar;
    private String filePath;
    private String address,deviceName;
    private MySharePreference sp;
    private AirUpgradeReceiver receiver;

    //空中升级时的监听
    private final DfuProgressListener dfuProgressListener = new DfuProgressListener() {
        @Override
        public void onDeviceConnecting(String deviceAddress) {
            proBar.setIndeterminate(true);
        }
        //设备开始连接
        @Override
        public void onDeviceConnected(String deviceAddress) {
            proBar.setIndeterminate(true);
        }
        //升级准备开始的时候调用
        @Override
        public void onDfuProcessStarting(String deviceAddress) {
            proBar.setIndeterminate(true);
        }
        //设备开始升级
        @Override
        public void onDfuProcessStarted(String deviceAddress) {
            proBar.setIndeterminate(true);
        }

        @Override
        public void onEnablingDfuMode(String deviceAddress) {
            proBar.setIndeterminate(true);
        }
        //升级过程中的回调
        @Override
        public void onProgressChanged(String deviceAddress, int percent, float speed, float avgSpeed, int currentPart, int partsTotal) {
            proBar.setIndeterminate(false);
            proBar.setProgress(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) {
            Toast.makeText(AirUpgradeActivity.this,getString(R.string.upgradesuccess),Toast.LENGTH_SHORT).show();
            proBar.setIndeterminate(false);
        }

        @Override
        public void onDfuAborted(String deviceAddress) {
            proBar.setIndeterminate(false);
        }
        //升级失败
        @Override
        public void onError(String deviceAddress, int error, int errorType, String message) {
            Log.e(TAG,"ERROR"+error+"message"+message);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.air_upgrade_activity);
        getActionBar().hide();
        //注册空中升级的监听
        DfuServiceListenerHelper.registerProgressListener(this, dfuProgressListener);
        initView();
        receiver = new AirUpgradeReceiver();//这里是收到手环确认升级时的广播监听
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.airupgrade.action");
        registerReceiver(receiver, filter);

        sp = new MySharePreference(this);
        address = sp.getDeviceAddress();
        deviceName = sp.getDeviceName();

        try {
            copyBigDataToSD("/mnt/sdcard/KeeFit/IR16506084.zip");//把assets文件夹的固件复制到手机内存
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int zipLength = getZipLength();
                    fileSize.setText(zipLength + "");//设置文件的大小
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).start();

        fileName.setText("IR16506084.zip");




    }

    private void initView() {
        fileName = ((TextView) findViewById(R.id.fileName));
        fileSize = ((TextView) findViewById(R.id.fileSize));
        airUpgrade = ((TextView) findViewById(R.id.airUpgradeTv));
        proBar = ((ProgressBar) findViewById(R.id.proBar));
        airUpgrade.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "XXXXXXXX");
                MyApplication.getInstance().mBlueToothService.setAirUpgrade();


            }
        });
    }


    /**
     * 得到固件的文件大小
     * @return
     * @throws IOException
     */
    public int getZipLength() throws IOException {
        int length ;
        InputStream is = getAssets().open("IR16506084.zip");
        length = is.available();
        Log.e(TAG,"is:"+is+"length"+length);

        return length;
    }
    //开始空中升级
    class AirUpgradeReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e(TAG, "开始空中升级" + address   +"   "+deviceName   +"");
            final DfuServiceInitiator starter = new DfuServiceInitiator(address)//设备地址
                    .setDeviceName(deviceName)//设备名
                    .setKeepBond(true);
            starter.setZip("/mnt/sdcard/KeeFit/IR16506084.zip");//设置固件
            starter.start(AirUpgradeActivity.this, DfuService.class);//开始升级

        }
    }
    //把zip固件复制到手机存储,之后再升级
    private void copyBigDataToSD(String strOutFileName) throws IOException
    {
        Log.e(TAG,"copyBigDataToSD");
        InputStream myInput;
        OutputStream myOutput = new FileOutputStream(strOutFileName);
        myInput = this.getAssets().open("IR16506084.zip");
        byte[] buffer = new byte[1024];
        int length = myInput.read(buffer);
        while(length > 0)
        {
            myOutput.write(buffer, 0, length);
            length = myInput.read(buffer);
        }

        myOutput.flush();
        myInput.close();
        myOutput.close();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);//取消注册
    }

    @Override
    protected void onPause() {
        super.onPause();
        DfuServiceListenerHelper.unregisterProgressListener(this, dfuProgressListener);//取消监听升级回调
    }
}


具体的代码就是这样,我这里遇到一个问题就是无法取到assets文件夹下文件的绝对路径,而升级的时候需要的是绝对路径,我尝试过许多方法还是不行,最后只能复制到手机存储然后再得到地址。


这里开始升级的时候需要个DfuService。这个主要是升级时在界面上显示个Notification通知进度条。下面我也贴下它们两个的代码:

首先是DfuService:

public class DfuService extends DfuBaseService {

	@Override
	protected Class getNotificationTarget() {
		
		return NotificationActivity.class;
	}

}
然后是
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
			final Intent parentIntent = new Intent(this, AirUpgradeActivity.class);
			parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			final Intent startAppIntent = new Intent(this, AirUpgradeActivity.class);
			startAppIntent.putExtras(getIntent().getExtras());
			startActivities(new Intent[] { parentIntent, startAppIntent });
		}

		// Now finish, which will drop the user in to the activity that was at the top
		//  of the task stack
		finish();
	}
}

最后,别忘了在清单文件配置DfuService和权限。

蓝牙ble实现空中升级功能_第1张图片

蓝牙ble实现空中升级功能_第2张图片

好了。今天就到这里,不知道什么问题上传不了效果图,不好意思。

共勉!



你可能感兴趣的:(android)