当前位置: 首页 > news >正文

广州网站建设企业/电商培训视频教程

广州网站建设企业,电商培训视频教程,做液压的公司网站,网站建设工作流程image.png最近做了一个小功能,由于没有需求,只有一个一代的app services功能实现进行提示。由于更换了外包厂商,所以在升级版本上需要自行研发。然而一直从事底层开发的我,一脸懵逼,后来验证了,这根本就是n…

c6a8ea78114a?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image.png

最近做了一个小功能,由于没有需求,只有一个一代的app services功能实现进行提示。由于更换了外包厂商,所以在升级版本上需要自行研发。然而一直从事底层开发的我,一脸懵逼,后来验证了,这根本就是n脸懵逼。

首先下载dex2jar对apk进行反编译,然后用jd-gui打开。经理说可以参考这个进行开发,我当时一看这不是很easy么,源码都有了,再编译一下就成。然而实在是太年轻,当时不明白这些变量的名字为什么这么奇怪,后来才知道,apk经过混淆,变量名都变了的。首先摸清楚业务逻辑就花了大力气,因为混淆过的app反解出来的代码,逻辑不完全一样,之可以知道大概做了些什么事,至于逻辑,需要重新组织。

至于需要使用的第三方dfu library也是不甚了解,这里将上面反解出来的classes-dex2jar.jar作为jar包,放入到android studio工程中的app/libs即可以完成dfu library库的导入。这里就可以使用第三方的接口进行升级操作了。首先新建一个android项目,然后如上导入jar包,然后开始创建reciever。

package com.包名;

import android.bluetooth.BluetoothDevice;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.SharedPreferences;

import android.util.Log;

import java.lang.reflect.Method;

import java.io.File;

public class ControllerOTARec extends BroadcastReceiver {

private static final String TAG = "ControllerRec";

private static final String ACTION_READY_FOR_OTA = "com.action.readyForOTA";

private static final String DEVICE_NAME = "DEVICE";

public static final String RETRY_OTA_UPGRADE = "retry.ota.upgrade";

private static final String BT_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";

private static final String GET_HAND_VERSION ="com.test.gethandversion";

private static final File otaFile = new File(ControllerOTAService.mFile);

public static boolean mHaveDisable = false;

public static boolean mHaveStart = false;

private int mOldVersion;

private int mNewVersion;

private Method getStringMethod = null;

public static BluetoothDevice mDevice = null;

@Override

public void onReceive(final Context context, final Intent intent0)

{

String actionStr = intent0.getAction();

if (BT_CONNECTED.equals(actionStr))

{

mDevice = (BluetoothDevice)intent0.getParcelableExtra("android.bluetooth.device.extra.DEVICE");

} else if(ACTION_READY_FOR_OTA.equals(actionStr)){

mNewVersion = getStringMethod("ro.build.controller.version", null);

int mOldVersion = Integer.parseInt(getStringMethod("sys.hand.appVersion","1"));

//catch if target version lower than present

if ((mNewVersion <= mOldVersion) || (mOldVersion == 0)) {

Log.d(TAG, "controller version is very new,not ota!");

return;

}

//catch if zipfile is not exist

if (!otaFile.exists()) {

Log.d(TAG, "ota file not exists");

return;

}

//begin to do the things

if (mDevice != null) {

final String deviceName = mDevice.getName();

final String deviceAddr = mDevice.getAddress();

int deviceBond = mDevice.getBondState();

Log.d(TAG, "deviceName:" + deviceName + ";and bond state is " + deviceBond + "; and device address is " + deviceAddr);

//通知蓝牙状态机马上进入ota模式,停止

if(!mHaveDisable) {

Log.d(TAG, "tell the bluetooth machine to stop for ota");

Intent intent = new Intent("bluetooth_ota_update");

intent.putExtra("start_bluetooth_state", false);

context.sendBroadcast(intent);

//delay 500ms for bt to stop

try {

Thread.sleep(500);

} catch (Exception e){

Log.d(TAG, "Sleep error");

}

}

if (!mHaveStart) {

removeBondStatus(mDevice);//这是清楚蓝牙配对,这是遇到的最大的一个问题

//储存设备地址和设备名信息

Log.d(TAG, "mHaveStart = true");

ControllerOTARec.mHaveStart = true;

SharedPreferences.Editor editor = context.getSharedPreferences("Controller_OTA", 0).edit();

editor.putString("deviceName", deviceName);

editor.putString("deviceAddress", deviceAddr);

editor.commit();

//告诉cs开始进入ota模式

Log.d(TAG,"will tell the controller service to stop for ota");

Intent intent1 = new Intent("com.startsignal");

context.sendBroadcast(intent1);

//准备工作完成,启动服务

Log.d(TAG, "start ota:" + mDevice.getAddress());

Intent intent2 = new Intent(context, ControllerOTAService.class);

intent2.putExtra("deviceName", deviceName);

intent2.putExtra("deviceAddress", deviceAddr);

context.startService(intent2);

}

}

} else if(RETRY_OTA_UPGRADE.equals(actionStr)){

Log.d(TAG, "wille retry for hand devices ota");

Intent intent = new Intent(context, ControllerOTAService.class);

String add = context.getSharedPreferences("Controller_OTA",0).getString("deviceAddress","default");

intent.putExtra("deviceName",DEVICE_NAME);

intent.putExtra("deviceAddress",add);

context.startService(intent);

}

}

//反射的方式访问系统属性

public String getStringMethod(final String key, final String def) {

try {

if (getStringMethod == null) {

getStringMethod = Class.forName("android.os.SystemProperties").getMethod("get", String.class, String.class);

}

return ((String) getStringMethod.invoke(null, key, def)).toString();

} catch (Exception e) {

return def;

}

}

//反射的方式访问蓝牙设备的隐藏接口removebond

public void removeBondStatus(BluetoothDevice btDevices){

boolean result = false;

try {

final Method removeBondStatus = btDevices.getClass().getMethod("removeBond");

if (removeBondStatus != null) {

result = (Boolean) removeBondStatus.invoke(btDevices);

Log.w(TAG, "removeBondStatus result is " + result);

while (btDevices.getBondState() != BluetoothDevice.BOND_NONE){

Thread.sleep(20);

}

}

} catch (final Exception e) {

Log.w(TAG, "An exception occurred while removing bond information", e);

}

}

}

然后创建服务

package com.包名;

import android.app.ProgressDialog;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.util.Log;

import java.io.File;

import no.nordicsemi.android.dfu.DfuProgressListener;

import no.nordicsemi.android.dfu.DfuServiceInitiator;

import no.nordicsemi.android.dfu.DfuServiceListenerHelper;

public class ControllerOTAService extends Service {

//定义安装包路径

public static final String ZIP_FILE_PATH = "/sdcard/Controller/";

//获取安装包文件名

public static final String mFile = getmPathFile();

//进度dialog

private ProgressDialog mDialog;

//通过路径找文件名

public static String getmPathFile(){

String otapackagepath = null;

File file = new File(ZIP_FILE_PATH);

File[] array = file.listFiles();

if(array[0].isFile()){

otapackagepath = ZIP_FILE_PATH +array[0].getName();

Log.d("ControllerOTAService", "file path is :" + otapackagepath);

} else{

Log.d("ControllerOTAService", "can not find the zip file");

}

return otapackagepath;

}

public ControllerOTAService() {

}

//注销监听,停止服务

private void stopService()

{

DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener);//取消监听升级回调

stopSelf();

}

//启动升级流程

private void beginToUpdate(String devname, String addr)

{

Log.d("ControllerOTAService", "begin to update hand device by DFU,create dialog");

createDialog();

if (this.mDialog != null)

this.mDialog.show();

Log.d("ControllerOTAService", "devices name is " + devname +", address is " + addr + ", zip file path is " + mFile);

final DfuServiceInitiator dfuservice = new DfuServiceInitiator(addr)

.setDeviceName(devname)

.setKeepBond(true);//升级完成后保持连接

dfuservice.setZip(null, mFile);

dfuservice.start(this, DfuService.class);

DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener);//注册监听

Log.d("ControllerOTAService", "dismiss dialog");

//取消dialog

new Thread(new Runnable() {

@Override

public void run() {

try{

Thread.sleep(5000);

ControllerOTAService.this.mDialog.dismiss();

} catch(InterruptedException e){

e.printStackTrace();

}

}

}).start();

}

//创建dialog

private void createDialog()

{

Log.d("ControllerOTAService", "create dialog");

this.mDialog = new ProgressDialog(this);

this.mDialog.setMax(100);

this.mDialog.setProgress(0);

this.mDialog.setProgressStyle(1);

this.mDialog.setTitle("hand ota");

this.mDialog.setMessage("start update hand device,please use head mode");

this.mDialog.setIndeterminate(false);

this.mDialog.setCancelable(true);

this.mDialog.getWindow().setType(2003);

}

//startservice会调到这里

public int onStartCommand(Intent intent, int int1, int int2)

{

String devname = intent.getStringExtra("deviceName");

String addr = intent.getStringExtra("deviceAddress");

Log.d("ControllerOTAService", "deviceName:" + devname + " deviceAddress:" + addr);

beginToUpdate(devname, addr);

return Service.START_NOT_STICKY;

}

@Override

public IBinder onBind(Intent intent) {

// TODO: Return the communication channel to the service.

throw new UnsupportedOperationException("Not yet implemented");

}

//新建dfu升级流程监听(新建后自动弹出接口函数)

private final DfuProgressListener mDfuProgressListener = new DfuProgressListener() {

//device connecting

@Override

public void onDeviceConnecting(String deviceAddress) {

Log.d("ControllerOTAService", "onDeviceConnecting");

}

//devices begin to connect

@Override

public void onDeviceConnected(String deviceAddress) {

Log.d("ControllerOTAService", "onDeviceConnected");

}

//before ota process start

@Override

public void onDfuProcessStarting(String deviceAddress) {

Log.d("ControllerOTAService", "onDfuProcessStarting");

}

@Override

public void onDfuProcessStarted(String deviceAddress) {

Log.d("ControllerOTAService", "onDfuProcessStarted");

}

@Override

public void onEnablingDfuMode(String deviceAddress) {

Log.d("ControllerOTAService", "onEnablingDfuMode");

}

@Override

public void onProgressChanged(String deviceAddress, int percent, float speed, float avgSpeed, int currentPart, int partsTotal) {

Log.d("ControllerOTAService", "onProgressChanged");

}

@Override

public void onFirmwareValidating(String deviceAddress) {

Log.d("ControllerOTAService", "onFirmwareValidating");

}

@Override

public void onDeviceDisconnecting(String deviceAddress) {

Log.d("ControllerOTAService", "onDeviceDisconnecting");

}

@Override

public void onDeviceDisconnected(String deviceAddress) {

Log.d("ControllerOTAService", "onDeviceDisconnected");

}

//完成升级会调入到这里

@Override

public void onDfuCompleted(String deviceAddress) {

Log.d("ControllerOTAService", "onDfuCompleted");

//发出停止广播

Intent intent = new Intent("com.handota.stop");

ControllerOTAService.this.sendBroadcast(intent);

//恢复状态机

Intent intent1 = new Intent("bluetooth_ota_update");

intent1.putExtra("start_bluetooth_state", true);

ControllerOTAService.this.sendBroadcast(intent1);

//是否启动ota状态改为false

ControllerOTARec.mHaveStart = false;

//tell app the result

Intent intent2 = new Intent("hand_device_ota_process");

intent2.putExtra("handOTAProcess",1);

ControllerOTAService.this.sendBroadcast(intent2);

//DFU completed will delete the zip file

Log.d("ControllerOTAService", "begin to delete the update zipfile");

clearFile(ZIP_FILE_PATH);

Log.d("ControllerOTAService", "<<

ControllerOTAService.this.stopService();

}

@Override

public void onDfuAborted(String deviceAddress) {

Log.d("ControllerOTAService", "onDfuAborted");

Intent intent = new Intent("bluetooth_ota_update");

intent.putExtra("start_bluetooth_state", true);

ControllerOTAService.this.sendBroadcast(intent);

ControllerOTARec.mHaveStart = false;

//tell app the result

Intent intent2 = new Intent("hand_device_ota_process");

intent2.putExtra("handOTAProcess",2);

ControllerOTAService.this.sendBroadcast(intent2);

//DFU completed will delete the zip file

Log.d("ControllerOTAService", "begin to delete the update zipfile");

clearFile(ZIP_FILE_PATH);

ControllerOTAService.this.stopService();

}

@Override

public void onError(String deviceAddress, int error, int errorType, String message) {

Log.d("", "ERROR"+error+"message"+message);

Intent intent = new Intent("bluetooth_ota_update");

intent.putExtra("start_bluetooth_state", true);

ControllerOTAService.this.sendBroadcast(intent);

//tell app the result

Intent intent2 = new Intent("hand_device_ota_process");

intent2.putExtra("handOTAProcess",3);

ControllerOTAService.this.sendBroadcast(intent2);

ControllerOTARec.mHaveStart = false;

//DFU completed will delete the zip file

Log.d("ControllerOTAService", "begin to delete the update zipfile");

clearFile(ZIP_FILE_PATH);

ControllerOTAService.this.stopService();

}

};

//删除文件函数

public static void clearFile(String filePath){

File targetFile = new File(filePath);

File[] fileList = targetFile.listFiles();

Log.d("ControllerOTAService", "clearFile");

if(fileList[0].exists()){

fileList[0].delete();

Log.d("ControllerOTAService", "clearFile success");

}else {

Log.d("ControllerOTAService", "no file to delete");

}

}

}

这里还要创建dfuservices类

package com.包名;

import android.app.Activity;

import no.nordicsemi.android.dfu.DfuBaseService;

public class DfuService extends DfuBaseService

{

protected Class extends Activity> getNotificationTarget()

{

return NotificationActivity.class;

}

protected boolean isDebug()

{

return true;

}

}

创建NotificationActivity通知类

package com.包名;

import android.os.Bundle;

import android.app.Activity;

public class NotificationActivity extends Activity {

@Override

protected void onCreate(Bundle bundle)

{

super.onCreate(bundle);

finish();

}

}

配置xml

package="com包名">

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:theme="@style/AppTheme">

android:name=".ControllerOTAService"

android:enabled="true"

android:exported="true" />

android:name=".DfuService"

android:enabled="true"

android:exported="true" />

配合蓝牙状态机升级流程大致如下

c6a8ea78114a?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image.png

遇到的问题:

1.不同版本的官方nordic软件,升级方式也不一样,1.61.3版本连接状态下可以直接进行升级;2.6.0版本必须设备通过硬件进入ota模式才能正常升级,同时,高版本的dfu代码在18年7月已经对O代码做了适应,同时到O有些接口发生了变化,得确认是否在自己项目里面支持,不对应的话,需要下载对应的dfu版本的三方库;

2.读取设备版本这里遇到过一些问题,由于代码设计问题,设备当前版本在目前项目里面经常被重置为1,这里采取临时的系统属性来储存正确读取的当前版本;

3.由于一开始使用的是反编译的apk做jar包,有些库函数并不能被反解出来,导致内部逻辑无法获知,后来在github上下载了源码,就可以看到了;

4.遇到一个读取dfu版本失败的问题,追Src read.p_value ptr is NULL发现深陷蓝牙协议栈中的调用无法自拔,找不到根本原因,追Reading DFU version number发现是dfuservices要发起一此读取dfu版本信息的请求,然后gattserver收到这个请教,通过jni,向蓝牙协议栈发送了这个请求,然后返回的结果不对,status为1,正确的情况status为0,一开始蓝牙这一块的东西什么都不懂的时候有点摸不清头脑。为什么这里要去读这个,而且这个读取操作在升级过程中有两到三次。整个升级流程也是一头雾水。后来慢慢的梳理log,发现在gatt server向手柄发送了进入ota模式的命令后,然后再去读取手柄相关属性就会失败。

这里涉及到一个隐藏任务,设备在ota模式和非ota模式,属性值会发生变化,在手柄进入ota模式后,主机设备的蓝牙服务还会进行一次扫描,然后才会开始发送安装包进行升级的操作。然而新产品上为什么协议栈没有进行扫描,这一点需要一定蓝牙知识进行调查可能会更快解决。这里的临时做法,就是先进行设备配对信息清除,清楚完之后,设备就会进行扫描(可能跟产品里面的状态机有关系,在有配对信息的情况下,就不会进行扫描。)。即是这里的removeBondStatus(mDevice);这一块困住了很长时间,在宇神的一次操作下成功绕出去了,就得到了这个workaround。

DfuImpl : Reading DFU version number...

WCNSS_FILTER: ibs_recv_ibs_cmd: Received IBS_WAKE_IND: 0xFD

WCNSS_FILTER: ibs_recv_ibs_cmd: Writing IBS_WAKE_ACK

WCNSS_FILTER: do_write: IBS write: fc

bt_btif : btapp_gattc_req_data :Src read.p_value ptr is NULL for event 0x3

BluetoothGatt: onCharacteristicRead() - Device=D0:F0:63:61:D4:B1 handle=28 Status=1

DfuImpl : Characteristic read error: 1

DfuBaseService: Unable to read version number (error 1)

DfuBaseService: Disconnecting from the device...

BluetoothGatt: cancelOpen() - device: D0:F0:63:61:D4:B1

BtGatt.GattService: clientDisconnect() - address=D0:F0:63:61:D4:B1, connId=8

BtGatt.GattService: onDisconnected() - clientIf=8, connId=8, address=D0:F0:63:61:D4:B1

BluetoothGatt: onClientConnectionState() - status=0 clientIf=8 device=D0:F0:63:61:D4:B1

DfuBaseService: Disconnected from GATT server

DfuBaseService: Cleaning up...

BluetoothGatt: close()

BluetoothGatt: unregisterApp() - mClientIf=8

5.apk实现后,怎样将android studio集成到android source项目当中去也是因为不太熟悉这块有太多的问题,首先是sdk版本过高,将apk放入android项目失败的问题。这里去android studio中手动从O降级到N,第三方库的降级方法就是一个个去解决编译错误,找到对应的地版本对象进行替换。这里的25都是由27转换过来的。

apply plugin: 'com.android.application'

android {

signingConfigs {

config {

keyAlias 'controllerota'

keyPassword '123456'

storeFile file('/home/edward/bin/android-studio/keystore/key.jks')

storePassword '123456'

}

}

compileSdkVersion 25

defaultConfig {

applicationId "com.qiyi.controllerota1"

minSdkVersion 23

targetSdkVersion 25

versionCode 1

versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

}

}

}

dependencies {

implementation fileTree(include: ['*.jar'], dir: 'libs')

implementation 'com.android.support:appcompat-v7:25.1.1'

implementation 'com.android.support.constraint:constraint-layout:1.1.2'

testImplementation 'junit:junit:4.12'

androidTestImplementation 'com.android.support.test:runner:1.0.2'

androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

implementation files('libs/DFUlibrary.jar')

}

6.关于系统ro属性的修改方法,在前一篇中记录了,之修改buildinfo.sh似乎是不奏效的。

最后一点忠告:就是尽量做需求清晰,设计明确的工作,降低跟同事工作的耦合度---------------虽然空白做法也挺锻炼人。

完全知识分享,谢谢支持

http://www.jmfq.cn/news/5127409.html

相关文章:

  • 国内红酒网站建设/媒介星软文平台
  • 东莞做网站公司首选/个人推广app的妙招
  • 河北网站制作公司哪家好/百度资源搜索引擎
  • 思途旅游cms网站建设系统/百度 seo排名查询
  • html5商城网站/小广告多的网站
  • 营销型网站建设与推广/国际新闻消息
  • 学校网站建设目标/网站制作免费
  • 有专门做检验的视频网站吗/烟台seo快速排名
  • 网站为什么不被收录/搜索引擎的设计与实现
  • 网站图标怎么上传/百度问一问在线咨询客服
  • 4昌平区网站建设/苏州seo招聘
  • 怎么才算完成一个网站/搭建网站多少钱
  • 淘宝上做网站的信得过吗/软文交易平台
  • 如何创建网址快捷方式/上海优化seo
  • 京东商城官方网站/谷歌搜索排名规则
  • 小网站开发用哪些技术/种子在线资源搜索神器
  • mac wordpress教程 pdf/百度搜索怎么优化
  • 杭州e时代互联网站建设/商业计划书
  • 网络营销专业属于什么类别/搜索引擎优化涉及的内容
  • 云南 网站建设/互联网营销顾问是做什么的
  • web前端开发难不难学/seo优化包括
  • 做网站怎么找优质客户/广东疫情最新资讯
  • 有做足球裁判跑动数据的网站吗/推广技术
  • 怎么找网站做公示/无锡seo公司找哪家好
  • 网站建设推广新闻/网站推广费用
  • 知名企业网站/网站维护推广的方案
  • 国外优秀门户网站/培训学校加盟
  • 高校邦营销型网站建设答案/百度指数网页版
  • 福田区建设局网站/网店代运营的套路
  • 河南企业网站推广/整站关键词排名优化