diff --git a/app/build.gradle b/app/build.gradle index 2a84a35a0..2c06c7e44 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,24 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' + +apply plugin: 'me.yifeiyuan.flap.plugin' + +buildscript { + repositories { + google() + jcenter() + + maven { + url = "$rootProject.projectDir/repos" + } + } + + dependencies { + classpath 'me.yifeiyuan.flap:plugin:1.0.0.1' + } +} android { compileSdkVersion 29 @@ -17,7 +35,10 @@ android { arguments = [autoRegister:'true'] } } + + multiDexEnabled true } + buildTypes { release { minifyEnabled false @@ -25,6 +46,15 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } + dataBinding { enabled = true } @@ -33,21 +63,25 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation project(':flap') - implementation project(':flap-annotations') - annotationProcessor project(':flap-compiler') +// implementation project(':flap') +// implementation project(':flap-annotations') +// annotationProcessor project(':flap-compiler') -// implementation 'me.yifeiyuan.flap:flap-annotations:1.5.1' -// implementation 'me.yifeiyuan.flap:flap:1.5.2' -// annotationProcessor 'me.yifeiyuan.flap:flap-compiler:1.5.1' + implementation 'me.yifeiyuan.flap:flap-annotations:1.6.1' + implementation 'me.yifeiyuan.flap:flap:1.6.1' + kapt 'me.yifeiyuan.flap:flap-compiler:1.6.1' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + def multidex_version = "2.0.1" + implementation "androidx.multidex:multidex:$multidex_version" + } diff --git a/app/src/androidTest/java/me/yifeiyuan/flapdev/ExampleInstrumentedTest.java b/app/src/androidTest/java/me/yifeiyuan/flapdev/ExampleInstrumentedTest.java index e76588655..157a15174 100644 --- a/app/src/androidTest/java/me/yifeiyuan/flapdev/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/me/yifeiyuan/flapdev/ExampleInstrumentedTest.java @@ -19,8 +19,8 @@ public class ExampleInstrumentedTest { @Test public void useAppContext() { // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); +// Context appContext = InstrumentationRegistry.getTargetContext(); - assertEquals("me.yifeiyuan.flapdev", appContext.getPackageName()); +// assertEquals("me.yifeiyuan.flapdev", appContext.getPackageName()); } } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/AsmTest.java b/app/src/main/java/me/yifeiyuan/flapdev/AsmTest.java new file mode 100644 index 000000000..42827e5df --- /dev/null +++ b/app/src/main/java/me/yifeiyuan/flapdev/AsmTest.java @@ -0,0 +1,36 @@ +package me.yifeiyuan.flapdev; + +import me.yifeiyuan.flap.Flap; +import me.yifeiyuan.flap.apt.proxies.SimpleImageComponentProxy; +import me.yifeiyuan.flap.apt.proxies.SimpleTextComponentProxy; + +/** + * Created by 程序亦非猿 on 2020/9/8. + * + * todo proxy 类的名字是 me/xxx/xxxProxy + * + * L1 + * LINENUMBER 16 L1 + * ALOAD 2 + * NEW me/yifeiyuan/flap/apt/proxies/SimpleTextComponentProxy + * DUP + * INVOKESPECIAL me/yifeiyuan/flap/apt/proxies/SimpleTextComponentProxy. ()V + * INVOKEVIRTUAL me/yifeiyuan/flap/Flap.register (Lme/yifeiyuan/flap/internal/ComponentProxy;)Lme/yifeiyuan/flap/ComponentRegistry; + * POP + * L2 + * LINENUMBER 18 L2 + * ALOAD 2 + * NEW me/yifeiyuan/flap/apt/proxies/SimpleImageComponentProxy + * DUP + * INVOKESPECIAL me/yifeiyuan/flap/apt/proxies/SimpleImageComponentProxy. ()V + * INVOKEVIRTUAL me/yifeiyuan/flap/Flap.register (Lme/yifeiyuan/flap/internal/ComponentProxy;)Lme/yifeiyuan/flap/ComponentRegistry; + * POP + * + */ +class AsmTest { + + private void foo(Flap flap){ + flap.register(new SimpleTextComponentProxy()); + flap.register(new SimpleImageComponentProxy()); + } +} diff --git a/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java index f50cd11e8..843632fe6 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java +++ b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java @@ -1,8 +1,11 @@ package me.yifeiyuan.flapdev; -import android.app.Application; +import android.content.Context; import android.util.Log; +import androidx.multidex.MultiDex; +import androidx.multidex.MultiDexApplication; + import me.yifeiyuan.flap.Flap; import me.yifeiyuan.flapdev.components.customviewtype.CustomViewTypeComponent; @@ -10,7 +13,7 @@ * Flap * Created by 程序亦非猿 on 2018/12/13. */ -public class FlapApplication extends Application { +public class FlapApplication extends MultiDexApplication { @Override public void onCreate() { diff --git a/app/src/main/java/me/yifeiyuan/flapdev/components/simpletext/SimpleTextComponent.java b/app/src/main/java/me/yifeiyuan/flapdev/components/simpletext/SimpleTextComponent.java index 3b134799b..12a9c6299 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/components/simpletext/SimpleTextComponent.java +++ b/app/src/main/java/me/yifeiyuan/flapdev/components/simpletext/SimpleTextComponent.java @@ -12,7 +12,7 @@ /** * Created by 程序亦非猿 on 2018/12/4. */ -@Proxy(layoutId = R.layout.flap_item_simple_text, autoRegister = true) +@Proxy(layoutId = R.layout.flap_item_simple_text, autoRegister = false) public class SimpleTextComponent extends Component { private static final String TAG = "SimpleTextItem"; diff --git a/build.gradle b/build.gradle index 3dfb40e25..4eae22e6c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,10 @@ buildscript { repositories { google() jcenter() + + maven { + url = "$rootProject.projectDir/repos" + } } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' @@ -16,6 +20,7 @@ buildscript { // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } diff --git a/flap-annotations/build.gradle b/flap-annotations/build.gradle index f0d7f9acc..dd535bd9f 100644 --- a/flap-annotations/build.gradle +++ b/flap-annotations/build.gradle @@ -14,7 +14,7 @@ publish { userOrg = 'alancheen' groupId = 'me.yifeiyuan.flap' artifactId = 'flap-annotations' - publishVersion = '1.5.1' + publishVersion = '1.6.1' desc = 'flap annotations' website = 'https://github.com/AlanCheen/Flap' } \ No newline at end of file diff --git a/flap-compiler/build.gradle b/flap-compiler/build.gradle index 6fc418990..bb5cef410 100644 --- a/flap-compiler/build.gradle +++ b/flap-compiler/build.gradle @@ -16,7 +16,7 @@ publish { userOrg = 'alancheen' groupId = 'me.yifeiyuan.flap' artifactId = 'flap-compiler' - publishVersion = '1.5.2' + publishVersion = '1.6.1' desc = 'flap annotations' website = 'https://github.com/AlanCheen/Flap' } \ No newline at end of file diff --git a/flap-gradle-plugin/.gitignore b/flap-gradle-plugin/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/flap-gradle-plugin/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/flap-gradle-plugin/build.gradle b/flap-gradle-plugin/build.gradle new file mode 100644 index 000000000..5b8bce32d --- /dev/null +++ b/flap-gradle-plugin/build.gradle @@ -0,0 +1,48 @@ +apply plugin: 'java-library' +apply plugin: 'maven-publish' + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation gradleApi() + implementation localGroovy() + implementation 'com.android.tools.build:gradle:3.2.1' //transform api 需要 + + implementation 'org.ow2.asm:asm-all:5.2' +} + +sourceCompatibility = "1.8" +targetCompatibility = "1.8" + +repositories { + mavenCentral() +} + +publishing { + + publications { + + mavenJava(MavenPublication) { + artifactId = 'plugin' + groupId = 'me.yifeiyuan.flap' + from components.java + version = '1.0.0.1' + } + } + + repositories { + maven { + url = "$rootProject.projectDir/repos" + } + } +} + +apply plugin: 'com.novoda.bintray-release' + +publish { + userOrg = 'alancheen' + groupId = 'me.yifeiyuan.flap' + artifactId = 'flap-plugin' + publishVersion = '1.0.0' + desc = 'flap plugin' + website = 'https://github.com/AlanCheen/Flap' +} \ No newline at end of file diff --git a/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/AutoRegister.java b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/AutoRegister.java new file mode 100644 index 000000000..cfc80acd6 --- /dev/null +++ b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/AutoRegister.java @@ -0,0 +1,155 @@ +package me.yifeiyuan.flap.plugin; + +import org.apache.commons.io.IOUtils; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; + +import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Opcodes.DUP; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.POP; + + +/** + * Created by 程序亦非猿 on 2020/9/8. + */ +class AutoRegister { + + //需要被注入的 Proxy 的类名 + private List classNames; + + public AutoRegister(List classNames) { + this.classNames = classNames; + } + + /** + * todo 可能 className 直接搞个列表一起处理就行了 + * + * @param flapFile Flap 这个类所在的 jar 包文件 + */ + public void registerFor(File flapFile) { + + Log.println("registerFor"); + + File optJar = new File(flapFile.getParent(), flapFile.getName() + ".opt"); + if (optJar.exists()) { + optJar.delete(); + } + + try { + JarFile jarFile = new JarFile(flapFile); + + Enumeration entries = jarFile.entries(); + + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(optJar)); + + while (entries.hasMoreElements()) { + + JarEntry jarEntry = entries.nextElement(); + + String entryName = jarEntry.getName(); + + ZipEntry zipEntry = new ZipEntry(entryName); + + InputStream inputStream = jarFile.getInputStream(jarEntry); + + jarOutputStream.putNextEntry(zipEntry); + + if (FlapTransform.FLAP_CLASS_FILE_NAME.equals(entryName)) { + Log.println("发现 Flap class,准备注入代码:" + entryName); + byte[] bytes = visitFlap(inputStream); + jarOutputStream.write(bytes); + } else { + jarOutputStream.write(IOUtils.toByteArray(inputStream)); + } + + inputStream.close(); + jarOutputStream.closeEntry(); + } + + jarOutputStream.close(); + jarFile.close(); + + if (flapFile.exists()) { + flapFile.delete(); + } + optJar.renameTo(flapFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private byte[] visitFlap(InputStream inputStream) throws IOException { + ClassReader cr = new ClassReader(inputStream); + ClassWriter cw = new ClassWriter(cr, 0); + ClassVisitor cv = new FlapClassVisitor(Opcodes.ASM5, cw); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + return cw.toByteArray(); + } + + class FlapClassVisitor extends ClassVisitor { + + FlapClassVisitor(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + + if (FlapTransform.FLAP_INJECT_METHOD_NAME.equals(name)) { + mv = new InjectMethodVisitor(Opcodes.ASM5, mv); + Log.println("visitMethod 找到注入方法 准备注入:" + name); + } + + return mv; + } + } + + class InjectMethodVisitor extends MethodVisitor { + + public InjectMethodVisitor(int i, MethodVisitor methodVisitor) { + super(i, methodVisitor); + } + + @Override + public void visitInsn(int opcode) { + + for (String className : classNames) { + + Log.println(">>>>>>>>> 正在注入:" + className); + + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(NEW, className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "me/yifeiyuan/flap/Flap", "register", "(Lme/yifeiyuan/flap/internal/ComponentProxy;)Lme/yifeiyuan/flap/ComponentRegistry;", false); + mv.visitInsn(POP); + } + + super.visitInsn(opcode); + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack + 4, maxLocals); + } + } +} diff --git a/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapPlugin.java b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapPlugin.java new file mode 100644 index 000000000..155d03856 --- /dev/null +++ b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapPlugin.java @@ -0,0 +1,19 @@ +package me.yifeiyuan.flap.plugin; + +import com.android.build.gradle.AppExtension; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.jetbrains.annotations.NotNull; + +/** + * Created by 程序亦非猿 on 2020/9/8. + */ +class FlapPlugin implements Plugin { + @Override + public void apply(@NotNull Project project) { + Log.setup(project); + AppExtension appExtension = project.getExtensions().getByType(AppExtension.class); + appExtension.registerTransform(new FlapTransform(project)); + } +} diff --git a/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapTransform.java b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapTransform.java new file mode 100644 index 000000000..95d6d7bb6 --- /dev/null +++ b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/FlapTransform.java @@ -0,0 +1,206 @@ +package me.yifeiyuan.flap.plugin; + +import com.android.build.api.transform.DirectoryInput; +import com.android.build.api.transform.Format; +import com.android.build.api.transform.JarInput; +import com.android.build.api.transform.QualifiedContent; +import com.android.build.api.transform.Transform; +import com.android.build.api.transform.TransformException; +import com.android.build.api.transform.TransformInput; +import com.android.build.api.transform.TransformInvocation; +import com.android.build.api.transform.TransformOutputProvider; +import com.android.build.gradle.internal.pipeline.TransformManager; +import com.android.utils.FileUtils; + +import org.apache.commons.codec.digest.DigestUtils; +import org.gradle.api.Project; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Created by 程序亦非猿 on 2020/9/8. + */ +public class FlapTransform extends Transform { + + final String PROXY_PACKAGE_PATH_PREFIX = "me/yifeiyuan/flap/apt/proxies/"; + + public static final String FLAP_CLASS_FILE_NAME = "me/yifeiyuan/flap/Flap.class"; + + public static final String FLAP_INJECT_METHOD_NAME = "injectProxiesByPlugin"; + + //me.yifeiyuan.flap.Flap 那个文件 + private File flapFile; + + private Project project; + + private List proxyClassList = new ArrayList<>(); + + public FlapTransform(Project project) { + this.project = project; + } + + @Override + public String getName() { + return "me.yifeiyuan.flap.FlapTransform"; + } + + @Override + public Set getInputTypes() { + return TransformManager.CONTENT_CLASS; + } + + @Override + public Set getScopes() { + return TransformManager.SCOPE_FULL_PROJECT; + } + + @Override + public boolean isIncremental() { + return false; + } + + @Override + public void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException { + super.transform(transformInvocation); + + Log.println("===================== flap transform start ===================== "); + + if (transformInvocation.isIncremental()) { + Log.println("增量编译"); + } else { + Log.println("全量编译"); + } + + if (!transformInvocation.isIncremental() && transformInvocation.getOutputProvider() != null) { + transformInvocation.getOutputProvider().deleteAll(); + } + + TransformOutputProvider outputProvider = transformInvocation.getOutputProvider(); + + List inputs = (List) transformInvocation.getInputs(); + + for (TransformInput input : inputs) { + //处理 jar 包中的 class 文件,找到 @Proxy 注解生成的文件 + handleJarInputs(outputProvider, input.getJarInputs()); + + // 处理文件夹目录中的 class 文件 + handleDirectoryInputs(outputProvider, input.getDirectoryInputs()); + } + + if (flapFile != null) { + new AutoRegister(proxyClassList).registerFor(flapFile); + } + + Log.println("===================== flap transform end ===================== "); + + } + + private void handleDirectoryInputs(TransformOutputProvider outputProvider, Collection directoryInputs) throws IOException { + Log.println("handleDirectoryInputs"); + for (DirectoryInput directoryInput : directoryInputs) { + + File dest = outputProvider.getContentLocation(directoryInput.getName(), directoryInput.getContentTypes(), directoryInput.getScopes(), Format.DIRECTORY); + + handleFiles(directoryInput.getFile()); + + FileUtils.copyDirectory(directoryInput.getFile(), dest); + } + } + + private void handleFiles(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (File file1 : files) { + handleFiles(file1); + } + } else { + if (file.getAbsolutePath().contains(PROXY_PACKAGE_PATH_PREFIX) && file.getName().endsWith("Proxy.class")) { + Log.println(">>>>>>>>>>>> 发现 proxy class :" + file.getName()); + String fileName = file.getName(); + int index = fileName.indexOf("."); + String className = PROXY_PACKAGE_PATH_PREFIX + fileName.substring(0, index); + Log.println("className:" + className); + proxyClassList.add(className); + } + } + } + + private void handleJarInputs(TransformOutputProvider outputProvider, Collection jarInputs) throws IOException { + Log.println("handleJarInputs start"); + for (JarInput jarInput : jarInputs) { + + String inputName = jarInput.getName(); + + if (inputName.endsWith(".jar")) { + inputName = inputName.substring(0, inputName.length() - 4); + } + + String hex = DigestUtils.md5Hex(jarInput.getFile().getAbsolutePath()); + + File srcFile = jarInput.getFile(); + + String destFileName = inputName + "-" + hex; + File destFile = outputProvider.getContentLocation(destFileName, jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR); + + if (shouldProcessPreDexJarFile(srcFile.getAbsolutePath())) { + scanJarFile(srcFile, destFile); + } + + FileUtils.copyFile(srcFile, destFile); + } + Log.println("handleJarInputs end"); + } + + //Users/xxx/.gradle/caches/transforms-1/files-1.1/cursoradapter-1.0.0.aar/6f2bc1b47d5cce5ab25d89f7c1b420fa/jars/classes.jar + //shouldProcessPreDexJarFile /Users/mingjue/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar + private boolean shouldProcessPreDexJarFile(String path) { + return !path.contains("org.jetbrains") && + !path.contains("androidx.constraintlayout") && + !path.contains("lifecycle-livedata") && + !path.contains("databinding-") && + !path.contains("vectordrawable-") && + !path.contains("/android/m2repository"); + } + + private void scanJarFile(File src, File dest) throws IOException { + if (null != src) { + + JarFile jarFile = new JarFile(src); + + Enumeration entries = jarFile.entries(); + + while (entries.hasMoreElements()) { + JarEntry jarEntry = entries.nextElement(); + String entryName = jarEntry.getName(); + + if (FLAP_CLASS_FILE_NAME.equals(entryName)) {//Flap/flap/build/intermediates/intermediate-jars/debug/classes.jar + Log.println(entryName); + Log.println(">>>>>>>>>>>> 发现 Flap class file <<<<<<<<<<<<"); + flapFile = dest; + } else if (entryName.startsWith(PROXY_PACKAGE_PATH_PREFIX)) { + Log.println(">>>>>>>>> 发现 proxy class :" + entryName); + int index = entryName.indexOf("."); + String className = entryName.substring(0, index); + Log.println("className:" + className); + proxyClassList.add(className); + } + } + + jarFile.close(); + } + + } + + private boolean shouldProcessClass(String entryName) { + return entryName != null && entryName.startsWith(PROXY_PACKAGE_PATH_PREFIX); + } +} diff --git a/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/Log.java b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/Log.java new file mode 100644 index 000000000..210608e4b --- /dev/null +++ b/flap-gradle-plugin/src/main/java/me/yifeiyuan/flap/plugin/Log.java @@ -0,0 +1,28 @@ +package me.yifeiyuan.flap.plugin; + +import org.gradle.api.Project; +import org.gradle.api.logging.Logger; + +/** + * Created by 程序亦非猿 on 2020/9/8. + */ +class Log { + + private static Logger logger; + + static void setup(Project project) { + logger = project.getLogger(); + } + + static void i(String info) { + logger.info("FlapPlugin:" + info); + } + + static void println(Object obj) { + System.out.println("FlapPlugin: " + obj); + } + + static void println(String msg) { + System.out.println("FlapPlugin: " + msg); + } +} diff --git a/flap-gradle-plugin/src/main/resources/META-INF/gradle-plugins/me.yifeiyuan.flap.plugin.properties b/flap-gradle-plugin/src/main/resources/META-INF/gradle-plugins/me.yifeiyuan.flap.plugin.properties new file mode 100644 index 000000000..ab29d3e16 --- /dev/null +++ b/flap-gradle-plugin/src/main/resources/META-INF/gradle-plugins/me.yifeiyuan.flap.plugin.properties @@ -0,0 +1 @@ +implementation-class=me.yifeiyuan.flap.plugin.FlapPlugin \ No newline at end of file diff --git a/flap/build.gradle b/flap/build.gradle index f31c2fdae..09a9786bc 100644 --- a/flap/build.gradle +++ b/flap/build.gradle @@ -33,7 +33,7 @@ dependencies { apply plugin: "guru.stefma.bintrayrelease" -version = "1.5.2" +version = "1.6.1" group = "me.yifeiyuan.flap" androidArtifact { artifactId = "flap" diff --git a/flap/src/main/java/me/yifeiyuan/flap/Flap.java b/flap/src/main/java/me/yifeiyuan/flap/Flap.java index 8e7576011..31107bb0d 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/Flap.java +++ b/flap/src/main/java/me/yifeiyuan/flap/Flap.java @@ -2,6 +2,9 @@ import androidx.annotation.NonNull; +import android.content.ComponentCallbacks2; +import android.content.Context; +import android.content.res.Configuration; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -29,7 +32,7 @@ * @since 1.1 */ @SuppressWarnings("ALL") -public final class Flap implements IFlap { +public final class Flap implements IFlap, ComponentCallbacks2 { private static final String TAG = "Flap"; @@ -51,6 +54,15 @@ public final class Flap implements IFlap { private static volatile Flap sInstance; + public static void setup(@NonNull Context ctx) { + Context applicationContext = ctx.getApplicationContext(); + applicationContext.registerComponentCallbacks(Flap.getDefault()); + } + + public static void setDebug(final boolean isDebugging) { + FlapDebug.setDebug(isDebugging); + } + public static Flap getDefault() { if (sInstance == null) { synchronized (Flap.class) { @@ -71,6 +83,11 @@ private Flap(int typeCount) { viewTypeProxyMapping = new SparseArray<>(typeCount); registerFlowListener(new ComponentPerformanceMonitor()); injectFactories(this); + injectProxiesByPlugin(this); + } + + private void injectProxiesByPlugin(@NonNull final Flap flap) { + } private void injectFactories(@NonNull final Flap flap) { @@ -197,10 +214,6 @@ public boolean onFailedToRecycleView(@NonNull final Component component, @Non return component.onFailedToRecycleView(flapAdapter); } - public static void setDebug(final boolean isDebugging) { - FlapDebug.setDebug(isDebugging); - } - public ComponentPool getComponentPool() { return GLOBAL_POOL; } @@ -214,4 +227,19 @@ public void registerFlowListener(final ComponentFlowListener componentFlowListen public void unregisterFlowListener(final ComponentFlowListener componentFlowListener) { flowListeners.remove(componentFlowListener); } + + @Override + public void onTrimMemory(int level) { + GLOBAL_POOL.onTrimMemory(level); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + GLOBAL_POOL.onConfigurationChanged(newConfig); + } + + @Override + public void onLowMemory() { + GLOBAL_POOL.onLowMemory(); + } } diff --git a/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPerformanceMonitor.java b/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPerformanceMonitor.java index 0157f7ad7..eaaa3f03f 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPerformanceMonitor.java +++ b/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPerformanceMonitor.java @@ -17,7 +17,7 @@ */ public class ComponentPerformanceMonitor implements ComponentFlowListener { - private static final String TAG = "PerformanceMonitor"; + private static final String TAG = "Flap-PerformanceMonitor"; private long createTime; private long bindTime; diff --git a/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPool.java b/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPool.java index 48e4cfc20..c3d09d1a9 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPool.java +++ b/flap/src/main/java/me/yifeiyuan/flap/extensions/ComponentPool.java @@ -1,5 +1,9 @@ package me.yifeiyuan.flap.extensions; +import android.content.ComponentCallbacks2; +import android.content.res.Configuration; + +import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import me.yifeiyuan.flap.FlapAdapter; @@ -7,14 +11,40 @@ /** * A global RecycledViewPool that can be shared among RecyclerViews , which is enabled by default. * + * @author 程序亦非猿 [Follow me]( https://github.com/AlanCheen) * @see FlapAdapter#setUseComponentPool(boolean) - * + *

* Flap Github: https://github.com/AlanCheen/Flap - * - * @author 程序亦非猿 [Follow me]( https://github.com/AlanCheen) * @since 2019/1/2 * @since 0.9.1 */ -public class ComponentPool extends RecyclerView.RecycledViewPool { +public class ComponentPool extends RecyclerView.RecycledViewPool implements ComponentCallbacks2 { + + @Override + public void onTrimMemory(int level) { + + switch (level) { + case TRIM_MEMORY_RUNNING_CRITICAL: + case TRIM_MEMORY_RUNNING_LOW: + case TRIM_MEMORY_RUNNING_MODERATE: + clear(); + break; + case TRIM_MEMORY_BACKGROUND: + case TRIM_MEMORY_COMPLETE: + case TRIM_MEMORY_MODERATE: + case TRIM_MEMORY_UI_HIDDEN: + default: + break; + } + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + + } + @Override + public void onLowMemory() { + clear(); + } } diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar new file mode 100644 index 000000000..ed30de28b Binary files /dev/null and b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar differ diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.md5 b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.md5 new file mode 100644 index 000000000..1aea8c035 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.md5 @@ -0,0 +1 @@ +9e639b96e7fb15070de45138fa14e752 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.sha1 b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.sha1 new file mode 100644 index 000000000..c8d26acc9 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.jar.sha1 @@ -0,0 +1 @@ +ee37a6d54da681894bfedba8ca164364bdeeea31 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom new file mode 100644 index 000000000..df4b99873 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom @@ -0,0 +1,22 @@ + + + 4.0.0 + me.yifeiyuan.flap + plugin + 1.0.0.0 + + + com.android.tools.build + gradle + 3.2.1 + runtime + + + org.ow2.asm + asm-all + 5.2 + runtime + + + diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.md5 b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.md5 new file mode 100644 index 000000000..fdc6de8bf --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.md5 @@ -0,0 +1 @@ +a55dc704098ef8ff4207742a27c0962d \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.sha1 b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.sha1 new file mode 100644 index 000000000..4a2d926b1 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.0/plugin-1.0.0.0.pom.sha1 @@ -0,0 +1 @@ +e952a845fc59d46580f1a051e75d6b4783da42de \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar new file mode 100644 index 000000000..6af6d6b18 Binary files /dev/null and b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar differ diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.md5 b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.md5 new file mode 100644 index 000000000..25798d646 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.md5 @@ -0,0 +1 @@ +9ea1347996f0f6a962e8a4a2ec54e519 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.sha1 b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.sha1 new file mode 100644 index 000000000..e0457f57c --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.jar.sha1 @@ -0,0 +1 @@ +331282feda3dae173ba7ed181ef04907263d5e4b \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom new file mode 100644 index 000000000..b9afc9463 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom @@ -0,0 +1,22 @@ + + + 4.0.0 + me.yifeiyuan.flap + plugin + 1.0.0.1 + + + com.android.tools.build + gradle + 3.2.1 + runtime + + + org.ow2.asm + asm-all + 5.2 + runtime + + + diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.md5 b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.md5 new file mode 100644 index 000000000..191807ec5 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.md5 @@ -0,0 +1 @@ +d61d7769c0b1f3a580386d7180f25a03 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.sha1 b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.sha1 new file mode 100644 index 000000000..0f5f1ae7f --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/1.0.0.1/plugin-1.0.0.1.pom.sha1 @@ -0,0 +1 @@ +355294650ff411e947b148f4a385ec1f9d236cb8 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml new file mode 100644 index 000000000..b54266695 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml @@ -0,0 +1,13 @@ + + + me.yifeiyuan.flap + plugin + + 1.0.0.1 + + 1.0.0.0 + 1.0.0.1 + + 20200909033301 + + diff --git a/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.md5 b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.md5 new file mode 100644 index 000000000..19afcfc2c --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.md5 @@ -0,0 +1 @@ +e860f7be3bf66323b3b3381a52b8eda1 \ No newline at end of file diff --git a/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.sha1 b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.sha1 new file mode 100644 index 000000000..586853169 --- /dev/null +++ b/repos/me/yifeiyuan/flap/plugin/maven-metadata.xml.sha1 @@ -0,0 +1 @@ +e56237410e3cc9280f28a3f1255159d0d5454840 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index f9c2945b5..72dc682b5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ +include ':flap-gradle-plugin' include ':app', ':flap', ':flap-annotations', ':flap-compiler'