当前位置: 首页 > 工具软件 > Robust > 使用案例 >

简单集成美团热更新RoBust

毋宏茂
2023-12-01

地址: https://gitee.com/mirrors/Robust

https://github.com/Meituan-Dianping/Robust

 

当前版本:0.4.99(目前不支持AGP4.1.0:https://github.com/Meituan-Dianping/Robust/issues/434,可以用0.4.100试试)

 

项目的build.gradle

dependencies {

classpath 'com.meituan.robust:gradle-plugin:0.4.99'

classpath 'com.meituan.robust:auto-patch-plugin:0.4.99'

}

APP的build.gradle

apply plugin: 'com.android.application'

//apply plugin: 'robust' 打基准包的时候用

apply plugin: 'auto-patch-plugin' 打补丁包的时候用

 

打基准包

拷贝robust.xml到src同级目录,需要修改的地方:<packname name="hotfixPackage"> <patchPackname name="patchPackname">,里面的值分别对应包名和包名.patch

继承com.meituan.robust.PatchManipulate,实现com.meituan.robust.RobustCallBack,代码放最后,都是从官方demo拿过来的

选一个合适的时机,调用new PatchExecutor(context, new TestPatchManipulate(), new TestRobustCallBack()).start();,加载补丁包

 

开启混淆,才能生成mapping文件

放开APP的build.gradle中基准包的引用,注释补丁包的引用

gradle --> app --> 找到assembleRelease (这一步需要配置签名信息)

执行成功后,会在build --> outputs --> 下面生成对应的文件,需要检查的有apk文件夹下的release>app-release.apk,mapping文件夹下的release>mapping.txt,robust文件夹下的methodsMap.robust

 

补丁包

拷贝上面的3个文件到src同级的robust文件夹下

修改代码,有修改的方法用@Modify注解,新增的方法用@Add,Lambda需要在方法内部调用RobustModify.modify(),参考官方文档

放开APP的build.gradle中补丁包的引用,注释基准包的引用,同步

run app,不出意外的话,Build会出错误提示:Cause: auto patch end successfully,出这个提示没问题,表示补丁包生成成功

在src同级的robust文件夹下,可以找到一个patch.jar,就是我们需要的补丁文件了

 

下发和校验

线上发布的下发和校验,可以灵活处理,主要逻辑在集成PatchManipulate的方法fetchPatchList和verifyPatch里面

理论上,robust实时生效,收到补丁包更新信息之后,下载补丁包到指定目录,调用预先设置的加载补丁包的方法,就OK了,实际运行也OK

检查方法:将patch.jar拷贝到手机根目录下的robust文件夹下,重新运行APP,需要权限
资源地址:https://download.csdn.net/download/qq_24179679/19430486,安装包在资源解压后src的同级robust文件夹下

new PatchExecutor(context, new TestPatchManipulate(), new TestRobustCallBack()).start();

有问题看日志,主要是在RobustCallBack中

 

——————————————————下面是部分代码—————————————————————

package com.wy.testrobust;

 

import android.content.Context;

import android.os.Environment;

import android.os.Handler;

import android.os.Looper;

import android.util.Log;

import android.widget.Toast;

import com.meituan.robust.Patch;

import com.meituan.robust.PatchManipulate;

 

import java.io.*;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

 

/**

* @Description: robust PatchManipulate

* @Author: ***

* @Date: 2021/6/4 5:18 下午

*/

public class TestPatchManipulate extends PatchManipulate {

@Override

protected List<Patch> fetchPatchList(Context context) {

String robustApkHash = RobustApkHashUtils.readRobustApkHash(context);

Log.w("robust","robustApkHash :" + robustApkHash);

//connect to network to get patch list on servers

//在这里去联网获取补丁列表

Patch patch = new Patch();

patch.setName("123");

//we recommend LocalPath store the origin patch.jar which may be encrypted,while TempPath is the true runnable jar

//LocalPath是存储原始的补丁文件,这个文件应该是加密过的,TempPath是加密之后的,TempPath下的补丁加载完毕就删除,保证安全性

//这里面需要设置一些补丁的信息,主要是联网的获取的补丁信息。重要的如MD5,进行原始补丁文件的简单校验,以及补丁存储的位置,这边推荐把补丁的储存位置放置到应用的私有目录下,保证安全性

patch.setLocalPath(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "robust" + File.separator + "patch");

 

//setPatchesInfoImplClassFullName 设置项各个App可以独立定制,需要确保的是setPatchesInfoImplClassFullName设置的包名是和xml配置项patchPackname保持一致,而且类名必须是:PatchesInfoImpl

//请注意这里的设置

patch.setPatchesInfoImplClassFullName("com.wy.testrobust.patch.PatchesInfoImpl");

List patches = new ArrayList<Patch>();

patches.add(patch);

return patches;

}

 

@Override

protected boolean verifyPatch(Context context, Patch patch) {

patch.setTempPath(context.getCacheDir() + File.separator + "robust" + File.separator + "patch");

try {

copy(patch.getLocalPath(), patch.getTempPath());

} catch (Exception e) {

String msg = Log.getStackTraceString(e);

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override

public void run() {

Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();

}

});

}

return true;

}

 

@Override

protected boolean ensurePatchExist(Patch patch) {

return true;

}

 

 

public void copy(String srcPath, String dstPath) throws IOException {

File src = new File(srcPath);

if (!src.exists()) {

throw new RuntimeException("source patch does not exist ");

}

File dst = new File(dstPath);

if (!dst.getParentFile().exists()) {

dst.getParentFile().mkdirs();

}

InputStream in = new FileInputStream(src);

try {

OutputStream out = new FileOutputStream(dst);

try {

// Transfer bytes from in to out

byte[] buf = new byte[1024];

int len;

while ((len = in.read(buf)) > 0) {

out.write(buf, 0, len);

}

} finally {

out.close();

}

} finally {

in.close();

}

}

}

——————————————————

package com.wy.testrobust;

 

import android.content.Context;

import android.text.TextUtils;

import com.meituan.robust.Constants;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

 

/**

* Created by hedex on 17/2/27.

*/

public class RobustApkHashUtils {

private static String robustApkHashValue;

 

public static String readRobustApkHash(Context context) {

 

if (TextUtils.isEmpty(robustApkHashValue)) {

robustApkHashValue = readRobustApkHashFile(context);

}

 

return robustApkHashValue;

}

 

private static String readRobustApkHashFile(Context context) {

String value = "";

if (null == context) {

return value;

}

 

try {

value = readFirstLine(context, Constants.ROBUST_APK_HASH_FILE_NAME);

} catch (Throwable throwable) {

 

}

 

return value;

}

 

private static String readFirstLine(Context context, String fileName) {

BufferedReader reader = null;

try {

reader = new BufferedReader(

new InputStreamReader(context.getAssets().open(fileName)));

 

return reader.readLine();

} catch (IOException e) {

return "";

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e) {

}

}

}

}

 

}

————————————————————

package com.wy.testrobust;

 

import android.util.Log;

import com.meituan.robust.Patch;

import com.meituan.robust.RobustCallBack;

 

import java.util.List;

 

/**

* @Description: robust TestRobustCallBack

* @Author: *****

* @Date: 2021/6/4 5:19 下午

*/

public class TestRobustCallBack implements RobustCallBack {

@Override

public void onPatchListFetched(boolean result, boolean isNet, List<Patch> patches) {

Log.e("RobustCallBack", "onPatchListFetched result: " + result);

Log.e("RobustCallBack", "onPatchListFetched isNet: " + isNet);

for (Patch patch : patches) {

Log.e("RobustCallBack", "onPatchListFetched patch: " + patch.getName());

}

}

 

@Override

public void onPatchFetched(boolean result, boolean isNet, Patch patch) {

Log.e("RobustCallBack", "onPatchFetched result: " + result);

Log.e("RobustCallBack", "onPatchFetched isNet: " + isNet);

Log.e("RobustCallBack", "onPatchFetched patch: " + patch.getName());

}

 

@Override

public void onPatchApplied(boolean result, Patch patch) {

Log.e("RobustCallBack", "onPatchApplied result: " + result);

Log.e("RobustCallBack", "onPatchApplied patch: " + patch.getName());

}

 

@Override

public void logNotify(String log, String where) {

Log.e("RobustCallBack", "logNotify log: " + log);

Log.e("RobustCallBack", "logNotify where: " + where);

}

 

@Override

public void exceptionNotify(Throwable throwable, String where) {

Log.e("RobustCallBack", "exceptionNotify where: " + where, throwable);

}

}

 

下载地址:https://download.csdn.net/download/qq_24179679/19430486

 类似资料: