总有jar和aar中修改其中class字节码的需求,之前想直接用压缩工具解压缩,直接用javasist写代码修改,然后再替换这个classes.jar 再转成aar格式,但是好像这样破坏了aar结构导致aar无法使用,于是就写了一个工具
看看效果图吧(修改classes.jar后可以被识别的aar)
借助了https://github.com/BryanSharp/hibeaver 中对jar和aar中修改其中class字节码相关代码的帮助(抄袭),这里感谢作者
以下这个工具的github 地址 https://github.com/zjw-swun/AppMethodTime
相关代码
public static File unzipEntryToTemp(ZipEntry element, ZipFile zipFile, String parentDir) {
def stream = zipFile.getInputStream(element);
def array = IOUtils.toByteArray(stream);
//String hex = DigestUtils.md5Hex(element.getName());
File targetFile = new File(parentDir, "temp.jar");
if (targetFile.exists()) {
targetFile.delete()
}
def out = new FileOutputStream(targetFile)
out.write(array)
out.close()
stream.close()
return targetFile
}
public
static File modifyJar(File jarFile) {
ClassPath jarClassPath = pool.appendClassPath(jarFile.path)
ClassPath androidClassPath = pool.insertClassPath(androidJarPath)
/**
* 读取原jar
*/
def file = new JarFile(jarFile);
/** 设置输出到的jar */
def hexName = "";
hexName = DigestUtils.md5Hex(jarFile.absolutePath).substring(0, 8);
def outputJar = new File(jarFile.parent, "Target_" + jarFile.name)
if (outputJar.exists()) {
outputJar.delete()
}
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(outputJar));
Enumeration enumeration = file.entries();
while (enumeration.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) enumeration.nextElement();
InputStream inputStream = file.getInputStream(jarEntry);
String entryName = jarEntry.getName();
String className
ZipEntry zipEntry = new ZipEntry(entryName);
jarOutputStream.putNextEntry(zipEntry);
byte[] modifiedClassBytes = null;
byte[] sourceClassBytes = IOUtils.toByteArray(inputStream);
if (filter(entryName)) {
//println("entryName "+entryName)
className = entryName.replace("/", ".").replace(".class", "")
//println("modifyJar className "+className)
CtClass c = modifyClass(className)
if (c != null) {
modifiedClassBytes = c.toBytecode()
c.detach()
}
}
if (modifiedClassBytes == null) {
jarOutputStream.write(sourceClassBytes);
} else {
jarOutputStream.write(modifiedClassBytes);
}
jarOutputStream.closeEntry();
}
// Log.info("${hexName} is modified");
jarOutputStream.close();
file.close();
pool.removeClassPath(jarClassPath)
pool.removeClassPath(androidClassPath)
return outputJar;
}
public static void modifyAar(File targetFile) {
ZipFile zipFile = new ZipFile(targetFile);
Enumeration<ZipEntry> entries = zipFile.entries();
def outputAar = new File(targetFile.parent, "Target_" + targetFile.name)
if (outputAar.exists()) {
outputAar.delete()
}
ZipOutputStream outputAarStream = new ZipOutputStream(new FileOutputStream(outputAar))
FileInputStream fileInputStream = null;
File innerJar = null;
File outJar = null;
while (entries.hasMoreElements()) {
ZipEntry element = entries.nextElement();
def name = element.getName();
ZipEntry zipEntry = new ZipEntry(name);
outputAarStream.putNextEntry(zipEntry);
if (name.endsWith(".jar")) {
innerJar = unzipEntryToTemp(element, zipFile, targetFile.parent);
outJar = modifyJar(innerJar);
fileInputStream = new FileInputStream(outJar)
outputAarStream.write(IOUtils.toByteArray(fileInputStream))
} else {
def stream = zipFile.getInputStream(element)
byte[] array = IOUtils.toByteArray(stream)
if (array != null) {
outputAarStream.write(array)
}
stream.close()
}
outputAarStream.closeEntry();
}
zipFile.close()
if (fileInputStream!= null){
fileInputStream.close()
}
outputAarStream.close()
if (innerJar != null){
innerJar.delete()
}
if (outJar != null){
outJar.delete()
}
}
项目中buildSrc模块中是一个transform api的插件
使用说明
添加aarOrJarPath 配置字段,填入目标jar或者aar路径 执行gradle面板对应项目中other目录appMethodJarOrAar 任务即可在aarOrJarPath 配置的同目录下生成带 Target_前缀的目标jar或者aar文件
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦