123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- import org.objectweb.asm.ClassReader
- import org.objectweb.asm.ClassWriter
- import org.objectweb.asm.Opcodes
- import org.objectweb.asm.tree.AnnotationNode
- import org.objectweb.asm.tree.ClassNode
- import org.objectweb.asm.tree.FieldNode
- import org.objectweb.asm.tree.InnerClassNode
- import org.objectweb.asm.tree.MethodNode
- import java.nio.file.Paths
- import java.util.jar.JarEntry
- import java.util.jar.JarFile
- import java.util.jar.JarOutputStream
- import java.util.zip.ZipEntry
- buildscript {
- repositories {
- maven { url "https://maven.aliyun.com/repository/public/" }
- }
- dependencies {
- classpath 'org.ow2.asm:asm-commons:9.2'
- }
- }
- Project frameworks = project(":Frameworks")
- gradle.projectsEvaluated {
- Task frameworksJarTask = null
- try {
- frameworksJarTask = frameworks.tasks.named("jar").get()
- } catch (Throwable ex) {
- ex.printStackTrace()
- }
- if (frameworksJarTask == null) {
- return
- }
- File frameworksJar = null
- frameworksJarTask.outputs.files.files.forEach {
- if (it.getName() == "Frameworks.jar") {
- frameworksJar = it
- }
- }
- if (frameworksJar == null) {
- return
- }
- // 获取SDK路径
- // android.sdkDirectory.getAbsolutePath()
- File sdkJar = new File(Paths.get(android.sdkDirectory.getAbsolutePath(), "platforms",
- "android-${sdkInt}", "android.jar").toString())
- File resultJar = new File(frameworksJar.getParent(), "android-${sdkInt}.jar")
- File tempDir = new File(frameworks.getBuildDir(), "tmp")
- File inputFile = new File(tempDir, System.currentTimeMillis() + ".txt")
- Project currentProject = project
- Task currentPreBuild = currentProject.tasks.named("preBuild").get()
- currentPreBuild.doLast {
- // 只有当frameworksJarTask未执行时才添加输入文件
- if (!frameworksJarTask.getState().executed) {
- if (!tempDir.exists()) {
- tempDir.mkdirs()
- }
- if (!inputFile.exists()) {
- inputFile.createNewFile()
- }
- // 为了避免UP-TO-DATE导致doLast不执行,这里随机添加一个输入文件
- frameworksJarTask.inputs.file(inputFile)
- }
- }
- frameworksJarTask.doLast {
- inputFile.delete()
- // 只有在编译当前Module时才去合并对应的jar
- if (currentPreBuild.getState().executed) {
- println("mergeJar -> $currentProject")
- try {
- if (resultJar.exists()) {
- resultJar.delete()
- }
- ClassMerge.mergeJar(resultJar, sdkJar, frameworksJar, "$sdkInt")
- } catch (Throwable ex) {
- ex.printStackTrace()
- }
- }
- }
- // 针对kotlin代码编译,需要加此设置才能编译通过
- if (project.getPlugins().findPlugin("kotlin-android") != null) {
- project.dependencies {
- compileOnly files(resultJar)
- }
- }
- tasks.withType(JavaCompile).configureEach {
- String taskName = it.name
- if (taskName.contains("UnitTest") || taskName.contains("AndroidTest")) {
- return
- }
- it.doFirst {
- // File androidJar = null
- // // android.jar在classpath中或者在bootstrapClasspath中
- // // TODO AndHub 规律暂时未知?
- // classpath.files.forEach {
- // if (it.getName() == "android.jar") {
- // androidJar = it
- // }
- // }
- // options.bootstrapClasspath.files.forEach {
- // if (it.getName() == "android.jar") {
- // androidJar = it
- // }
- // }
- //
- // println("classpath framework jar = ${resultJar}")
- //
- // try {
- // ClassMerge.mergeJar(resultJar, androidJar, frameworksJar, "$sdkInt")
- // } catch (Throwable ex) {
- // ex.printStackTrace()
- // }
- // android.jar在classpath中则需要设置classpath
- // android.jar在bootstrapClasspath中则需要设置bootstrapClasspath
- // 这里都设置一下
- classpath = files(resultJar, classpath)
- options.bootstrapClasspath = files(resultJar, options.bootstrapClasspath)
- }
- }
- }
- dependencies {
- compileOnly frameworks
- }
- class ClassMerge {
- /**
- * 合并jar文件中的class,规则:<br/>
- * 1、frameworksJar中的class如果在androidJar中能找到同类则进行合并后写入resultJar中<br/>
- * 2、frameworksJar中的class如果在androidJar找不到到同类则直接写入resultJar中
- *
- * @param resultJar 合并后的jar文件
- * @param androidJar SDK中对应版本的android.jar
- * @param frameworksJar Frameworks module编译出的jar文件
- *
- * @throws Exception
- */
- static void mergeJar(File resultJar, File androidJar, File frameworksJar, String sdkInt) throws Exception {
- // 这里只合并一次,不然在extractXxxAnnotations任务中会报错
- // WARN: Could not read file:
- // xxx/Frameworks/build/libs/android-32.jar!/android/graphics/drawable/Drawable.class;
- // size in bytes: 10378; file type: CLASS
- // java.util.zip.ZipException: zip END header not found
- // 可能是文件流被占用的原因
- if (resultJar.exists()) {
- return
- }
- JarOutputStream jos = new JarOutputStream(new FileOutputStream(resultJar))
- JarFile androidJarFile = new JarFile(androidJar)
- JarFile frameworksJarFile = new JarFile(frameworksJar)
- Enumeration<JarEntry> enumeration = frameworksJarFile.entries()
- while (enumeration.hasMoreElements()) {
- JarEntry jarEntry = enumeration.nextElement()
- String entryName = jarEntry.getName()
- // 过滤掉commons下面的class
- if (entryName.startsWith("commons/") || entryName.startsWith("META-INF/")) {
- continue
- }
- ZipEntry zipEntry = new ZipEntry(entryName)
- jos.putNextEntry(zipEntry)
- ZipEntry androidJarZip = androidJarFile.getEntry(entryName)
- byte[] byteCode
- if (androidJarZip != null && entryName.endsWith(".class")) {
- byte[] baseClassByte = androidJarFile.getInputStream(jarEntry).readAllBytes()
- byte[] copyClassByte = frameworksJarFile.getInputStream(jarEntry).readAllBytes()
- byteCode = mergeAndFixClass(baseClassByte, copyClassByte, sdkInt)
- } else {
- // android.jar中无此class,直接拷贝,无需合并
- byte[] baseClassByte = frameworksJarFile.getInputStream(jarEntry).readAllBytes()
- // 这里除了class还有文件夹,baseClassByte.length为0
- // META-INF/MANIFEST.MF
- if (entryName.endsWith(".class")) {
- byteCode = mergeAndFixClass(baseClassByte, null, sdkInt)
- } else {
- byteCode = baseClassByte
- }
- }
- jos.write(byteCode)
- jos.closeEntry()
- }
- jos.close()
- androidJarFile.close()
- frameworksJarFile.close()
- }
- private static byte[] mergeAndFixClass(byte[] baseClassByte, byte[] copyClassByte, String sdkInt) throws Exception {
- int api = Opcodes.ASM9
- int flags = ClassWriter.COMPUTE_FRAMES
- ClassReader baseClassReader = new ClassReader(baseClassByte)
- ClassNode baseClassNode = new ClassNode(api)
- baseClassReader.accept(baseClassNode, 0)
- // 需要将访问属性改为public的类
- Set<String> publicClass = new HashSet<>()
- publicClass.add("android/annotation/NonNull")
- publicClass.add("android/annotation/Nullable")
- if (publicClass.contains(baseClassNode.name)) {
- baseClassNode.access = baseClassNode.access | Opcodes.ACC_PUBLIC
- }
- List<MethodNode> baseClassMethods = fixMethod(baseClassNode.methods, sdkInt)
- List<FieldNode> baseClassFields = fixField(baseClassNode.fields, sdkInt)
- if (copyClassByte != null) {
- ClassReader copyClassReader = new ClassReader(copyClassByte)
- ClassNode copyClassNode = new ClassNode(api)
- copyClassReader.accept(copyClassNode, 0)
- List<MethodNode> methods = fixMethod(copyClassNode.methods, sdkInt)
- Formatter formatter = new Formatter(Locale.getDefault())
- for (MethodNode node : methods) {
- // 过滤掉重复方法,会什么会有重复方法?
- // 有些版本的android.jar中没有此方法,有些版本中有此方法,
- // 导致Frameworks.jar中的方法和android.jar中的方法重复
- if (methodExists(baseClassMethods, node)) {
- String access = formatter.format("0x%04x", node.access).toString()
- println("重复方法->[${copyClassNode.name}] $access ${node.name} ${node.desc}")
- } else {
- baseClassMethods.add(node)
- }
- }
- // 添加字段
- List<FieldNode> fields = fixField(copyClassNode.fields, sdkInt)
- for (FieldNode node : fields) {
- baseClassFields.add(node)
- }
- // 添加内部类
- for (InnerClassNode node : copyClassNode.innerClasses) {
- if (!innerClassesExists(baseClassNode.innerClasses, node)) {
- baseClassNode.innerClasses.add(node)
- }
- }
- }
- ClassWriter baseClassWriter = new ClassWriter(flags)
- baseClassNode.accept(baseClassWriter)
- return baseClassWriter.toByteArray()
- }
- private static boolean innerClassesExists(List<InnerClassNode> classNodes, InnerClassNode innerClass) {
- for (InnerClassNode node : classNodes) {
- if (node.name == innerClass.name) {
- return true
- }
- }
- return false
- }
- private static boolean methodExists(List<MethodNode> methods, MethodNode method) {
- for (MethodNode node : methods) {
- if (node.name == method.name && node.desc == method.desc) {
- return true
- }
- }
- return false
- }
- private static List<FieldNode> fixField(List<FieldNode> fields, String sdkInt) {
- for (FieldNode node : fields) {
- // 修改字段类型
- fixNodeDesc(node, node.visibleAnnotations, sdkInt)
- // 清除掉字段上的注解,如:
- // java.lang.Deprecated
- // RetentionPolicy.RUNTIME注解
- node.visibleAnnotations = Collections.emptyList()
- // RetentionPolicy.CLASS注解
- node.invisibleAnnotations = Collections.emptyList()
- }
- return fields
- }
- private static List<MethodNode> fixMethod(List<MethodNode> methods, String sdkInt) {
- for (MethodNode node : methods) {
- // 修改方法描述符
- fixNodeDesc(node, node.visibleAnnotations, sdkInt)
- int newAccess = node.access
- // 将将构造方法改为public
- if ("<init>" == node.name) {
- int maskFlag = newAccess & 0x000F
- // private、protected、默认修饰符
- if (maskFlag == Opcodes.ACC_PRIVATE
- || maskFlag == Opcodes.ACC_PROTECTED
- || maskFlag == 0) {
- newAccess = (newAccess & 0xFFF0) | Opcodes.ACC_PUBLIC
- }
- }
- // 去掉方法deprecated标记
- if ((newAccess & 0xF0000) == Opcodes.ACC_DEPRECATED) {
- newAccess = newAccess & 0x0FFFF
- }
- node.access = newAccess
- // 清除掉方法参数和返回值上的注解,如:
- // android.annotation.Nullable
- // android.annotation.NonNull
- // RetentionPolicy.RUNTIME注解
- node.visibleAnnotations = Collections.emptyList()
- node.visibleParameterAnnotations = Collections.emptyList()
- // RetentionPolicy.CLASS注解
- node.invisibleAnnotations = Collections.emptyList()
- node.invisibleParameterAnnotations = Collections.emptyList()
- }
- return methods
- }
- private static void fixNodeDesc(Object node, List<AnnotationNode> annotations, String sdkInt) {
- if (node == null && annotations == null && annotations.size() == 0) {
- return
- }
- for (AnnotationNode annotation : annotations) {
- String desc = annotation.desc
- if (desc == "Lcommons/annotations/MethodDescriptor;"
- || desc == "Lcommons/annotations/FieldType;") {
- List<Object> values = annotation.values
- // 注解方法和值依次排列,方法在前,值在后
- // MethodDescriptor [version, 31, value, (IZ)Landroid/window/TaskSnapshot;]
- // FieldType [version, 31, value, [Landroid/graphics/Insets;]
- if (values != null && values.size() == 4 && values.get(1).toString() == sdkInt) {
- node.desc = values.get(3)
- }
- } else if (desc == "Lcommons/annotations/MethodDescriptor\$MethodDescriptors;"
- || desc == "Lcommons/annotations/FieldType\$FieldTypes;") {
- // 注解方法和值依次排列,方法在前,值在后
- // annotationNode.values第一个值为value,第2个值为数组
- // [value, [org.objectweb.asm.tree.AnnotationNode@797081d1, org.objectweb.asm.tree.AnnotationNode@7035ba64]]
- for (AnnotationNode object : annotation.values.get(1)) {
- List<Object> values = object.values
- if (values != null && values.size() == 4 && values.get(1).toString() == sdkInt) {
- node.desc = values.get(3)
- }
- }
- }
- }
- }
- }
|