总有jar和aar中修改其中class字节码的需求,之前想直接用压缩工具解压缩,直接用javasist写代码修改,然后再替换这个classes.jar 再转成aar格式,但是好像这样破坏了aar结构导致aar无法使用,于是就写了一个工具
看看效果图吧(修改classes.jar后可以被识别的aar)
借助了https://github.com/BryanSharp/hibeaver 中对jar和aar中修改其中class字节码相关代码的帮助(抄袭),这里感谢作者
以下这个工具的github 地址
github.com/zjw-swun/Ap…
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文件
github.com/zjw-swun/Ap…