阿里云热修复的使用
在阿里云上注册账户,并配置好相关信息,在阿里云热修复钉钉群里,发现3.1.3有兼容7.0失败的问题,3.1.2没有,故采用了3.1.2
1. 接入方法
(1) 配置Project的阿里云仓库地址
allprojects {
repositories {
jcenter()
//阿里云仓库地址
maven {
url "http://maven.aliyun.com/nexus/content/repositories/releases"
}
}
}
(2)配置APP的依赖
compile 'com.aliyun.ams:alicloud-android-hotfix:3.1.2'
(3)权限说明
<! -- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<! -- 外部存储读权限,调试工具加载本地补丁需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
(4)配置AndroidManifest.xml文件
<meta-data
android:name="com.taobao.android.hotfix.IDSECRET"
android:value="App ID" />
<meta-data
android:name="com.taobao.android.hotfix.APPSECRET"
android:value="App Secret" />
<meta-data
android:name="com.taobao.android.hotfix.RSASECRET"
android:value="RSA密钥" />
(5)混淆配置
#基线包使用,生成mapping.txt
-printmapping mapping.txt
#生成的mapping.txt在app/buidl/outputs/mapping/release路径下,移动到/app路径下
#修复后的项目使用,保证混淆结果一致
#-applymapping mapping.txt
#hotfix
-keep class com.taobao.sophix.**{*;}
-keep class com.ta.utdid2.device.**{*;}
#防止inline
-dontoptimize
2. 接入SDK
(1)在Application中添加init以及查询
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
findPatch(); //查询Patch包
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
initHotFix(base);
MultiDex.install(this);
}
/**
* 查询patch包
* */
private void findPatch(){
long lastTime = MySharedPreferences.getInstance(this).getLastLoadPatchTime();
long newTime = System.currentTimeMillis();
if (newTime - lastTime > Constants.MAX_FIND_HOTFIX_PATCH_TIMES){ //说明已经超过一定的时间间隔()了,可以再次去查询了
SophixManager.getInstance().queryAndLoadNewPatch();
MySharedPreferences.getInstance(this).saveLastLoadPatchTime(newTime);
}else {
//说明刚刚已经查询过了,时间间隔没有超过144分钟,所以不再查询
}
}
/**
*
* 初始化热修复
* initialize最好放在attachBaseContext最前面,初始化直接在Application类里面,切勿封装到其他类
* 逻辑:
* (1)当返回补丁为加载成功,要将SP中的loadNewPatch设置为true,表示已经加载了Patch包
* (2)当返回补丁为需要重启,则调用reStartAPP来重启应用
* (3)当返回补丁为后台一键清除,则通过SP中的loadNewPatch来判断,如果是true,说明已经加载过patch包,设置loadNewPatch为false, 然后调用reStartAPP来生效清除补丁
* 如果是false,说明没有加载过补丁,则不用调用loadNewPatch来判断
* (4) 其它信息,则忽略,不用进行处理
* */
private void initHotFix(final Context context){
SophixManager.getInstance().setContext(this)
.setAppVersion(CommonUtil.getVersionName(this))
.setAesKey(null)
.setEnableDebug(true)
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
// 补丁加载回调通知
CommonUtil.printLogs("wnwFix", code + " " + info);
boolean cleared = MySharedPreferences.getInstance(context).getBooleanValue("loadNewPatch", false);
CommonUtil.printLogs("wnwCleared", cleared +" " );
if (code == PatchStatus.CODE_LOAD_SUCCESS) {
// 表明补丁加载成功
MySharedPreferences.getInstance(context).setBooleanValue("loadNewPatch", true);
} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
// 表明新补丁生效需要重启. 开发者可提示用户或者强制重启;
// 建议: 用户可以监听进入后台事件, 然后调用killProcessSafely自杀,以此加快应用补丁,详见1.3.2.3
reStartApp();
} else if (code == PatchStatus.CODE_REQ_CLEARPATCH){
// 如果后台已经一键清除了所有的patch:如果没有
if (cleared){
MySharedPreferences.getInstance(getContext()).setBooleanValue("loadNewPatch", false);
reStartApp();
}
}else {
// 其它错误信息, 查看PatchStatus类说明,如果是
}
}
}).initialize();
}
/**
* 重启APP
* (1)由于这里要调用阿里的杀进程,所以不能用一般的重启APP策略,是利用PendingIntent将重启Service交给AlarmManager
* (2)AlarmManager有两种情况,当API<19之前,是调用set方法就可以准确定时,但是当API>19后,就不行了,至少有5s的启动缓存,
* 所以当API>=19后,调用相应的方法定时5s,但是过了4秒钟才会调用杀进程程序,这样可以造成重启APP时间短的假象。
* */
private void reStartApp(){
Intent intent = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(getBaseContext().getPackageName());
PendingIntent restartIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
//mgr.setExact(AlarmManager.RTC, 2000, restartIntent);
CommonUtil.printLogs("wnw version", Build.VERSION.SDK_INT+"");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + Constants.RESTART_APP_TIME, restartIntent); // 300ms后重启应用
CommonUtil.printLogs("wnw version", ">= 6.0");
delayKillProcess();
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
CommonUtil.printLogs("wnw version", "19 - 6.0");
mgr.setExact(AlarmManager.RTC, System.currentTimeMillis() + Constants.RESTART_APP_TIME, restartIntent);
delayKillProcess();
}else{
CommonUtil.printLogs("wnw version", "< 19");
mgr.set(AlarmManager.RTC,System.currentTimeMillis() + 300,restartIntent);
SophixManager.getInstance().killProcessSafely(); //根据阿里的建议,调用其杀掉进程,并且保证了热修复的安全
}
}
/**
* 延时4000ms去杀死当前进程
* */
private void delayKillProcess(){
CommonUtil.printLogs("wnw", "kill process");
new Handler(getMainLooper()).postDelayed(new Runnable(){
public void run() {
SophixManager.getInstance().killProcessSafely(); //根据阿里的建议,调用其杀掉进程,并且保证了热修复的安全
}
}, Constants.DELAY_KILL_PROCESS_TIME);
}