其实实现思路是简简单单的,就是对AAR剥皮提取其中的classes.jar。直接provided其中的jar即可。
第二个问题,如何Jar依赖AAR也是一样的道理,比如我们要对一组接口打成一个Jar包,但是接口的入参用到了Fragment,不好意思,编译失败,因为找不到Fragment
解决方案
1、获取依赖项对应的AAR地址,通过新增compile的方式对使用者提供入口。
2、extractAarTransform:把AAR拆开提前其中的jar到指定目录,。
3、aarTransform:过滤出所有的Jar文件,并输出。
可悲的是,在Gradle2版本上原生的ExtractAarTransform运行失效,未执行transform方法。没办法只能自己手动调用了。
源码如下:
import com.android.utils.FileUtils
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import com.google.common.io.ByteStreams
import com.google.common.io.Files
import org.gradle.api.artifacts.transform.ArtifactTransform
import javax.inject.Inject
import java.util.jar.JarOutputStream
import java.util.jar.Manifest
import java.util.regex.Pattern
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
apply plugin: 'java-library'
apply plugin: MyPlugin
def SUPPORT_LIBS_VERSION = '25.1.1'
def targetSdkVersion = 19
def cachePath = "build/pitaya-caches/aar2jar"
public class MyPlugin implements Plugin {
@Override
void apply(Project project) {
project.getConfigurations().create("AARCompile", new Action() {
@Override
public void execute(Configuration config) {
}
})
}
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
sourceSets {
main {
java.srcDirs = ['src/main/java/']
}
}
dependencies {
/*
Android Jar
*/
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def sdkDir = properties.getProperty('sdk.dir')
if (isGradle3()) {
compileOnly files("${sdkDir}/platforms/android-${targetSdkVersion}/android.jar")
} else {
project.dependencies.add("compileOnly", files("${sdkDir}/platforms/android-${targetSdkVersion}/android.jar"))
}
AARCompile "com.android.support:appcompat-v7:$SUPPORT_LIBS_VERSION"
AARCompile "com.android.support:recyclerview-v7:$SUPPORT_LIBS_VERSION"
ExtractAarTransform extractAarTransform = new ExtractAarTransform()
extractAarTransform.setOutputDirectory(new File(project.rootDir, cachePath))
AarTransform aarTransform = new AarTransform()
List fileList = Lists.newArrayList()
configurations.AARCompile.files.collect {
if (it.absolutePath.endsWith(".jar")) {
fileList.add(it.absoluteFile)
compileOnly project.files(it.absolutePath)
System.out.println("From AARCompile **===> " + it.absolutePath)
return
}
List tempRoot = extractAarTransform.transform(it.absoluteFile)
List tempAAR2JarFile = aarTransform.transform(tempRoot.get(0))
if (isGradle3()) {
compileOnly project.files(tempAAR2JarFile.toArray())
} else {
project.dependencies.add("compileOnly", project.files(tempAAR2JarFile.toArray()))
}
fileList.add(tempAAR2JarFile)
System.out.println("From AARCompile AAR2JarFiles ===> " + tempAAR2JarFile.toArray())
System.out.println("From AARCompile ===> " + it.absolutePath)
}
}
public class ExtractAarTransform extends ArtifactTransform {
private static final String LIBS_PREFIX = "libs/";
private static final int LIBS_PREFIX_LENGTH = "libs/".length();
private static final int JARS_PREFIX_LENGTH = "jars".length() + 1;
@Inject
public ExtractAarTransform() {
}
public List transform(File input) {
//TODO 1
File outputDir = new File(this.getOutputDirectory(), input.name);
FileUtils.mkdirs(outputDir);
StringBuilder sb = new StringBuilder(20);
sb.append("jars").append(File.separatorChar);
try {
InputStream fis = new BufferedInputStream(new FileInputStream(input));
Throwable var5 = null;
try {
ZipInputStream zis = new ZipInputStream(fis);
Throwable var7 = null;
try {
ZipEntry entry;
try {
while ((entry = zis.getNextEntry()) != null) {
try {
String name = entry.getName();
if (!entry.isDirectory()) {
//TODO 2
String path = name;
if (!name.equals("classes.jar")) {
continue
}
if (!name.equals("classes.jar") && !name.equals("lint.jar")) {
if (name.startsWith("libs/")) {
sb.setLength(JARS_PREFIX_LENGTH);
String path2 = name.substring(LIBS_PREFIX_LENGTH);
if ("classes.jar".equals(path2)) {
sb.append("libs/").append("classes-2.jar");
} else if ("lint.jar".equals(path2)) {
sb.append("libs/").append("lint-2.jar");
} else {
sb.append("libs/").append(path2);
}
path = sb.toString();
}
} else {
sb.setLength(JARS_PREFIX_LENGTH);
sb.append(name);
path = sb.toString();
}
File outputFile = new File(outputDir, path.replace("/".chars[0], File.separatorChar));
FileUtils.mkdirs(outputFile.getParentFile());
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));
Throwable var13 = null;
try {
ByteStreams.copy(zis, outputStream);
outputStream.flush();
} catch (Throwable var81) {
var13 = var81;
throw var81;
} finally {
if (outputStream != null) {
if (var13 != null) {
try {
outputStream.close();
} catch (Throwable var79) {
var13.addSuppressed(var79);
}
} else {
outputStream.close();
}
}
}
}
} finally {
zis.closeEntry();
}
}
} catch (Throwable var84) {
var7 = var84;
throw var84;
}
} finally {
if (zis != null) {
if (var7 != null) {
try {
zis.close();
} catch (Throwable var78) {
var7.addSuppressed(var78);
}
} else {
zis.close();
}
}
}
} catch (Throwable var86) {
var5 = var86;
throw var86;
} finally {
if (fis != null) {
if (var5 != null) {
try {
fis.close();
} catch (Throwable var77) {
var5.addSuppressed(var77);
}
} else {
fis.close();
}
}
}
} catch (Throwable var88) {
throw new RuntimeException(var88);
}
File classesJar = new File(new File(outputDir, "jars"), "classes.jar");
if (!classesJar.exists()) {
try {
Files.createParentDirs(classesJar);
JarOutputStream jarOutputStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(classesJar)), new Manifest());
jarOutputStream.close();
} catch (IOException var80) {
throw new RuntimeException("Cannot create missing classes.jar", var80);
}
}
return ImmutableList.of(outputDir);
}
}
public class AarTransform extends ArtifactTransform {
@Inject
public AarTransform() {
}
public List transform(File input) {
return getJars(input);
}
private static List getJars(File explodedAar) {
List files = Lists.newArrayList();
File jarFolder = new File(explodedAar, "jars");
File file = FileUtils.join(jarFolder, "classes.jar");
if (file.isFile()) {
files.add(file);
}
File localJarFolder = new File(jarFolder, "libs");
File[] jars = localJarFolder.listFiles(new FilenameFilter() {
@Override
boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
});
if (jars != null) {
files.addAll(Arrays.asList(jars));
}
return files;
}
}
private boolean isGradle3() {
Pattern GRADLE_ACCEPTABLE_VERSIONS = Pattern.compile("4\\.\\d*|0\\.\\d*[1-9]\\d*\$")
if (GRADLE_ACCEPTABLE_VERSIONS.matcher(project.getGradle().getGradleVersion()).matches()) {
return true
}
return false
}