Skip to content

Instantly share code, notes, and snippets.

@tiann
Created May 5, 2018 07:13
Show Gist options
  • Save tiann/42f829ae86b90934c8467f6f76dd6a85 to your computer and use it in GitHub Desktop.
Save tiann/42f829ae86b90934c8467f6f76dd6a85 to your computer and use it in GitHub Desktop.
import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.io.FileUtils
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
class JarZipUtil {
static List<String> blackList = Arrays.asList(
// "io.virtualapp.XApp",
// "io.virtualapp.VCommends",
"xxxxxxxxxxxx"
)
/**
* 将该jar包解压到指定目录
* @param jarPath jar包的绝对路径
* @param destDirPath jar包解压后的保存路径
* @return 返回该jar包中包含的所有class的完整类名类名集合,其中一条数据如:com.aitski.hotpatch.Xxxx.class
*/
public static List unzipJar(String jarPath, String destDirPath) {
List list = new ArrayList()
if (jarPath.endsWith('.jar')) {
JarFile jarFile = new JarFile(jarPath)
Enumeration<JarEntry> jarEntrys = jarFile.entries()
while (jarEntrys.hasMoreElements()) {
JarEntry jarEntry = jarEntrys.nextElement()
if (jarEntry.directory) {
continue
}
String entryName = jarEntry.getName()
if (entryName.endsWith('.class')) {
String className = entryName.replace('\\', '.').replace('/', '.')
list.add(className)
}
String outFileName = destDirPath + "/" + entryName
File outFile = new File(outFileName)
outFile.getParentFile().mkdirs()
InputStream inputStream = jarFile.getInputStream(jarEntry)
FileOutputStream fileOutputStream = new FileOutputStream(outFile)
fileOutputStream << inputStream
fileOutputStream.close()
inputStream.close()
}
jarFile.close()
}
return list
}
/**
* 重新打包jar
* @param packagePath 将这个目录下的所有文件打包成jar
* @param destPath 打包好的jar包的绝对路径
*/
public static void zipJar(String packagePath, String destPath) {
File file = new File(packagePath)
JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(destPath))
file.eachFileRecurse { File f ->
String entryName = f.getAbsolutePath().substring(packagePath.length() + 1)
String pkg = entryName.replaceAll('/', '.')
boolean ignore = false
blackList.each { black ->
if (pkg.contains(black)) {
println "found target pkg: ${pkg}"
ignore = true
}
}
if (ignore) {
println("ignore class: ${f}")
} else {
outputStream.putNextEntry(new ZipEntry(entryName))
if (!f.directory) {
InputStream inputStream = new FileInputStream(f)
outputStream << inputStream
inputStream.close()
}
}
}
outputStream.close()
}
}
class MyClassTransform extends Transform {
private Project mProject;
public MyClassTransform(Project p) {
this.mProject = p;
}
@Override
public String getName() {
return "MyClassTransform";
}
@Override
public Set<QualifiedContent.ContentType> getInputTypes() {
return TransformManager.CONTENT_CLASS;
}
@Override
public Set<QualifiedContent.Scope> getScopes() {
return TransformManager.SCOPE_FULL_PROJECT;
}
@Override
public boolean isIncremental() {
return false
}
private void deleteFiles(File dir, FileFilter filter) {
if (dir.file) {
if (filter != null && filter.accept(dir)) {
dir.delete()
}
} else {
File[] files = dir.listFiles()
for (File f : files) {
deleteFiles(f, filter)
}
}
}
@Override
public void transform(Context context,
Collection<TransformInput> inputs,
Collection<TransformInput> referencedInputs,
TransformOutputProvider outputProvider,
boolean isIncremental) throws IOException, TransformException, InterruptedException {
inputs.each {
TransformInput input ->
input.directoryInputs.each {
DirectoryInput directoryInput ->
//BuryInject.injectDir(directoryInput.file.absolutePath,"com\\sasas\\dsdsd")
// 获取output目录</strong></span>
def dest = outputProvider.getContentLocation(directoryInput.name,
directoryInput.contentTypes, directoryInput.scopes,
Format.DIRECTORY);
deleteFiles(directoryInput.file, new FileFilter() {
@Override
boolean accept(File pathname) {
String abspath = pathname.absolutePath.replaceAll("/", ".")
for (String s : JarZipUtil.blackList) {
if (abspath.contains(s)) {
println "ignore class: ${pathname}, for: ${s}"
return true
} else {
println "${pathname} does not contains: ${s}"
}
}
return false
}
})
println("" + directoryInput.file + " transform" + dest);
FileUtils.copyDirectory(directoryInput.file, dest)
}
input.jarInputs.each {
JarInput jarInput ->
def jarName = jarInput.name
injectJar(jarInput.file.absolutePath)
if (jarName.endsWith(".jar")) {
jarName = jarName.substring(0, jarName.length() - 4)
}
def dest = outputProvider.getContentLocation(jarName,
jarInput.contentTypes, jarInput.scopes, Format.JAR)
println("jar " + jarInput.file + " transform " + dest)
FileUtils.copyFile(jarInput.file, dest)
}
}
}
public static void injectJar(String path) {
if (path.endsWith(".jar")) {
File jarFile = new File(path)
String jarZipDir = jarFile.getParent() + "/" + jarFile.getName().replace('.jar', '')
List classNameList = JarZipUtil.unzipJar(path, jarZipDir)
jarFile.delete()
for (String className : classNameList) {
if (className.endsWith(".class")
&& !className.contains('R$')
&& !className.contains('R.class')
&& !className.contains("BuildConfig.class")) {
String tmp = className.substring(0, className.lastIndexOf('.'))
tmp = tmp.substring(0, tmp.lastIndexOf('.'))
// println "processing package : ${tmp}"
}
}
JarZipUtil.zipJar(jarZipDir, path)
FileUtils.deleteDirectory(new File(jarZipDir))
}
}
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
def classTransform = new MyClassTransform(project)
project.android.registerTransform(classTransform)
}
}
apply plugin: GreetingPlugin
@softwareboy92
Copy link

大佬,弱弱的问一句,这个插件怎么用啊?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment