├── app ├── .gitignore ├── server │ └── release │ │ ├── app-server-release.apk │ │ └── output.json ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── xml │ │ │ │ └── provider_paths.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ │ └── ic_launcher_background.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── heaton │ │ │ │ └── baselibsample │ │ │ │ ├── Constant.java │ │ │ │ ├── TestComponent.java │ │ │ │ ├── Article.java │ │ │ │ ├── User.java │ │ │ │ ├── MyApplication.java │ │ │ │ └── MainActivity.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── heaton │ │ │ └── baselibsample │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── heaton │ │ └── baselibsample │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── aop-arms ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── ids.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-en │ │ │ └── strings.xml │ │ └── layout │ │ │ └── activity_permission.xml │ │ ├── java │ │ └── cn │ │ │ └── com │ │ │ └── superLei │ │ │ └── aoparms │ │ │ ├── common │ │ │ ├── reflect │ │ │ │ ├── NULL.java │ │ │ │ ├── ReflectException.java │ │ │ │ └── Reflect.java │ │ │ ├── ResourceType.java │ │ │ ├── permission │ │ │ │ ├── IPermission.java │ │ │ │ ├── AopPermissionUtils.java │ │ │ │ └── AopPermissionActivity.java │ │ │ ├── utils │ │ │ │ ├── FileUtils.java │ │ │ │ ├── RxJavaHelper.java │ │ │ │ ├── Preconditions.java │ │ │ │ ├── IOUtils.java │ │ │ │ └── ArmsPreference.java │ │ │ ├── collection │ │ │ │ └── NoEmptyHashMap.java │ │ │ ├── statistic │ │ │ │ ├── StatisticsLife.java │ │ │ │ ├── ActivityLifecycleImpl.java │ │ │ │ └── StatisticInfo.java │ │ │ ├── PathUtils.java │ │ │ ├── assist │ │ │ │ └── TestAssist.java │ │ │ ├── systrace │ │ │ │ └── SystraceMonitor.java │ │ │ └── PkgScanner.java │ │ │ ├── callback │ │ │ ├── Interceptor.java │ │ │ └── StatisticCallback.java │ │ │ ├── annotation │ │ │ ├── Callback.java │ │ │ ├── MainThread.java │ │ │ ├── Prefs.java │ │ │ ├── DelayAway.java │ │ │ ├── ScheduledAway.java │ │ │ ├── Statistics.java │ │ │ ├── Async.java │ │ │ ├── Cache.java │ │ │ ├── Intercept.java │ │ │ ├── PrefsEvict.java │ │ │ ├── EnableSystrace.java │ │ │ ├── Permission.java │ │ │ ├── Safe.java │ │ │ ├── Component.java │ │ │ ├── PermissionDenied.java │ │ │ ├── TimeLog.java │ │ │ ├── PermissionNoAskDenied.java │ │ │ ├── SingleClick.java │ │ │ ├── CacheEvict.java │ │ │ ├── Delay.java │ │ │ ├── Retry.java │ │ │ └── Scheduled.java │ │ │ ├── Options.java │ │ │ ├── aspect │ │ │ ├── EnableSystraceAspect.java │ │ │ ├── DelayAwayAspect.java │ │ │ ├── CacheAspect.java │ │ │ ├── ScheduledAwayAspect.java │ │ │ ├── PrefsAspect.java │ │ │ ├── StatisticsAspect.java │ │ │ ├── PrefsEvictAspect.java │ │ │ ├── InterceptAspect.java │ │ │ ├── CacheEvictAspect.java │ │ │ ├── TimeLogAspect.java │ │ │ ├── AsyncAspect.java │ │ │ ├── SingleClickAspect.java │ │ │ ├── SafeAspect.java │ │ │ ├── MainThreadAspect.java │ │ │ ├── DelayAspect.java │ │ │ ├── ScheduledAspect.java │ │ │ ├── RetryAspect.java │ │ │ └── PermissionAspect.java │ │ │ ├── AopArmsInitProvider.java │ │ │ ├── AopArms.java │ │ │ └── AopLog.java │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── .idea ├── caches │ └── gradle_models.ser ├── markdown-navigator │ └── profiles_settings.xml ├── encodings.xml ├── vcs.xml ├── markdown-doclet.xml ├── runConfigurations.xml ├── gradle.xml ├── misc.xml ├── codeStyles │ └── Project.xml └── markdown-navigator.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── gradlew └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /aop-arms/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':aop-arms' 2 | -------------------------------------------------------------------------------- /.idea/caches/gradle_models.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/.idea/caches/gradle_models.ser -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/server/release/app-server-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/server/release/app-server-release.apk -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /aop-arms/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aicareles/AopArms/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AopArms 3 | 确定 4 | 取消 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/reflect/NULL.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.reflect; 2 | 3 | /** 4 | * description $desc$ 5 | * created by jerry on 2019/5/29. 6 | */ 7 | public class NULL { 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/heaton/baselibsample/Constant.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | public class Constant { 4 | public static final int MAIN_ACTIVITY_STATISTIC_KEY = 1; 5 | public static final int TEST_CLICK_STATISTIC_KEY = 2; 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /aop-arms/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 确定 4 | 取消 5 | 去设置 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /aop-arms/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | OK 4 | Cancel 5 | 去设置 6 | 7 | -------------------------------------------------------------------------------- /app/server/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-server-release.apk","fullName":"serverRelease","baseName":"server-release"},"path":"app-server-release.apk","properties":{}}] -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/callback/Interceptor.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.callback; 2 | 3 | /** 4 | * description $desc$ 5 | * created by jerry on 2019/6/3. 6 | */ 7 | public interface Interceptor { 8 | boolean intercept(String key, String methodName) throws Throwable; 9 | } 10 | -------------------------------------------------------------------------------- /aop-arms/src/main/res/layout/activity_permission.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.idea/markdown-doclet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/callback/StatisticCallback.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.callback; 2 | 3 | import cn.com.superLei.aoparms.common.statistic.StatisticInfo; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/6/3. 8 | */ 9 | public interface StatisticCallback { 10 | void statistics(StatisticInfo statisticInfo); 11 | } 12 | -------------------------------------------------------------------------------- /aop-arms/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Callback.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Callback { 11 | } 12 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/MainThread.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.CLASS) 9 | @Target(ElementType.METHOD) 10 | public @interface MainThread { 11 | } 12 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Prefs.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Prefs { 11 | 12 | String key(); 13 | } 14 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/DelayAway.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface DelayAway { 11 | 12 | String key(); 13 | } 14 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/ScheduledAway.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface ScheduledAway { 11 | 12 | String key(); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Statistics.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.METHOD, ElementType.TYPE}) 10 | public @interface Statistics { 11 | int value(); 12 | } 13 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Async.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.CLASS) 9 | @Target(ElementType.METHOD) 10 | public @interface Async { 11 | // int priority() default 5;//一旦改变优先级,则会重新new Thread 12 | } 13 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Cache.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Cache { 11 | 12 | String key(); 13 | 14 | int expiry() default -1; // 过期时间,单位是秒 15 | } 16 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Intercept.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) 10 | public @interface Intercept { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/PrefsEvict.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface PrefsEvict { 11 | 12 | String key(); 13 | 14 | boolean allEntries() default false;//是否清空所有 15 | } 16 | -------------------------------------------------------------------------------- /app/src/test/java/com/heaton/baselibsample/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/EnableSystrace.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD}) 10 | public @interface EnableSystrace { 11 | long filter() default 60L; 12 | boolean containNative() default false; 13 | } 14 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Permission.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Permission { 11 | String[] value(); 12 | 13 | int requestCode() default 1; 14 | 15 | String rationale() default ""; 16 | } 17 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Safe.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * description $desc$ 10 | * created by jerry on 2019/5/30. 11 | */ 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Safe { 15 | 16 | String callBack() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/ResourceType.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common; 2 | 3 | /** 4 | * description $desc$ 5 | * created by jerry on 2019/6/4. 6 | */ 7 | public enum ResourceType { 8 | JAR("jar"), 9 | FILE("file"), 10 | 11 | CLASS_FILE(".class"); 12 | 13 | private String typeString; 14 | 15 | private ResourceType(String type) { 16 | this.typeString = type; 17 | } 18 | 19 | public String getTypeString() { 20 | return this.typeString; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/permission/IPermission.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.permission; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/8/5. 8 | */ 9 | public interface IPermission { 10 | //同意权限 11 | void permissionGranted(); 12 | 13 | //拒绝权限并且选中不再提示 14 | void permissionNoAskDenied(int requestCode, List denyNoAskList); 15 | 16 | //取消权限 17 | void permissionDenied(int requestCode, List denyList); 18 | } 19 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Component.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * description $desc$ 11 | * created by jerry on 2019/6/4. 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | @Documented 16 | public @interface Component { 17 | } -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/PermissionDenied.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * description $desc$ 10 | * created by jerry on 2019/8/5. 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.METHOD) 14 | public @interface PermissionDenied { 15 | 16 | // int requestCode() default 0; 17 | } -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/TimeLog.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 打印方法耗时Log注解, 10 | * 通过aop切片的方式在编译期间织入源代码中 11 | * Created by jerry on 2018/6/13. 12 | */ 13 | 14 | @Retention(RetentionPolicy.CLASS) 15 | @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) 16 | public @interface TimeLog { 17 | } 18 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/PermissionNoAskDenied.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * description $desc$ 10 | * created by jerry on 2019/8/5. 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.METHOD) 14 | public @interface PermissionNoAskDenied { 15 | // String[] value(); 16 | // int requestCode() default 0; 17 | } -------------------------------------------------------------------------------- /aop-arms/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/SingleClick.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import android.view.View; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 防止重复点击 12 | * Created by jerry on 2018/6/13. 13 | */ 14 | 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface SingleClick { 18 | long value() default 500L; 19 | 20 | int[] ids() default {View.NO_ID}; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/heaton/baselibsample/TestComponent.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import android.util.Log; 4 | 5 | import cn.com.superLei.aoparms.annotation.Component; 6 | 7 | /** 8 | * description $desc$ 9 | * created by jerry on 2019/6/4. 10 | */ 11 | @Component 12 | public class TestComponent { 13 | 14 | 15 | private static final String TAG = "TestComponent"; 16 | 17 | public static void main(String[] args) { 18 | byte[] data = new byte[4]; 19 | data[0] = (byte) 255; 20 | data[1] = (byte) 0xff; 21 | 22 | Log.e(TAG, "main: "); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/CacheEvict.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface CacheEvict { 11 | 12 | String key(); 13 | 14 | // 缓存的清除是否在方法之前执行, 默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除 15 | boolean beforeInvocation() default false; 16 | 17 | boolean allEntries() default false;//是否清空所有缓存 18 | } 19 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/reflect/ReflectException.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.reflect; 2 | 3 | public class ReflectException extends RuntimeException { 4 | private static final long serialVersionUID = -6654702552823551870L; 5 | 6 | public ReflectException(String message) { 7 | super(message); 8 | } 9 | 10 | public ReflectException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | 14 | public ReflectException() { 15 | super(); 16 | } 17 | 18 | public ReflectException(Throwable cause) { 19 | super(cause); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/Options.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms; 2 | 3 | //配置类 4 | public class Options { 5 | private boolean isLoggable = false; 6 | private String logTag = "AopArms"; 7 | 8 | public Options() { 9 | } 10 | 11 | public boolean isLoggable() { 12 | return isLoggable; 13 | } 14 | 15 | public Options setLoggable(boolean loggable) { 16 | isLoggable = loggable; 17 | return this; 18 | } 19 | 20 | public String getLogTag() { 21 | return logTag; 22 | } 23 | 24 | public Options setLogTag(String logTag) { 25 | this.logTag = logTag; 26 | return this; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/heaton/baselibsample/Article.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/5/28. 8 | */ 9 | public class Article implements Serializable { 10 | 11 | public String author; 12 | public String title; 13 | public String createDate; 14 | public String content; 15 | 16 | @Override 17 | public String toString() { 18 | return "Article{" + 19 | "author='" + author + '\'' + 20 | ", title='" + title + '\'' + 21 | ", createDate='" + createDate + '\'' + 22 | ", content='" + content + '\'' + 23 | '}'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.utils; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/5/29. 8 | */ 9 | public class FileUtils { 10 | public static boolean exists(File file) { 11 | return file!=null && file.exists(); 12 | } 13 | 14 | /** 15 | * 判断是否文件 16 | * @param file 17 | * @return 18 | */ 19 | public static boolean isFile(File file) { 20 | return exists(file) && file.isFile(); 21 | } 22 | 23 | /** 24 | * 判断是否目录 25 | * @param file 26 | * @return 27 | */ 28 | public static boolean isDirectory(File file) { 29 | return exists(file) && file.isDirectory(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Delay.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.METHOD) 11 | public @interface Delay { 12 | 13 | String key() default ""; 14 | 15 | /** 16 | * 回调是否在异步线程 17 | * @return 18 | */ 19 | boolean asyn() default false; 20 | 21 | int priority() default 5;//一旦改变优先级,则会重新new Thread 22 | 23 | long delay() default 0L; //延迟时间 单位是毫秒 24 | 25 | /** 26 | * 时间单位 27 | * @return 28 | */ 29 | TimeUnit timeUnit() default TimeUnit.MILLISECONDS; 30 | } 31 | -------------------------------------------------------------------------------- /aop-arms/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | #PbintrayKey = 65d7654943c19d5348ae6f6fdb115f8315aa8e5c 16 | #PbintrayUser = liulei 17 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/heaton/baselibsample/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.heaton.baselib", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/heaton/baselibsample/User.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/5/28. 8 | */ 9 | public class User implements Serializable { 10 | private String name; 11 | private String password; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public String getPassword() { 22 | return password; 23 | } 24 | 25 | public void setPassword(String password) { 26 | this.password = password; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "User{" + 32 | "name='" + name + '\'' + 33 | ", password='" + password + '\'' + 34 | '}'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Retry.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * description $desc$ 10 | * created by jerry on 2019/5/30. 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.METHOD) 14 | public @interface Retry { 15 | /** 16 | * 重试次数 17 | * @return 18 | */ 19 | int count() default 0; 20 | 21 | 22 | /** 23 | * 重试的间隔时间 24 | * @return 25 | */ 26 | long delay() default 0L; 27 | 28 | 29 | /** 30 | * 是否支持异步重试方式 31 | * @return 32 | */ 33 | boolean asyn() default false; 34 | 35 | /** 36 | * 重试n次后,结果的回调 37 | * @return 38 | */ 39 | String retryCallback() default ""; 40 | } 41 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep @cn.com.superLei.aoparms.annotation.* class * {*;} 23 | -keep class * { 24 | @cn.com.superLei.aoparms.annotation.* ; 25 | } 26 | -keepclassmembers class * { 27 | @cn.com.superLei.aoparms.annotation.* ; 28 | } -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/annotation/Scheduled.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * description 定时任务 11 | * created by jerry on 2019/5/30. 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.METHOD) 15 | public @interface Scheduled { 16 | 17 | String key() default ""; 18 | /** 19 | * 初始化延迟 20 | * @return 21 | */ 22 | long initialDelay() default 0L; 23 | 24 | /** 25 | * 时间间隔 26 | * @return 27 | */ 28 | long interval(); 29 | 30 | /** 31 | * 时间单位 32 | * @return 33 | */ 34 | TimeUnit timeUnit() default TimeUnit.MILLISECONDS; 35 | 36 | /** 37 | * 执行次数 38 | * @return 39 | */ 40 | int count() default Integer.MAX_VALUE; 41 | 42 | /** 43 | * 定时任务到期回调 44 | * @return 45 | */ 46 | String taskExpiredCallback() default ""; 47 | } 48 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/collection/NoEmptyHashMap.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.collection; 2 | 3 | 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import cn.com.superLei.aoparms.common.utils.Preconditions; 8 | 9 | /** 10 | * description $desc$ 11 | * created by jerry on 2019/5/30. 12 | */ 13 | public class NoEmptyHashMap extends HashMap { 14 | 15 | private static NoEmptyHashMap noEmptyHashMap = new NoEmptyHashMap(); 16 | public static NoEmptyHashMap getInstance() { 17 | return noEmptyHashMap; 18 | } 19 | 20 | private NoEmptyHashMap() { 21 | super(); 22 | } 23 | 24 | @Override 25 | public V put(final K key, final V value) { 26 | if (Preconditions.isBlank(key) || Preconditions.isBlank(value)) { 27 | return null; 28 | } 29 | return super.put(key, value); 30 | } 31 | 32 | @Override 33 | public void putAll(final Map map) { 34 | for (Entry entry : map.entrySet()) { 35 | put(entry.getKey(), entry.getValue()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/statistic/StatisticsLife.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.statistic; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | public class StatisticsLife { 7 | private static final String TAG = StatisticsLife.class.getSimpleName(); 8 | 9 | private static ActivityLifecycleImpl sLifecycleImpl; 10 | 11 | public static ActivityLifecycleImpl getLifecycle() { 12 | return sLifecycleImpl; 13 | } 14 | 15 | public static void registerStatisticsLife(Application application) { 16 | if (sLifecycleImpl == null) { 17 | synchronized (StatisticsLife.class) { 18 | if (sLifecycleImpl == null) { 19 | sLifecycleImpl = new ActivityLifecycleImpl(); 20 | } 21 | } 22 | } 23 | application.registerActivityLifecycleCallbacks(sLifecycleImpl); 24 | } 25 | 26 | public static void unregisterStatisticsLife(Application application) { 27 | if (sLifecycleImpl != null) { 28 | application.unregisterActivityLifecycleCallbacks(sLifecycleImpl); 29 | } else { 30 | Log.i(TAG, "ActivityLifecycleImpl不能为空"); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/EnableSystraceAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.util.Log; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import cn.com.superLei.aoparms.annotation.EnableSystrace; 11 | 12 | /** 13 | * description $desc$ 14 | * created by jerry on 2019/5/30. 15 | */ 16 | @Aspect 17 | public class EnableSystraceAspect { 18 | // private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.EnableSystrace * *(..))"; 19 | private static final String POINTCUT_METHOD = "execution(* android.app.Application.onCreate(..))"; 20 | 21 | @Pointcut(POINTCUT_METHOD) 22 | public void onSystraceMethod() { 23 | 24 | } 25 | 26 | @Around("onSystraceMethod() && @annotation(enableSystrace)") 27 | public Object doSystraceMethod(ProceedingJoinPoint joinPoint, EnableSystrace enableSystrace) throws Throwable { 28 | long filter = enableSystrace.filter(); 29 | boolean containNative = enableSystrace.containNative(); 30 | Class clazz = joinPoint.getClass(); 31 | if (clazz.isAnnotationPresent(EnableSystrace.class)){ 32 | 33 | } 34 | return joinPoint.proceed(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/DelayAwayAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Pointcut; 7 | 8 | import cn.com.superLei.aoparms.annotation.DelayAway; 9 | import cn.com.superLei.aoparms.common.collection.NoEmptyHashMap; 10 | import io.reactivex.disposables.Disposable; 11 | 12 | /** 13 | * description $desc$ 14 | * created by jerry on 2019/5/30. 15 | */ 16 | @Aspect 17 | public class DelayAwayAspect { 18 | private static final String TAG = "DelayAwayAspect"; 19 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.DelayAway * *(..))"; 20 | 21 | @Pointcut(POINTCUT_METHOD) 22 | public void onDelayAwayMethod() { 23 | } 24 | 25 | @Around("onDelayAwayMethod() && @annotation(delayAway)") 26 | public Object doDelayAwayMethod(final ProceedingJoinPoint joinPoint, DelayAway delayAway) throws Throwable { 27 | String key = delayAway.key(); 28 | Disposable subscribe = (Disposable) NoEmptyHashMap.getInstance().get(key); 29 | if (subscribe != null){ 30 | subscribe.dispose(); 31 | NoEmptyHashMap.getInstance().remove(key); 32 | } 33 | return joinPoint.proceed(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/CacheAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Pointcut; 7 | 8 | import java.io.Serializable; 9 | import cn.com.superLei.aoparms.AopArms; 10 | import cn.com.superLei.aoparms.annotation.Cache; 11 | import cn.com.superLei.aoparms.common.utils.ArmsCache; 12 | 13 | /** 14 | * description $desc$ 15 | * created by jerry on 2019/5/30. 16 | */ 17 | @Aspect 18 | public class CacheAspect { 19 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Cache * *(..))"; 20 | 21 | @Pointcut(POINTCUT_METHOD) 22 | public void onCacheMethod() { 23 | } 24 | 25 | @Around("onCacheMethod() && @annotation(cache)") 26 | public Object doCacheMethod(ProceedingJoinPoint joinPoint, Cache cache) throws Throwable { 27 | String key = cache.key(); 28 | int expiry = cache.expiry(); 29 | 30 | Object result = joinPoint.proceed(); 31 | ArmsCache aCache = ArmsCache.get(AopArms.getContext()); 32 | if (expiry>0) { 33 | aCache.put(key,(Serializable)result,expiry); 34 | } else { 35 | aCache.put(key,(Serializable)result); 36 | } 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/ScheduledAwayAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Pointcut; 7 | 8 | import cn.com.superLei.aoparms.annotation.ScheduledAway; 9 | import cn.com.superLei.aoparms.common.collection.NoEmptyHashMap; 10 | import io.reactivex.disposables.Disposable; 11 | 12 | @Aspect 13 | public class ScheduledAwayAspect { 14 | 15 | private static final String TAG = "ScheduledAspect"; 16 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.ScheduledAway * *(..))"; 17 | 18 | @Pointcut(POINTCUT_METHOD) 19 | public void onScheduledAwayMethod() { 20 | } 21 | 22 | @Around("onScheduledAwayMethod() && @annotation(scheduledAway)") 23 | public Object doScheduledAwayMethod(final ProceedingJoinPoint joinPoint, ScheduledAway scheduledAway) throws Throwable { 24 | Object result = null; 25 | String key = scheduledAway.key(); 26 | Disposable subscribe = (Disposable) NoEmptyHashMap.getInstance().get(key); 27 | if (subscribe != null){ 28 | subscribe.dispose(); 29 | NoEmptyHashMap.getInstance().remove(key); 30 | } 31 | result = joinPoint.proceed(); 32 | return result; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/utils/RxJavaHelper.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.utils; 2 | 3 | import android.os.Process; 4 | import android.support.annotation.Size; 5 | 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | import io.reactivex.Scheduler; 10 | import io.reactivex.annotations.NonNull; 11 | import io.reactivex.schedulers.Schedulers; 12 | 13 | public class RxJavaHelper { 14 | 15 | public static ThreadFactory newFactory(@Size(min = 1, max = 10) int priority){ 16 | return new ThreadFactory() { 17 | @Override 18 | public Thread newThread(@NonNull final Runnable r) { 19 | Thread thread = new Thread(new Runnable() { 20 | @Override 21 | public void run() { 22 | //这里的r是线程池或Sceduler的Worker,所以我们要在调用r.run()方法前提前设置优先级 23 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 24 | r.run(); 25 | } 26 | }); 27 | thread.setPriority(priority); 28 | return thread; 29 | } 30 | }; 31 | } 32 | 33 | public static Scheduler scheduler(int priority){ 34 | if (priority!=5){ 35 | return Schedulers.from(Executors.newScheduledThreadPool(1, newFactory(priority))); 36 | } 37 | return Schedulers.io(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/PrefsAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Pointcut; 7 | import org.aspectj.lang.reflect.MethodSignature; 8 | 9 | import cn.com.superLei.aoparms.AopArms; 10 | import cn.com.superLei.aoparms.annotation.Prefs; 11 | import cn.com.superLei.aoparms.common.utils.ArmsPreference; 12 | 13 | 14 | /** 15 | * Created by jerry on 2018/6/13. 16 | */ 17 | 18 | @Aspect 19 | public class PrefsAspect { 20 | 21 | @Pointcut("execution(@cn.com.superLei.aoparms.annotation.Prefs * *(..))") 22 | public void onPrefsMethod() { 23 | } 24 | 25 | @Around("onPrefsMethod() && @annotation(prefs)") 26 | public Object doPrefsMethod(final ProceedingJoinPoint joinPoint, Prefs prefs) throws Throwable { 27 | Object result = null; 28 | if (prefs!=null) { 29 | String key = prefs.key(); 30 | 31 | result = joinPoint.proceed(); 32 | String type = ((MethodSignature) joinPoint.getSignature()).getReturnType().toString(); 33 | 34 | if (!"void".equalsIgnoreCase(type)) { 35 | ArmsPreference.put(AopArms.getContext(), key, result); 36 | } 37 | } else { 38 | // 不影响原来的流程 39 | result = joinPoint.proceed(); 40 | } 41 | 42 | return result; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/StatisticsAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.Signature; 5 | import org.aspectj.lang.annotation.Around; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.aspectj.lang.reflect.MethodSignature; 9 | 10 | import cn.com.superLei.aoparms.AopArms; 11 | import cn.com.superLei.aoparms.annotation.Statistics; 12 | import cn.com.superLei.aoparms.callback.StatisticCallback; 13 | import cn.com.superLei.aoparms.common.statistic.StatisticInfo; 14 | 15 | /** 16 | * description $desc$ 17 | * created by jerry on 2019/5/30. 18 | */ 19 | @Aspect 20 | public class StatisticsAspect { 21 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Statistics * *(..))"; 22 | 23 | @Pointcut(POINTCUT_METHOD) 24 | public void onStatisticsMethod() { 25 | } 26 | 27 | @Around("onStatisticsMethod() && @annotation(statistics)") 28 | public Object doStatisticsMethod(ProceedingJoinPoint joinPoint, Statistics statistics) throws Throwable { 29 | int value = statistics.value(); 30 | StatisticCallback callback = AopArms.getStatisticCallback(); 31 | if (callback != null){ 32 | Signature signature = joinPoint.getSignature(); 33 | if (signature instanceof MethodSignature){ 34 | StatisticInfo info = new StatisticInfo(value, System.currentTimeMillis(),signature.getName(),true); 35 | callback.statistics(info); 36 | } 37 | } 38 | return joinPoint.proceed(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/PrefsEvictAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import cn.com.superLei.aoparms.AopArms; 11 | import cn.com.superLei.aoparms.annotation.PrefsEvict; 12 | import cn.com.superLei.aoparms.common.utils.ArmsPreference; 13 | 14 | 15 | /** 16 | * Created by jerry on 2018/6/13. 17 | */ 18 | 19 | @Aspect 20 | public class PrefsEvictAspect { 21 | 22 | @Pointcut("execution(@cn.com.superLei.aoparms.annotation.PrefsEvict * *(..))") 23 | public void onPrefsEvictMethod() { 24 | } 25 | 26 | @Around("onPrefsEvictMethod() && @annotation(prefsEvict)") 27 | public Object doPrefsEvictMethod(final ProceedingJoinPoint joinPoint, PrefsEvict prefsEvict) throws Throwable { 28 | Object result = null; 29 | if (prefsEvict!=null) { 30 | String key = prefsEvict.key(); 31 | boolean allEntries = prefsEvict.allEntries(); 32 | result = joinPoint.proceed(); 33 | if (allEntries){ 34 | if (!TextUtils.isEmpty(key)) 35 | throw new IllegalArgumentException("Key cannot have value when cleaning all caches"); 36 | ArmsPreference.clear(AopArms.getContext()); 37 | } 38 | ArmsPreference.remove(AopArms.getContext(), key); 39 | } else { 40 | // 不影响原来的流程 41 | result = joinPoint.proceed(); 42 | } 43 | 44 | return result; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/InterceptAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import cn.com.superLei.aoparms.AopArms; 11 | import cn.com.superLei.aoparms.annotation.Intercept; 12 | 13 | /** 14 | * description $desc$ 15 | * created by jerry on 2019/5/30. 16 | */ 17 | @Aspect 18 | public class InterceptAspect { 19 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Intercept * *(..))"; 20 | 21 | @Pointcut(POINTCUT_METHOD) 22 | public void onInterceptMethod() { 23 | } 24 | 25 | @Around("onInterceptMethod() && @annotation(intercept)") 26 | public Object doInterceptMethod(ProceedingJoinPoint joinPoint, Intercept intercept) throws Throwable { 27 | if (AopArms.getInterceptor() == null)return joinPoint.proceed(); 28 | String value = intercept.value(); 29 | if (!TextUtils.isEmpty(value)){ 30 | //拦截 31 | boolean result = proceedIntercept(intercept.value(), joinPoint); 32 | return result ? null : joinPoint.proceed(); 33 | } 34 | return joinPoint.proceed(); 35 | } 36 | 37 | private boolean proceedIntercept(String value, ProceedingJoinPoint joinPoint) throws Throwable { 38 | boolean intercept = AopArms.getInterceptor().intercept(value, joinPoint.getSignature().getName()); 39 | if (intercept){ 40 | return true; 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/CacheEvictAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import cn.com.superLei.aoparms.AopArms; 11 | import cn.com.superLei.aoparms.annotation.CacheEvict; 12 | import cn.com.superLei.aoparms.common.utils.ArmsCache; 13 | 14 | /** 15 | * description $desc$ 16 | * created by jerry on 2019/5/30. 17 | */ 18 | @Aspect 19 | public class CacheEvictAspect { 20 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.CacheEvict * *(..))"; 21 | 22 | @Pointcut(POINTCUT_METHOD) 23 | public void onCacheEvictMethod() { 24 | } 25 | 26 | @Around("onCacheEvictMethod() && @annotation(cacheEvict)") 27 | public Object doCacheEvictMethod(ProceedingJoinPoint joinPoint, CacheEvict cacheEvict) throws Throwable { 28 | String key = cacheEvict.key(); 29 | boolean beforeInvocation = cacheEvict.beforeInvocation(); 30 | boolean allEntries = cacheEvict.allEntries(); 31 | ArmsCache aCache = ArmsCache.get(AopArms.getContext()); 32 | Object result = null; 33 | if (allEntries){ 34 | if (!TextUtils.isEmpty(key)) 35 | throw new IllegalArgumentException("Key cannot have value when cleaning all caches"); 36 | aCache.clear(); 37 | } 38 | if (beforeInvocation){ 39 | aCache.remove(key); 40 | result = joinPoint.proceed(); 41 | }else { 42 | result = joinPoint.proceed(); 43 | aCache.remove(key); 44 | } 45 | return result; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-aspectjx' 3 | 4 | android { 5 | compileSdkVersion 28 6 | defaultConfig { 7 | applicationId "com.heaton.baselibsample" 8 | minSdkVersion 16 9 | targetSdkVersion 28 10 | versionCode 3 11 | versionName "1.0.4" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | 26 | flavorDimensions "default" 27 | productFlavors { 28 | beta { 29 | dimension "default" 30 | } 31 | server { 32 | dimension "default" 33 | } 34 | google { 35 | dimension "default" 36 | } 37 | productFlavors.all { flavor -> 38 | flavor.manifestPlaceholders = [CHANNEL_VALUE: name] 39 | } 40 | } 41 | 42 | } 43 | 44 | dependencies { 45 | implementation fileTree(include: ['*.jar'], dir: 'libs') 46 | implementation 'com.android.support:appcompat-v7:28.0.0' 47 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 48 | testImplementation 'junit:junit:4.12' 49 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 51 | 52 | // implementation 'cn.com.superLei:aop-arms:1.0.4' 53 | implementation project(':aop-arms') 54 | implementation 'com.jakewharton:butterknife:8.8.1' 55 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 56 | } 57 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/PathUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * description $desc$ 7 | * created by jerry on 2019/6/4. 8 | */ 9 | public class PathUtils { 10 | private PathUtils() {} 11 | 12 | /** 13 | * 把路径字符串转换为包名. 14 | * a/b/c/d -> a.b.c.d 15 | * 16 | * @param path 17 | * @return 18 | */ 19 | public static String pathToPackage(String path) { 20 | if (path.startsWith("/")) { 21 | path = path.substring(1); 22 | } 23 | 24 | return path.replaceAll("/", "."); 25 | } 26 | 27 | /** 28 | * 包名转换为路径名 29 | * @param pkg 30 | * @return 31 | */ 32 | public static String packageToPath(String pkg) { 33 | return pkg.replaceAll("\\.", File.separator); 34 | } 35 | 36 | /** 37 | * 将多个对象转换成字符串并连接起来 38 | * @param objs 39 | * @return 40 | */ 41 | public static String concat(Object... objs) { 42 | StringBuilder sb = new StringBuilder(30); 43 | for (int ix = 0 ; ix < objs.length ; ++ix) { 44 | sb.append(objs[ix]); 45 | } 46 | 47 | return sb.toString(); 48 | } 49 | 50 | /** 51 | * 去掉文件的后缀名 52 | * @param name 53 | * @return 54 | */ 55 | public static String trimSuffix(String name) { 56 | int dotIndex = name.indexOf('.'); 57 | if (-1 == dotIndex) { 58 | return name; 59 | } 60 | 61 | return name.substring(0, dotIndex); 62 | } 63 | 64 | public static String distillPathFromJarURL(String url) { 65 | int startPos = url.indexOf(':'); 66 | int endPos = url.lastIndexOf('!'); 67 | 68 | return url.substring(startPos + 1, endPos); 69 | } 70 | 71 | public static void main(String[] args) { 72 | String s = "/a/b/c/d"; 73 | System.out.println(pathToPackage(s)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /aop-arms/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'android-aspectjx' 3 | apply plugin: 'com.novoda.bintray-release' 4 | 5 | android { 6 | compileSdkVersion 28 7 | 8 | defaultConfig { 9 | minSdkVersion 15 10 | targetSdkVersion 28 11 | versionCode 3 12 | versionName "1.0.4" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | 35 | implementation 'com.android.support:appcompat-v7:28.0.0' 36 | implementation "io.reactivex.rxjava2:rxandroid:2.1.0" 37 | implementation "io.reactivex.rxjava2:rxjava:2.2.5" 38 | implementation 'org.aspectj:aspectjrt:1.8.14' 39 | implementation 'org.javassist:javassist:3.20.0-GA' 40 | } 41 | 42 | repositories { 43 | jcenter() 44 | } 45 | 46 | allprojects { 47 | repositories { 48 | jcenter() 49 | } 50 | tasks.withType(Javadoc) { 51 | options{ encoding "UTF-8" 52 | charSet 'UTF-8' 53 | links "http://docs.oracle.com/javase/7/docs/api" 54 | } 55 | } 56 | } 57 | 58 | publish{ 59 | repoName = 'maven'//远程仓库名字,不指明,默认是上传到maven 60 | userOrg = 'superliu'//bintray.com的用户名 61 | groupId = 'cn.com.superLei'//一个唯一值,默认包名,生成的gradle依赖前缀 62 | artifactId = 'aop-arms'//远程仓库包名称 63 | publishVersion = '1.0.4' 64 | desc = 'A very convenient aop library for Android' 65 | website = 'https://github.com/AICareless/AopArms' 66 | licences = ['Apache-2.0'] 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/TimeLogAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.util.Log; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.aspectj.lang.reflect.MethodSignature; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 自动打印方法的耗时 15 | * Created by jerry on 2018/6/13. 16 | */ 17 | 18 | @Aspect 19 | public class TimeLogAspect { 20 | 21 | @Pointcut("execution(@cn.com.superLei.aoparms.annotation.TimeLog * *(..))")//方法切入点 22 | public void methodAnnotated() { 23 | } 24 | 25 | @Pointcut("execution(@cn.com.superLei.aoparms.annotation.TimeLog *.new(..))")//构造器切入点 26 | public void constructorAnnotated() { 27 | } 28 | 29 | @Around("methodAnnotated() || constructorAnnotated()")//在连接点进行方法替换 30 | public Object aroundJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { 31 | MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); 32 | Log.d("TimeLog", methodSignature.getMethod().getDeclaringClass().getCanonicalName()); 33 | String className = methodSignature.getDeclaringType().getSimpleName(); 34 | String methodName = methodSignature.getName(); 35 | long startTime = System.nanoTime(); 36 | Object result = joinPoint.proceed();//执行原方法 37 | StringBuilder keyBuilder = new StringBuilder(); 38 | keyBuilder.append(methodName + ":"); 39 | for (Object obj : joinPoint.getArgs()) { 40 | if (obj instanceof String) keyBuilder.append((String) obj); 41 | else if (obj instanceof Class) keyBuilder.append(((Class) obj).getSimpleName()); 42 | } 43 | String key = keyBuilder.toString(); 44 | Log.d("TimeLog", (className + "." + key + joinPoint.getArgs().toString() + " --->:" + "[" + (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) + "ms]"));// 打印时间差 45 | return result; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/AsyncAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.os.Looper; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import io.reactivex.BackpressureStrategy; 11 | import io.reactivex.Flowable; 12 | import io.reactivex.FlowableEmitter; 13 | import io.reactivex.FlowableOnSubscribe; 14 | import io.reactivex.android.schedulers.AndroidSchedulers; 15 | import io.reactivex.schedulers.Schedulers; 16 | 17 | /** 18 | * description $desc$ 19 | * created by jerry on 2019/5/30. 20 | */ 21 | @Aspect 22 | public class AsyncAspect { 23 | 24 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Async * *(..))"; 25 | 26 | @Around("onAsyncMethod()") 27 | public void doAsyncMethod(final ProceedingJoinPoint joinPoint) throws Throwable { 28 | asyncMethod(joinPoint); 29 | } 30 | 31 | @Pointcut(POINTCUT_METHOD) 32 | public void onAsyncMethod() { 33 | } 34 | 35 | private void asyncMethod(final ProceedingJoinPoint joinPoint) throws Throwable { 36 | 37 | Flowable.create(new FlowableOnSubscribe() { 38 | @Override 39 | public void subscribe(FlowableEmitter e) throws Exception { 40 | Looper.prepare(); 41 | try { 42 | joinPoint.proceed(); 43 | } catch (Throwable throwable) { 44 | throwable.printStackTrace(); 45 | } 46 | Looper.loop(); 47 | } 48 | } 49 | , BackpressureStrategy.BUFFER) 50 | .subscribeOn(Schedulers.io()) 51 | .observeOn(AndroidSchedulers.mainThread()) 52 | .subscribe(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/SingleClickAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | 6 | import org.aspectj.lang.ProceedingJoinPoint; 7 | import org.aspectj.lang.annotation.Around; 8 | import org.aspectj.lang.annotation.Aspect; 9 | import org.aspectj.lang.annotation.Pointcut; 10 | 11 | import java.util.Calendar; 12 | 13 | import cn.com.superLei.aoparms.R; 14 | import cn.com.superLei.aoparms.annotation.SingleClick; 15 | 16 | /** 17 | * Created by jerry on 2018/6/13. 18 | */ 19 | 20 | @Aspect 21 | public class SingleClickAspect { 22 | static int TIME_TAG = R.id.click_time; 23 | 24 | @Pointcut("execution(@cn.com.superLei.aoparms.annotation.SingleClick * *(..))")//方法切入点 25 | public void onSingleClickMethod() { 26 | } 27 | 28 | @Around("onSingleClickMethod() && @annotation(singleClick)")//在连接点进行方法替换 29 | public void doSingleClickMethod(ProceedingJoinPoint joinPoint, SingleClick singleClick) throws Throwable { 30 | View view = null; 31 | for (Object arg : joinPoint.getArgs()) 32 | if (arg instanceof View) view = (View) arg; 33 | if (view != null) { 34 | Object tag = view.getTag(TIME_TAG); 35 | long lastClickTime = ((tag != null) ? (long) tag : 0); 36 | Log.d("SingleClickAspect", "lastClickTime:" + lastClickTime); 37 | long currentTime = Calendar.getInstance().getTimeInMillis(); 38 | long value = singleClick.value(); 39 | int[] ids = singleClick.ids(); 40 | 41 | if (currentTime - lastClickTime > value || !hasId(ids, view.getId())) {//过滤掉500毫秒内的连续点击 42 | view.setTag(TIME_TAG, currentTime); 43 | Log.d("SingleClickAspect", "currentTime:" + currentTime); 44 | joinPoint.proceed();//执行原方法 45 | } 46 | 47 | } 48 | } 49 | 50 | public static boolean hasId(int[] arr, int value) { 51 | for (int i : arr) { 52 | if (i == value) 53 | return true; 54 | } 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/SafeAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.util.Log; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import java.io.PrintWriter; 11 | import java.io.StringWriter; 12 | 13 | import cn.com.superLei.aoparms.annotation.Safe; 14 | import cn.com.superLei.aoparms.common.reflect.Reflect; 15 | import cn.com.superLei.aoparms.common.reflect.ReflectException; 16 | import cn.com.superLei.aoparms.common.utils.Preconditions; 17 | 18 | /** 19 | * description $desc$ 20 | * created by jerry on 2019/5/30. 21 | */ 22 | @Aspect 23 | public class SafeAspect { 24 | 25 | private static final String TAG = "SafeAspect"; 26 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Safe * *(..))"; 27 | 28 | @Pointcut(POINTCUT_METHOD) 29 | public void onSafeMethod() { 30 | } 31 | 32 | @Around("onSafeMethod() && @annotation(safe)") 33 | public Object doSafeMethod(final ProceedingJoinPoint joinPoint, Safe safe) throws Throwable { 34 | 35 | Object result = null; 36 | try { 37 | result = joinPoint.proceed(); 38 | } catch (Throwable e) { 39 | Log.w(TAG, getStringFromException(e)); 40 | 41 | String callBack = safe.callBack(); 42 | 43 | if (Preconditions.isNotBlank(callBack)) { 44 | 45 | try { 46 | Reflect.on(joinPoint.getTarget()).callback(callBack, e); 47 | } catch (ReflectException exception) { 48 | exception.printStackTrace(); 49 | Log.e(TAG, "no method "+callBack); 50 | } 51 | } 52 | } 53 | return result; 54 | } 55 | 56 | private static String getStringFromException(Throwable ex) { 57 | StringWriter errors = new StringWriter(); 58 | ex.printStackTrace(new PrintWriter(errors)); 59 | return errors.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/MainThreadAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.os.Looper; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import io.reactivex.BackpressureStrategy; 11 | import io.reactivex.Flowable; 12 | import io.reactivex.FlowableEmitter; 13 | import io.reactivex.FlowableOnSubscribe; 14 | import io.reactivex.Observable; 15 | import io.reactivex.android.schedulers.AndroidSchedulers; 16 | import io.reactivex.schedulers.Schedulers; 17 | 18 | /** 19 | * description $desc$ 20 | * created by jerry on 2019/5/30. 21 | */ 22 | @Aspect 23 | public class MainThreadAspect { 24 | 25 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.MainThread * *(..))"; 26 | 27 | @Around("onMainThreadMethod()") 28 | public void doMainThreadMethod(final ProceedingJoinPoint joinPoint) throws Throwable { 29 | mainThreadMethod(joinPoint); 30 | } 31 | 32 | @Pointcut(POINTCUT_METHOD) 33 | public void onMainThreadMethod() { 34 | } 35 | 36 | private void mainThreadMethod(final ProceedingJoinPoint joinPoint) throws Throwable { 37 | if (Looper.myLooper() == Looper.getMainLooper()) { 38 | joinPoint.proceed(); 39 | } else { 40 | Flowable.create(new FlowableOnSubscribe() { 41 | @Override 42 | public void subscribe(FlowableEmitter e) throws Exception { 43 | try { 44 | joinPoint.proceed(); 45 | } catch (Throwable throwable) { 46 | throwable.printStackTrace(); 47 | } 48 | } 49 | } 50 | , BackpressureStrategy.BUFFER) 51 | .subscribeOn(AndroidSchedulers.mainThread()) 52 | .subscribe(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/AopArmsInitProvider.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.content.pm.ProviderInfo; 7 | import android.database.Cursor; 8 | import android.net.Uri; 9 | import android.support.annotation.NonNull; 10 | 11 | /** 12 | * description $desc$ 13 | * created by jerry on 2019/8/12. 14 | */ 15 | public class AopArmsInitProvider extends ContentProvider { 16 | 17 | public AopArmsInitProvider() { 18 | } 19 | 20 | @Override 21 | public boolean onCreate() { 22 | // AopArms.init(getContext()); 23 | return true; 24 | } 25 | 26 | @Override 27 | public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 28 | return null; 29 | } 30 | 31 | @Override 32 | public String getType(@NonNull Uri uri) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public Uri insert(@NonNull Uri uri, ContentValues values) { 38 | return null; 39 | } 40 | 41 | @Override 42 | public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { 43 | return 0; 44 | } 45 | 46 | @Override 47 | public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { 48 | return 0; 49 | } 50 | 51 | @Override 52 | public void attachInfo(Context context, ProviderInfo providerInfo) { 53 | if (providerInfo == null) { 54 | throw new NullPointerException("AopArmsInitProvider ProviderInfo cannot be null."); 55 | } 56 | // So if the authorities equal the library internal ones, the developer forgot to set his applicationId 57 | if ("cn.com.superLei.aoparms.AopArmsInitProvider".equals(providerInfo.authority)) { 58 | throw new IllegalStateException("Incorrect provider authority in manifest. Most likely due to a " 59 | + "missing applicationId variable in application\'s build.gradle."); 60 | } 61 | super.attachInfo(context, providerInfo); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/statistic/ActivityLifecycleImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.statistic; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | 7 | import java.lang.annotation.Annotation; 8 | 9 | import cn.com.superLei.aoparms.AopArms; 10 | import cn.com.superLei.aoparms.annotation.Statistics; 11 | import cn.com.superLei.aoparms.callback.StatisticCallback; 12 | 13 | public class ActivityLifecycleImpl implements Application.ActivityLifecycleCallbacks { 14 | 15 | private void proceedStatistic(Activity activity, StatisticInfo.ActivityLife activityLife){ 16 | Class cls = activity.getClass(); 17 | if (cls.isAnnotationPresent(Statistics.class)){ 18 | for(Annotation ann : cls.getDeclaredAnnotations()){ 19 | if(ann instanceof Statistics){ 20 | int value = ((Statistics) ann).value(); 21 | StatisticInfo info = new StatisticInfo(value,System.currentTimeMillis(),cls.getSimpleName(),true, activityLife); 22 | StatisticCallback callback = AopArms.getStatisticCallback(); 23 | if (callback != null){ 24 | callback.statistics(info); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | public void onActivityCreated(Activity activity, Bundle bundle) { 33 | proceedStatistic(activity, StatisticInfo.ActivityLife.CREATE); 34 | } 35 | 36 | @Override 37 | public void onActivityStarted(Activity activity) { 38 | 39 | } 40 | 41 | @Override 42 | public void onActivityResumed(Activity activity) { 43 | 44 | } 45 | 46 | @Override 47 | public void onActivityPaused(Activity activity) { 48 | proceedStatistic(activity, StatisticInfo.ActivityLife.PAUSE); 49 | } 50 | 51 | @Override 52 | public void onActivityStopped(Activity activity) { 53 | 54 | } 55 | 56 | @Override 57 | public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 58 | 59 | } 60 | 61 | @Override 62 | public void onActivityDestroyed(Activity activity) { 63 | proceedStatistic(activity, StatisticInfo.ActivityLife.DESTROY); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/utils/Preconditions.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.utils; 2 | 3 | 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | public class Preconditions { 9 | 10 | /** 11 | * 可以判断任何一个对象是否为空,包括List Map String 复杂对象等等, 12 | * 只能判断对象,而不能判断基本数据类型 13 | * Preconditions.isBlank("") true 14 | * Preconditions.isBlank(" ") true 15 | * Preconditions.isBlank(null) true 16 | * Preconditions.isBlank("null") false 17 | * @param t 18 | * @param 19 | * @return 20 | */ 21 | public static boolean isBlank(T t) { 22 | 23 | if (t==null) { 24 | return true; 25 | } 26 | 27 | 28 | if (t instanceof List) { 29 | if (((List) t).size()==0) { 30 | return true; 31 | } 32 | } else if (t instanceof Map) { 33 | if (((Map) t).size()==0) { 34 | return true; 35 | } 36 | } else if (t instanceof Set) { 37 | if (((Set) t).size()==0) { 38 | return true; 39 | } 40 | } else if (t instanceof Object []) { 41 | if (((Object[]) t).length==0) { 42 | return true; 43 | } 44 | } else if (t instanceof String) { 45 | 46 | String str = (String)t; 47 | if (str.length()==0) return true; 48 | 49 | str = str.trim(); 50 | if (str.length()==0) return true; 51 | } 52 | 53 | return false; 54 | } 55 | 56 | public static boolean isNotBlank(T t) { 57 | return !isBlank(t); 58 | } 59 | 60 | public static boolean isNotBlanks(Object... objects) { 61 | 62 | if (objects==null) { 63 | return false; 64 | } 65 | 66 | for (Object obj:objects) { 67 | if (isBlank(obj)) { 68 | return false; 69 | } 70 | } 71 | 72 | return true; 73 | } 74 | 75 | public static T checkNotNull(T arg) { 76 | return checkNotNull(arg, "Argument must not be null"); 77 | } 78 | 79 | public static T checkNotNull(T arg, String message) { 80 | if (arg == null) { 81 | throw new NullPointerException(message); 82 | } 83 | return arg; 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/assist/TestAssist.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.assist; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Modifier; 5 | 6 | import javassist.ClassPool; 7 | import javassist.CtClass; 8 | import javassist.CtConstructor; 9 | import javassist.CtField; 10 | import javassist.CtMethod; 11 | import javassist.CtNewMethod; 12 | 13 | public class TestAssist { 14 | 15 | public static ClassPool pool = ClassPool.getDefault(); 16 | public static CtClass clazz = pool.makeClass("Employ"); 17 | 18 | public static void main(String[] args) throws Exception { 19 | 20 | //创建属性方法一 21 | CtField ctFieldOne = CtField.make("private Integer empId;", clazz); 22 | clazz.addField(ctFieldOne); 23 | CtField ctFieldTwo = CtField.make("private Integer empAge;", clazz); 24 | clazz.addField(ctFieldTwo); 25 | 26 | //创建属性方法二 27 | CtField ctFieldThree = new CtField(pool.get("java.lang.String"),"empName", clazz); 28 | ctFieldThree.setModifiers(Modifier.PRIVATE); 29 | clazz.addField(ctFieldThree); 30 | 31 | //创建含参构造器 32 | CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.Integer"), pool.get("java.lang.String"),pool.get("java.lang.Integer")}, clazz); 33 | constructor.setBody("{this.empId = $1; this.empName = $2; this.empAge = $3;}"); 34 | clazz.addConstructor(constructor); 35 | 36 | //创建方法方法一 37 | CtMethod ctMethodOne = CtMethod.make("public Integer getEmpId() {return empId;}", clazz); 38 | clazz.addMethod(ctMethodOne); 39 | CtMethod ctMethodTwo = CtMethod.make("public void setEmpId(Integer empId) {this.empId = empId;}", clazz); 40 | clazz.addMethod(ctMethodTwo); 41 | 42 | //创建方法方法二 43 | clazz.addMethod(CtNewMethod.getter("getEmpAge", ctFieldTwo)); 44 | clazz.addMethod(CtNewMethod.setter("setEmpAge", ctFieldTwo)); 45 | 46 | clazz.writeFile("/home/liulei/AndroidStudioProjects/Github/AopArms/aop-arms/src/main/java/cn/com/superLei/aoparms/common/assist"); 47 | 48 | 49 | Class clazzEmploy = clazz.toClass(); 50 | 51 | //调用含参构造器 52 | Object obj = clazzEmploy.getConstructor(Integer.class,String.class,Integer.class).newInstance(1,"Sandy",8); 53 | 54 | //调用方法 55 | Method method =clazzEmploy.getDeclaredMethod("getEmpAge"); 56 | System.out.println("method.invoke(obj): " + method.invoke(obj)); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/statistic/StatisticInfo.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.statistic; 2 | 3 | public class StatisticInfo { 4 | private int key; 5 | private long startTime; 6 | private String statisticName; 7 | private boolean isActivity; 8 | private boolean isMethod; 9 | private Enum activityLife; 10 | 11 | public StatisticInfo(int key, long startTime, String statisticName, boolean isMethod) { 12 | this.key = key; 13 | this.startTime = startTime; 14 | this.statisticName = statisticName; 15 | this.isMethod = isMethod; 16 | } 17 | 18 | public StatisticInfo(int key, long startTime, String statisticName, boolean isActivity, Enum activityLife) { 19 | this.key = key; 20 | this.startTime = startTime; 21 | this.statisticName = statisticName; 22 | this.isActivity = isActivity; 23 | this.activityLife = activityLife; 24 | } 25 | 26 | public Enum getActivityLife() { 27 | return activityLife; 28 | } 29 | 30 | public void setActivityLife(Enum activityLife) { 31 | this.activityLife = activityLife; 32 | } 33 | 34 | public int getKey() { 35 | return key; 36 | } 37 | 38 | public void setKey(int key) { 39 | this.key = key; 40 | } 41 | 42 | public long getStartTime() { 43 | return startTime; 44 | } 45 | 46 | public void setStartTime(long startTime) { 47 | this.startTime = startTime; 48 | } 49 | 50 | public String getStatisticName() { 51 | return statisticName; 52 | } 53 | 54 | public void setStatisticName(String statisticName) { 55 | this.statisticName = statisticName; 56 | } 57 | 58 | public boolean isActivity() { 59 | return isActivity; 60 | } 61 | 62 | public void setActivity(boolean activity) { 63 | isActivity = activity; 64 | } 65 | 66 | public boolean isMethod() { 67 | return isMethod; 68 | } 69 | 70 | public void setMethod(boolean method) { 71 | isMethod = method; 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return "StatisticInfo{" + 77 | "key=" + key + 78 | ", startTime=" + startTime + 79 | ", statisticName='" + statisticName + '\'' + 80 | ", isActivity=" + isActivity + 81 | ", isMethod=" + isMethod + 82 | ", activityLife=" + activityLife + 83 | '}'; 84 | } 85 | 86 | public enum ActivityLife { 87 | CREATE, 88 | RESTART, 89 | PAUSE, 90 | DESTROY 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/DelayAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import cn.com.superLei.aoparms.annotation.Delay; 13 | import cn.com.superLei.aoparms.common.collection.NoEmptyHashMap; 14 | import cn.com.superLei.aoparms.common.utils.RxJavaHelper; 15 | import io.reactivex.Observable; 16 | import io.reactivex.Scheduler; 17 | import io.reactivex.android.schedulers.AndroidSchedulers; 18 | import io.reactivex.disposables.Disposable; 19 | import io.reactivex.functions.Consumer; 20 | 21 | /** 22 | * description 延迟任务 23 | * created by jerry on 2019/5/30. 24 | */ 25 | @Aspect 26 | public class DelayAspect { 27 | private static final String TAG = "DelayAspect"; 28 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Delay * *(..))"; 29 | 30 | @Pointcut(POINTCUT_METHOD) 31 | public void onDelayMethod() { 32 | } 33 | 34 | @Around("onDelayMethod() && @annotation(delay)") 35 | public Object doDelayMethod(final ProceedingJoinPoint joinPoint, Delay delay) throws Throwable { 36 | String key = delay.key(); 37 | if (TextUtils.isEmpty(key)){ 38 | key = joinPoint.getSignature().getName(); 39 | } 40 | long delayTime = delay.delay(); 41 | boolean asyn = delay.asyn(); 42 | int priority = delay.priority(); 43 | TimeUnit unit = delay.timeUnit(); 44 | Object result = null; 45 | if (delayTime>0) { 46 | final String finalKey = key; 47 | Scheduler scheduler = RxJavaHelper.scheduler(priority); 48 | Disposable subscribe = Observable.timer(delayTime, unit) 49 | .subscribeOn(scheduler) 50 | .observeOn(asyn ? scheduler: AndroidSchedulers.mainThread()) 51 | .subscribe(new Consumer() { 52 | @Override 53 | public void accept(Long aLong) throws Exception { 54 | try { 55 | joinPoint.proceed(); 56 | NoEmptyHashMap.getInstance().remove(finalKey); 57 | } catch (Throwable throwable) { 58 | throwable.printStackTrace(); 59 | } 60 | } 61 | }); 62 | NoEmptyHashMap.getInstance().put(key, subscribe); 63 | } else { 64 | result = joinPoint.proceed(); 65 | } 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/AopArms.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | import cn.com.superLei.aoparms.annotation.EnableSystrace; 8 | import cn.com.superLei.aoparms.callback.Interceptor; 9 | import cn.com.superLei.aoparms.callback.StatisticCallback; 10 | import cn.com.superLei.aoparms.common.statistic.StatisticsLife; 11 | import cn.com.superLei.aoparms.common.systrace.SystraceMonitor; 12 | 13 | /** 14 | * description $desc$ 15 | * created by jerry on 2019/5/31. 16 | */ 17 | public class AopArms { 18 | @SuppressLint("StaticFieldLeak") 19 | private static Application application; 20 | private static Interceptor sInterceptor; 21 | private static StatisticCallback statisticCallback; 22 | 23 | public static void init(Application app){ 24 | init(app, new Options()); 25 | } 26 | 27 | public static void init(Application app, Options options){ 28 | if (app == null)throw new IllegalArgumentException("application is null"); 29 | application = app; 30 | AopLog.init(options); 31 | StatisticsLife.registerStatisticsLife(application); 32 | systraceEnable(application); 33 | } 34 | 35 | private static void systraceEnable(Application app) { 36 | Class cls = app.getClass(); 37 | if (cls.isAnnotationPresent(EnableSystrace.class)){ 38 | EnableSystrace systrace = cls.getAnnotation(EnableSystrace.class); 39 | if (systrace != null){ 40 | long filter = systrace.filter(); 41 | boolean containNative = systrace.containNative(); 42 | SystraceMonitor monitor = SystraceMonitor.getInstance(); 43 | monitor.setContainNative(containNative); 44 | monitor.setFilterTime(filter); 45 | monitor.start(); 46 | } 47 | } 48 | } 49 | 50 | public static Application getApplication(){ 51 | if (application == null){ 52 | throw new IllegalStateException("please init AopArms"); 53 | } 54 | return application; 55 | } 56 | 57 | public static Context getContext(){ 58 | return getApplication().getApplicationContext(); 59 | } 60 | 61 | public static void setInterceptor(Interceptor interceptor){ 62 | sInterceptor = interceptor; 63 | } 64 | 65 | public static Interceptor getInterceptor(){ 66 | return sInterceptor; 67 | } 68 | 69 | public static StatisticCallback getStatisticCallback() { 70 | return statisticCallback; 71 | } 72 | 73 | public static void setStatisticCallback(StatisticCallback statisticCallback) { 74 | AopArms.statisticCallback = statisticCallback; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/AopLog.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms; 2 | 3 | import android.support.annotation.RestrictTo; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import java.util.Locale; 8 | 9 | /** 10 | * 蓝牙日志类 11 | * Created by LiuLei on 2017/5/16. 12 | */ 13 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 14 | public class AopLog { 15 | 16 | public static String TAG = "AopArms"; 17 | private static boolean isLoggable; 18 | 19 | public static void init(Options options){ 20 | isLoggable = options.isLoggable(); 21 | if (!TextUtils.isEmpty(options.getLogTag())) 22 | TAG = options.getLogTag(); 23 | } 24 | 25 | private static String getSubTag(Object o){ 26 | String tag = ""; 27 | if(o instanceof String){ 28 | tag = (String) o; 29 | }else if(o instanceof Number){ 30 | tag = String.valueOf(o); 31 | }else { 32 | tag = o.getClass().getSimpleName(); 33 | } 34 | return tag; 35 | } 36 | 37 | public static void e(Object o, String msg){ 38 | if(isLoggable){ 39 | Log.e(TAG,buildMessge(getSubTag(o), msg)); 40 | } 41 | } 42 | 43 | public static void i(Object o, String msg){ 44 | if(isLoggable){ 45 | Log.i(TAG,buildMessge(getSubTag(o), msg)); 46 | } 47 | } 48 | 49 | public static void w(Object o, String msg){ 50 | if(isLoggable){ 51 | Log.w(TAG,buildMessge(getSubTag(o), msg)); 52 | } 53 | } 54 | 55 | public static void d(Object o, String msg){ 56 | if(isLoggable){ 57 | Log.d(TAG,buildMessge(getSubTag(o), msg)); 58 | } 59 | } 60 | 61 | private static String buildMessge(String subTag, String msg){ 62 | return String.format(Locale.CHINA, "[%d] %s: %s", 63 | Thread.currentThread().getId(), subTag, msg); 64 | } 65 | 66 | /** 67 | * Formats the caller's provided message and prepends useful info like 68 | * calling thread ID and method name. 69 | */ 70 | private static String buildMessage(String format, Object... args) { 71 | String msg = (args == null) ? format : String.format(Locale.CHINA, format, args); 72 | StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace(); 73 | 74 | String caller = ""; 75 | // Walk up the stack looking for the first caller outside of VolleyLog. 76 | // It will be at least two frames up, so start there. 77 | for (int i = 2; i < trace.length; i++) { 78 | Class clazz = trace[i].getClass(); 79 | if (!clazz.equals(AopLog.class)) { 80 | String callingClass = trace[i].getClassName(); 81 | callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1); 82 | callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1); 83 | 84 | caller = callingClass + "." + trace[i].getMethodName(); 85 | break; 86 | } 87 | } 88 | return String.format(Locale.CHINA, "[%d] %s: %s", 89 | Thread.currentThread().getId(), caller, msg); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/systrace/SystraceMonitor.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.systrace; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | import android.os.Looper; 6 | import android.util.Printer; 7 | 8 | import cn.com.superLei.aoparms.AopArms; 9 | import cn.com.superLei.aoparms.AopLog; 10 | 11 | public class SystraceMonitor { 12 | private static final String TAG = "SystraceMonitor"; 13 | private static SystraceMonitor sInstance = new SystraceMonitor(); 14 | private Handler mIoHandler; 15 | //方法耗时的卡口,60毫秒 16 | private static final long TIME_BLOCK = 60L; 17 | private long filterTime = TIME_BLOCK; 18 | private long startMonitorTime = 0L; 19 | private boolean isBlock = false; 20 | private boolean isContainNative = false; 21 | 22 | private SystraceMonitor() { 23 | HandlerThread logThread = new HandlerThread("log"); 24 | logThread.start(); 25 | mIoHandler = new Handler(logThread.getLooper()); 26 | } 27 | 28 | public void start() { 29 | Looper.getMainLooper().setMessageLogging(new Printer() { 30 | //分发和处理消息开始前的log 31 | private static final String START = ">>>>> Dispatching"; 32 | //分发和处理消息结束后的log 33 | private static final String END = "<<<<< Finished"; 34 | 35 | @Override 36 | public void println(String x) { 37 | if (x.startsWith(START)) { 38 | //开始计时 39 | startMonitor(); 40 | } 41 | if (x.startsWith(END)) { 42 | //结束计时,并计算出方法执行时间 43 | removeMonitor(); 44 | } 45 | } 46 | }); 47 | 48 | } 49 | 50 | public boolean isContainNative() { 51 | return isContainNative; 52 | } 53 | 54 | public void setContainNative(boolean containNative) { 55 | isContainNative = containNative; 56 | } 57 | 58 | public long getFilterTime() { 59 | return filterTime; 60 | } 61 | 62 | public void setFilterTime(long filterTime) { 63 | this.filterTime = filterTime; 64 | } 65 | 66 | private Runnable mLogRunnable = new Runnable() { 67 | @Override 68 | public void run() { 69 | isBlock = true; 70 | //打印出执行的耗时方法的栈消息 71 | StringBuilder sb = new StringBuilder(); 72 | StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace(); 73 | for (StackTraceElement s : stackTrace) { 74 | /*if (isContainNative){ 75 | sb.append(s.toString()); 76 | }else { 77 | if (s.getClassName().contains(AopArms.getContext().getPackageName())){ 78 | sb.append(s.toString()); 79 | } 80 | }*/ 81 | sb.append(s.toString()); 82 | sb.append("\n"); 83 | } 84 | AopLog.w(TAG, sb.toString()); 85 | } 86 | }; 87 | 88 | public static SystraceMonitor getInstance() { 89 | return sInstance; 90 | } 91 | 92 | /** 93 | * 开始计时 94 | */ 95 | public void startMonitor() { 96 | startMonitorTime = System.currentTimeMillis(); 97 | mIoHandler.postDelayed(mLogRunnable, filterTime); 98 | } 99 | 100 | /** 101 | * 停止计时 102 | */ 103 | public void removeMonitor() { 104 | if (isBlock){ 105 | AopLog.w(TAG, "耗时时长: ["+(System.currentTimeMillis() - startMonitorTime)+"ms]"); 106 | } 107 | isBlock = false; 108 | startMonitorTime = 0L; 109 | mIoHandler.removeCallbacks(mLogRunnable); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/ScheduledAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import org.aspectj.lang.ProceedingJoinPoint; 7 | import org.aspectj.lang.annotation.Around; 8 | import org.aspectj.lang.annotation.Aspect; 9 | import org.aspectj.lang.annotation.Pointcut; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import cn.com.superLei.aoparms.annotation.Scheduled; 13 | import cn.com.superLei.aoparms.common.collection.NoEmptyHashMap; 14 | import cn.com.superLei.aoparms.common.reflect.Reflect; 15 | import cn.com.superLei.aoparms.common.reflect.ReflectException; 16 | import cn.com.superLei.aoparms.common.utils.Preconditions; 17 | import io.reactivex.Observable; 18 | import io.reactivex.disposables.Disposable; 19 | import io.reactivex.functions.Consumer; 20 | import io.reactivex.functions.Function; 21 | 22 | @Aspect 23 | public class ScheduledAspect { 24 | 25 | private static final String TAG = "ScheduledAspect"; 26 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Scheduled * *(..))"; 27 | private Disposable disposable; 28 | 29 | @Pointcut(POINTCUT_METHOD) 30 | public void onScheduledMethod() { 31 | } 32 | 33 | @Around("onScheduledMethod() && @annotation(scheduled)") 34 | public Object doScheduledMethod(final ProceedingJoinPoint joinPoint, Scheduled scheduled) throws Throwable { 35 | 36 | String key = scheduled.key(); 37 | if (TextUtils.isEmpty(key)){ 38 | key = joinPoint.getSignature().getName(); 39 | } 40 | long initialDelay = scheduled.initialDelay(); 41 | long interval = scheduled.interval(); 42 | final int counts = scheduled.count(); 43 | TimeUnit timeUnit = scheduled.timeUnit(); 44 | final String taskExpiredCallback = scheduled.taskExpiredCallback(); 45 | Object result = null; 46 | String finalKey = key; 47 | disposable = Observable.interval(initialDelay+interval, interval, timeUnit) 48 | .map(new Function() { 49 | @Override 50 | public Long apply(Long aLong) throws Exception { 51 | try { 52 | joinPoint.proceed(); 53 | } catch (Throwable throwable) { 54 | throwable.printStackTrace(); 55 | } 56 | return aLong + 1; 57 | } 58 | }) 59 | .subscribe(new Consumer() { 60 | @Override 61 | public void accept(Long count) throws Exception { 62 | Log.d(TAG, "count: " + count); 63 | if (count == (counts-1)) { 64 | if (disposable != null) { 65 | disposable.dispose(); 66 | } 67 | NoEmptyHashMap.getInstance().remove(finalKey); 68 | doTaskExpiredCallback(joinPoint, taskExpiredCallback); 69 | } 70 | } 71 | }); 72 | NoEmptyHashMap.getInstance().put(key, disposable); 73 | result = joinPoint.proceed(); 74 | return result; 75 | } 76 | 77 | private void doTaskExpiredCallback(ProceedingJoinPoint joinPoint, String taskExpiredCallback){ 78 | if (Preconditions.isNotBlank(taskExpiredCallback)) { 79 | 80 | try { 81 | Reflect.on(joinPoint.getTarget()).callback(taskExpiredCallback); 82 | } catch (ReflectException exception) { 83 | exception.printStackTrace(); 84 | Log.e(TAG, "no method "+taskExpiredCallback); 85 | } 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/heaton/baselibsample/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.heaton.baselibsample; 2 | 3 | import android.app.Application; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | import android.widget.Toast; 7 | 8 | import cn.com.superLei.aoparms.AopArms; 9 | import cn.com.superLei.aoparms.Options; 10 | import cn.com.superLei.aoparms.annotation.Delay; 11 | import cn.com.superLei.aoparms.annotation.EnableSystrace; 12 | import cn.com.superLei.aoparms.common.utils.ArmsPreference; 13 | 14 | 15 | /** 16 | * 应用入口 17 | * Created by LiuLei on 2016/4/25. 18 | *         ┏┓   ┏┓ 19 | *        ┏┛┻━━━┛┻┓ 20 | *        ┃       ┃ 21 | *        ┃   ━   ┃ 22 | *        ┃ >   < ┃ 23 | *        ┃       ┃ 24 | *        ┃... ⌒ ... ┃ 25 | *        ┃       ┃ 26 | *        ┗━┓   ┏━┛ 27 | *          ┃   ┃ Code is far away from bug with the animal protecting 28 | *          ┃   ┃ 神兽保佑,代码无bug 29 | *          ┃   ┃ 30 | *          ┃   ┃ 31 | *          ┃   ┃ 32 | *          ┃   ┃ 33 | *          ┃   ┗━━━┓ 34 | *          ┃       ┣┓ 35 | *          ┃       ┏┛ 36 | *          ┗┓┓┏━┳┓┏┛ 37 | *           ┃┫┫ ┃┫┫ 38 | *           ┗┻┛ ┗┻┛ 39 | */ 40 | @EnableSystrace(filter = 60L, containNative = true)//开启耗时监控,过滤时间>60ms,包含native系统方法 41 | public class MyApplication extends Application { 42 | 43 | private static final String TAG = "MyApplication"; 44 | private static MyApplication mApplication; 45 | 46 | @Override 47 | public void onCreate() { 48 | super.onCreate(); 49 | mApplication = this; 50 | AopArms.init(this, new Options().setLoggable(true)); 51 | 52 | AopArms.setInterceptor((key, methodName) -> { 53 | Log.e(TAG, "intercept methodName:>>>>>"+methodName); 54 | if ("login_intercept".equals(key)){ 55 | String userId = ArmsPreference.get(mApplication, "userId", ""); 56 | if (TextUtils.isEmpty(userId)){ 57 | Toast.makeText(mApplication, "您还没有登录", Toast.LENGTH_SHORT).show(); 58 | return true; 59 | } 60 | } 61 | return false; 62 | }); 63 | AopArms.setStatisticCallback(statisticInfo -> { 64 | Log.e(TAG, "statisticInfo: "+statisticInfo.toString()); 65 | }); 66 | 67 | initSDK(); 68 | 69 | } 70 | 71 | /** 72 | * 异步初始化第三方sdk,可设置线程优先级 73 | */ 74 | @Delay(delay = 100L, asyn = true, priority = 10) 75 | public void initSDK(){ 76 | //... 77 | } 78 | 79 | public static MyApplication getInstance() { 80 | return mApplication; 81 | } 82 | 83 | 84 | } 85 | /** 86 | *   &#######& 87 | *   #########& 88 | *   ###########& 89 | *   ##&#$###$ ##& 90 | *   ;### ####& #### 91 | *   ###;####### #### 92 | *   &########### ##### 93 | *   ;#########o## ##### 94 | *   ######### ## ###### 95 | *   ;########### ### ###### 96 | *   ################ ####### 97 | *   #################; ######, 98 | *   #############$#### ####### 99 | *   ########&;,######## &####### 100 | *   ;######### &### ######## 101 | *   ########## ###; ######## 102 | *   ########### ##$ ######## 103 | *   ########### ### ######### 104 | *   ##########&$ ## ;######## 105 | *   #########, ! ## ######## 106 | *   ;########& ## ####### 107 | *   #&##### ## &#& 108 | *   o# &# #; 109 | *   ## ## 110 | *   &#& ;## 111 | *   ## ### 112 | *

113 | *          葱官赐福  百无禁忌 114 | */ 115 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/utils/IOUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.utils; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.Closeable; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.OutputStream; 12 | import java.nio.channels.FileChannel; 13 | 14 | /** 15 | * description $desc$ 16 | * created by jerry on 2019/5/29. 17 | */ 18 | public class IOUtils { 19 | 20 | private final static int BUFFER_SIZE = 0x400; // 1024 21 | 22 | /** 23 | * 从输入流读取数据 24 | * @param inStream 25 | * @return 26 | * @throws Exception 27 | */ 28 | public static byte[] readInputStream(InputStream inStream) throws IOException { 29 | ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); 30 | byte[] buffer = new byte[BUFFER_SIZE]; 31 | int len = 0; 32 | while( (len = inStream.read(buffer)) !=-1 ){ 33 | if (len!=0) { 34 | outSteam.write(buffer, 0, len); 35 | } 36 | } 37 | outSteam.close(); 38 | inStream.close(); 39 | return outSteam.toByteArray(); 40 | } 41 | 42 | /** 43 | * 从输入流读取数据 44 | * @param inStream 45 | * @return 46 | * @throws Exception 47 | */ 48 | public static String inputStream2String(InputStream inStream) throws IOException{ 49 | 50 | return new String(readInputStream(inStream), "UTF-8"); 51 | } 52 | 53 | /** 54 | * 55 | * @param is 56 | * @param os 57 | * @throws IOException 58 | */ 59 | public static void copyStream(InputStream is, OutputStream os) throws IOException { 60 | byte[] bytes = new byte[BUFFER_SIZE]; 61 | for (;;) { 62 | int count = is.read(bytes, 0, BUFFER_SIZE); 63 | if (count == -1) 64 | break; 65 | os.write(bytes, 0, count); 66 | } 67 | } 68 | 69 | /** 70 | * 文件拷贝 71 | * @param src source {@link File} 72 | * @param dst destination {@link File} 73 | * @throws IOException 74 | */ 75 | public static void copyFile(File src, File dst) throws IOException { 76 | FileInputStream in = new FileInputStream(src); 77 | FileOutputStream out = new FileOutputStream(dst); 78 | FileChannel inChannel = in.getChannel(); 79 | FileChannel outChannel = out.getChannel(); 80 | 81 | try { 82 | inChannel.transferTo(0, inChannel.size(), outChannel); 83 | } finally { 84 | if (inChannel != null) { 85 | inChannel.close(); 86 | } 87 | if (outChannel != null) { 88 | outChannel.close(); 89 | } 90 | } 91 | 92 | in.close(); 93 | out.close(); 94 | } 95 | 96 | /** 97 | * 将流写入文件 98 | * @param in 99 | * @param target 100 | * @throws IOException 101 | */ 102 | public static void writeToFile(InputStream in, File target) throws IOException { 103 | BufferedOutputStream bos = new BufferedOutputStream( 104 | new FileOutputStream(target)); 105 | int count; 106 | byte data[] = new byte[BUFFER_SIZE]; 107 | while ((count = in.read(data, 0, BUFFER_SIZE)) != -1) { 108 | bos.write(data, 0, count); 109 | } 110 | bos.close(); 111 | } 112 | 113 | /** 114 | * 安全关闭io流 115 | * @param closeable 116 | */ 117 | public static void closeQuietly(Closeable closeable) { 118 | if (closeable != null) { 119 | try { 120 | closeable.close(); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } 124 | } 125 | } 126 | 127 | /** 128 | * 安全关闭io流 129 | * @param closeables 130 | */ 131 | public static void closeQuietly(Closeable... closeables) { 132 | 133 | if (Preconditions.isNotBlank(closeables)) { 134 | 135 | for(Closeable closeable:closeables) { 136 | closeQuietly(closeable); // 系统先匹配确定参数的方法,没有再去匹配调用不定项参数的方法 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 26 | 27 | 28 | 29 | 30 |

31 | 32 | 33 | 34 | xmlns:android 35 | 36 | ^$ 37 | 38 | 39 | 40 |
41 |
42 | 43 | 44 | 45 | xmlns:.* 46 | 47 | ^$ 48 | 49 | 50 | BY_NAME 51 | 52 |
53 |
54 | 55 | 56 | 57 | .*:id 58 | 59 | http://schemas.android.com/apk/res/android 60 | 61 | 62 | 63 |
64 |
65 | 66 | 67 | 68 | .*:name 69 | 70 | http://schemas.android.com/apk/res/android 71 | 72 | 73 | 74 |
75 |
76 | 77 | 78 | 79 | name 80 | 81 | ^$ 82 | 83 | 84 | 85 |
86 |
87 | 88 | 89 | 90 | style 91 | 92 | ^$ 93 | 94 | 95 | 96 |
97 |
98 | 99 | 100 | 101 | .* 102 | 103 | ^$ 104 | 105 | 106 | BY_NAME 107 | 108 |
109 |
110 | 111 | 112 | 113 | .* 114 | 115 | http://schemas.android.com/apk/res/android 116 | 117 | 118 | ANDROID_ATTRIBUTE_ORDER 119 | 120 |
121 |
122 | 123 | 124 | 125 | .* 126 | 127 | .* 128 | 129 | 130 | BY_NAME 131 | 132 |
133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/RetryAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.util.Log; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.aspectj.lang.reflect.MethodSignature; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import cn.com.superLei.aoparms.annotation.Retry; 14 | import cn.com.superLei.aoparms.common.reflect.Reflect; 15 | import cn.com.superLei.aoparms.common.reflect.ReflectException; 16 | import cn.com.superLei.aoparms.common.utils.Preconditions; 17 | import io.reactivex.Observable; 18 | import io.reactivex.ObservableEmitter; 19 | import io.reactivex.ObservableOnSubscribe; 20 | import io.reactivex.ObservableSource; 21 | import io.reactivex.android.schedulers.AndroidSchedulers; 22 | import io.reactivex.disposables.Disposable; 23 | import io.reactivex.functions.Consumer; 24 | import io.reactivex.functions.Function; 25 | import io.reactivex.schedulers.Schedulers; 26 | 27 | @Aspect 28 | public class RetryAspect { 29 | 30 | private static final String TAG = "RetryAspect"; 31 | private static final String POINTCUT_METHOD = "execution(@cn.com.superLei.aoparms.annotation.Retry * *(..))"; 32 | 33 | private int retryCount = 0;//当前出错重试次数 34 | 35 | @Pointcut(POINTCUT_METHOD) 36 | public void onRetryMethod() { 37 | } 38 | 39 | @Around("onRetryMethod() && @annotation(retry)") 40 | public Object doRetryMethod(final ProceedingJoinPoint joinPoint, Retry retry) throws Throwable { 41 | 42 | final int count = retry.count(); 43 | final long delay = retry.delay(); 44 | boolean asyn = retry.asyn(); 45 | final String retryCallback = retry.retryCallback(); 46 | String type = ((MethodSignature) joinPoint.getSignature()).getReturnType().toString(); 47 | if (!"boolean".equalsIgnoreCase(type)){ 48 | Log.e(TAG, "方法返回值必须是boolean类型"); 49 | return joinPoint.proceed(); 50 | } 51 | Disposable subscribe = Observable.create(new ObservableOnSubscribe() { 52 | @Override 53 | public void subscribe(ObservableEmitter emitter) throws Exception { 54 | Boolean value = false; 55 | try { 56 | Log.e(TAG, "任务重试中,当前重试次数>>>>"+retryCount+"---"+Thread.currentThread().getName()); 57 | value = (Boolean) joinPoint.proceed(); 58 | } catch (Throwable throwable) { 59 | throwable.printStackTrace(); 60 | } 61 | if (value){ 62 | Log.e(TAG, "任务请求成功,当前重试次数>>>>"+retryCount); 63 | doRetryResult(joinPoint, retryCallback, true); 64 | retryCount = 0; 65 | }else { 66 | throw new Exception("任务请求失败,准备重试..."); 67 | } 68 | } 69 | }).observeOn(Schedulers.io()) 70 | .subscribeOn(asyn ? Schedulers.io() : AndroidSchedulers.mainThread()) 71 | .retryWhen(new Function, ObservableSource>() { 72 | @Override 73 | public ObservableSource apply(Observable throwableObservable) throws Exception { 74 | return throwableObservable 75 | .flatMap(new Function>() { 76 | @Override 77 | public ObservableSource apply(Throwable throwable) throws Exception { 78 | if (++retryCount <= count) { 79 | Log.e(TAG, "An error occurred, ready to try again, retries count>>>>>" + retryCount); 80 | // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed). 81 | return Observable.timer(delay, TimeUnit.MILLISECONDS); 82 | } 83 | return Observable.error(throwable); 84 | } 85 | }); 86 | } 87 | }).subscribe(new Consumer() { 88 | @Override 89 | public void accept(Boolean aBoolean) throws Exception { 90 | Log.e(TAG, "accept: >>>>>" + aBoolean); 91 | } 92 | }, new Consumer() { 93 | @Override 94 | public void accept(Throwable throwable) throws Exception { 95 | Log.e(TAG, "throwable: >>>>>" + throwable.getMessage()); 96 | doRetryResult(joinPoint, retryCallback, false); 97 | retryCount = 0; 98 | } 99 | }); 100 | return null; 101 | } 102 | 103 | private void doRetryResult(ProceedingJoinPoint joinPoint, String retryCallback, boolean result){ 104 | if (Preconditions.isNotBlank(retryCallback)) { 105 | try { 106 | Reflect.on(joinPoint.getTarget()).callback(retryCallback, result); 107 | } catch (ReflectException exception) { 108 | exception.printStackTrace(); 109 | Log.e(TAG, "no method "+retryCallback); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/permission/AopPermissionUtils.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common.permission; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.app.AlertDialog; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.content.pm.PackageManager; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | import android.provider.Settings; 13 | import android.support.v4.app.ActivityCompat; 14 | import android.support.v4.util.SimpleArrayMap; 15 | import android.util.SparseArray; 16 | 17 | import cn.com.superLei.aoparms.R; 18 | 19 | /** 20 | * Created by jerry on 2018/6/13. 21 | */ 22 | 23 | public class AopPermissionUtils { 24 | 25 | private static final SimpleArrayMap MIN_SDK_PERMISSIONS; 26 | 27 | static { 28 | MIN_SDK_PERMISSIONS = new SimpleArrayMap<>(8); 29 | MIN_SDK_PERMISSIONS.put("com.android.voicemail.permission.ADD_VOICEMAIL", 14); 30 | MIN_SDK_PERMISSIONS.put("android.permission.BODY_SENSORS", 20); 31 | MIN_SDK_PERMISSIONS.put("android.permission.READ_CALL_LOG", 16); 32 | MIN_SDK_PERMISSIONS.put("android.permission.READ_EXTERNAL_STORAGE", 16); 33 | MIN_SDK_PERMISSIONS.put("android.permission.USE_SIP", 9); 34 | MIN_SDK_PERMISSIONS.put("android.permission.WRITE_CALL_LOG", 16); 35 | MIN_SDK_PERMISSIONS.put("android.permission.SYSTEM_ALERT_WINDOW", 23); 36 | MIN_SDK_PERMISSIONS.put("android.permission.WRITE_SETTINGS", 23); 37 | } 38 | /** 39 | * 判断是否所有权限都同意了,都同意返回true 否则返回false 40 | * 41 | * @param context context 42 | * @param permissions permission list 43 | * @return return true if all permissions granted else false 44 | */ 45 | public static boolean hasSelfPermissions(Context context, String... permissions) { 46 | for (String permission : permissions) { 47 | if (permissionExists(permission) && !hasSelfPermission(context, permission)) { 48 | return false; 49 | } 50 | } 51 | return true; 52 | } 53 | 54 | /** 55 | * 判断单个权限是否同意 56 | * 57 | * @param context context 58 | * @param permission permission 59 | * @return return true if permission granted 60 | */ 61 | private static boolean hasSelfPermission(Context context, String permission) { 62 | return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; 63 | } 64 | 65 | /** 66 | * 判断权限是否存在 67 | * 68 | * @param permission permission 69 | * @return return true if permission exists in SDK version 70 | */ 71 | private static boolean permissionExists(String permission) { 72 | Integer minVersion = MIN_SDK_PERMISSIONS.get(permission); 73 | return minVersion == null || Build.VERSION.SDK_INT >= minVersion; 74 | } 75 | 76 | /** 77 | * 检查是否都赋予权限 78 | * 79 | * @param grantResults grantResults 80 | * @return 所有都同意返回true 否则返回false 81 | */ 82 | public static boolean verifyPermissions(int... grantResults) { 83 | if (grantResults.length == 0) return false; 84 | for (int result : grantResults) { 85 | if (result != PackageManager.PERMISSION_GRANTED) { 86 | return false; 87 | } 88 | } 89 | return true; 90 | } 91 | 92 | /** 93 | * 检查所给权限List是否需要给提示 94 | * 95 | * @param activity Activity 96 | * @param permissions 权限list 97 | * @return 如果某个权限需要提示则返回true 98 | */ 99 | public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) { 100 | for (String permission : permissions) { 101 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { 102 | return true; 103 | } 104 | } 105 | return false; 106 | } 107 | 108 | public static void showGoSetting(Activity activity, String rationale, String positiveButtonText, String NegativeButtonText){ 109 | new AlertDialog.Builder(activity) 110 | .setMessage(rationale) 111 | .setPositiveButton(positiveButtonText, new DialogInterface.OnClickListener() { 112 | @Override 113 | public void onClick(DialogInterface dialog, int which) { 114 | dialog.dismiss(); 115 | go2Setting(activity); 116 | } 117 | }) 118 | .setNegativeButton(NegativeButtonText, new DialogInterface.OnClickListener() { 119 | @Override 120 | public void onClick(DialogInterface dialog, int which) { 121 | dialog.dismiss(); 122 | } 123 | }) 124 | .create().show(); 125 | } 126 | 127 | public static void showGoSetting(Activity activity, String rationale){ 128 | showGoSetting(activity, rationale, activity.getString(R.string.toSetting), activity.getString(R.string.btn_cancel)); 129 | } 130 | 131 | /** 132 | * 跳转到设置页面 133 | * @param context 134 | */ 135 | public static void go2Setting(Context context) { 136 | Intent intent = new Intent(); 137 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 138 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 139 | intent.setData(Uri.fromParts("package", context.getPackageName(), null)); 140 | context.startActivity(intent); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle create up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to create the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/aspect/PermissionAspect.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.aspect; 2 | 3 | import android.app.Fragment; 4 | import android.content.Context; 5 | 6 | import org.aspectj.lang.ProceedingJoinPoint; 7 | import org.aspectj.lang.annotation.Around; 8 | import org.aspectj.lang.annotation.Aspect; 9 | 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.lang.reflect.Method; 12 | import java.util.List; 13 | 14 | import cn.com.superLei.aoparms.AopArms; 15 | import cn.com.superLei.aoparms.annotation.Permission; 16 | import cn.com.superLei.aoparms.annotation.PermissionDenied; 17 | import cn.com.superLei.aoparms.annotation.PermissionNoAskDenied; 18 | import cn.com.superLei.aoparms.common.permission.IPermission; 19 | import cn.com.superLei.aoparms.common.permission.AopPermissionActivity; 20 | 21 | 22 | /** 23 | * Created by jerry on 2018/6/13. 24 | */ 25 | 26 | @Aspect 27 | public class PermissionAspect { 28 | 29 | @Around("execution(@cn.com.superLei.aoparms.annotation.Permission * *(..)) && @annotation(permission)") 30 | public void aroundJoinPoint(final ProceedingJoinPoint joinPoint, final Permission permission) throws Throwable { 31 | Context context = null; 32 | final Object object = joinPoint.getThis(); 33 | if (object instanceof Context) { 34 | context = (Context) object; 35 | } else if (object instanceof Fragment) { 36 | context = ((Fragment) object).getActivity(); 37 | } else if (object instanceof android.support.v4.app.Fragment) { 38 | context = ((android.support.v4.app.Fragment) object).getActivity(); 39 | } else { 40 | //获取切入点方法上的参数列表 41 | Object[] objects = joinPoint.getArgs(); 42 | if (objects.length > 0) { 43 | //非静态方法且第一个参数为context 44 | if (objects[0] instanceof Context) { 45 | context = (Context) objects[0]; 46 | } else { 47 | //没有传入context 默认使用application 48 | context = AopArms.getContext(); 49 | } 50 | } else { 51 | context = AopArms.getContext(); 52 | } 53 | } 54 | if (context == null || permission == null) { 55 | joinPoint.proceed(); 56 | return; 57 | } 58 | AopPermissionActivity.PermissionRequest(context, permission.value(), 59 | permission.requestCode(), permission.rationale(), new IPermission() { 60 | @Override 61 | public void permissionGranted() { 62 | try { 63 | joinPoint.proceed(); 64 | } catch (Throwable throwable) { 65 | throwable.printStackTrace(); 66 | } 67 | } 68 | 69 | @Override 70 | public void permissionNoAskDenied(int requestCode, List denyNoAskList) { 71 | Class cls = object.getClass(); 72 | Method[] methods = cls.getDeclaredMethods(); 73 | if (methods.length == 0) return; 74 | for (Method method : methods) { 75 | //过滤不含自定义注解PermissionNoAskDenied的方法 76 | boolean isHasAnnotation = method.isAnnotationPresent(PermissionNoAskDenied.class); 77 | if (isHasAnnotation) { 78 | method.setAccessible(true); 79 | //获取方法类型 80 | Class[] types = method.getParameterTypes(); 81 | if (types.length != 2) return; 82 | //获取方法上的注解 83 | PermissionNoAskDenied aInfo = method.getAnnotation(PermissionNoAskDenied.class); 84 | if (aInfo == null) return; 85 | //解析注解上对应的信息 86 | try { 87 | method.invoke(object, requestCode, denyNoAskList); 88 | } catch (IllegalAccessException e) { 89 | e.printStackTrace(); 90 | } catch (InvocationTargetException e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | } 95 | } 96 | 97 | @Override 98 | public void permissionDenied(int requestCode, List denyList) { 99 | Class cls = object.getClass(); 100 | Method[] methods = cls.getDeclaredMethods(); 101 | if (methods.length == 0) return; 102 | for (Method method : methods) { 103 | //过滤不含自定义注解PermissionDenied的方法 104 | boolean isHasAnnotation = method.isAnnotationPresent(PermissionDenied.class); 105 | if (isHasAnnotation) { 106 | method.setAccessible(true); 107 | //获取方法类型 108 | Class[] types = method.getParameterTypes(); 109 | if (types.length != 2) return; 110 | //获取方法上的注解 111 | PermissionDenied aInfo = method.getAnnotation(PermissionDenied.class); 112 | if (aInfo == null) return; 113 | //解析注解上对应的信息 114 | try { 115 | method.invoke(object, requestCode, denyList); 116 | } catch (IllegalAccessException e) { 117 | e.printStackTrace(); 118 | } catch (InvocationTargetException e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | } 123 | } 124 | 125 | }); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /aop-arms/src/main/java/cn/com/superLei/aoparms/common/PkgScanner.java: -------------------------------------------------------------------------------- 1 | package cn.com.superLei.aoparms.common; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.lang.annotation.Annotation; 9 | import java.net.URL; 10 | import java.util.ArrayList; 11 | import java.util.Enumeration; 12 | import java.util.List; 13 | import java.util.jar.JarEntry; 14 | import java.util.jar.JarFile; 15 | 16 | /** 17 | * description $desc$ 18 | * created by jerry on 2019/6/4. 19 | */ 20 | public class PkgScanner { 21 | 22 | /** 23 | * 包名 24 | */ 25 | private String pkgName; 26 | 27 | /** 28 | * 包对应的路径名 29 | */ 30 | private String pkgPath; 31 | 32 | /** 33 | * 注解的class对象 34 | */ 35 | private Class anClazz; 36 | 37 | private ClassLoader cl; 38 | 39 | 40 | public PkgScanner(String pkgName) { 41 | this.pkgName = pkgName; 42 | this.pkgPath = PathUtils.packageToPath(pkgName); 43 | 44 | cl = Thread.currentThread().getContextClassLoader(); 45 | } 46 | 47 | public PkgScanner(String pkgName, Class anClazz) { 48 | this(pkgName); 49 | 50 | this.anClazz = anClazz; 51 | } 52 | 53 | /** 54 | * 执行扫描操作. 55 | * 56 | * @return 57 | * @throws IOException 58 | */ 59 | public List scan() throws IOException { 60 | List list = loadResource(); 61 | if (null != this.anClazz) { 62 | list = filterComponents(list); 63 | } 64 | 65 | return list; 66 | } 67 | 68 | public void setPkgName(String pkgName) { 69 | this.pkgName = pkgName; 70 | this.pkgPath = PathUtils.packageToPath(pkgName); 71 | } 72 | 73 | public void setAnnocation(Class an) { 74 | this.anClazz = an; 75 | } 76 | 77 | private List loadResource() throws IOException { 78 | List list = null; 79 | 80 | Enumeration urls = cl.getResources(pkgPath); 81 | while (urls.hasMoreElements()) { 82 | URL u = urls.nextElement(); 83 | 84 | ResourceType type = determineType(u); 85 | 86 | switch (type) { 87 | case JAR: 88 | String path = PathUtils.distillPathFromJarURL(u.getPath()); 89 | list = scanJar(path); 90 | break; 91 | 92 | case FILE: 93 | list = scanFile(u.getPath(), pkgName); 94 | break; 95 | } 96 | } 97 | 98 | return list; 99 | } 100 | 101 | /** 102 | * 根据URL判断是JAR包还是文件目录 103 | * @param url 104 | * @return 105 | */ 106 | private ResourceType determineType(URL url) { 107 | if (url.getProtocol().equals(ResourceType.FILE.getTypeString())) { 108 | return ResourceType.FILE; 109 | } 110 | 111 | if (url.getProtocol().equals(ResourceType.JAR.getTypeString())) { 112 | return ResourceType.JAR; 113 | } 114 | 115 | throw new IllegalArgumentException("不支持该类型:" + url.getProtocol()); 116 | } 117 | 118 | /** 119 | * 扫描JAR文件 120 | * @param path 121 | * @return 122 | * @throws IOException 123 | */ 124 | private List scanJar(String path) throws IOException { 125 | JarFile jar = new JarFile(path); 126 | 127 | List classNameList = new ArrayList<>(20); 128 | 129 | Enumeration entries = jar.entries(); 130 | while (entries.hasMoreElements()) { 131 | JarEntry entry = entries.nextElement(); 132 | String name = entry.getName(); 133 | 134 | if( (name.startsWith(pkgPath)) && (name.endsWith(ResourceType.CLASS_FILE.getTypeString())) ) { 135 | name = PathUtils.trimSuffix(name); 136 | name = PathUtils.pathToPackage(name); 137 | 138 | classNameList.add(name); 139 | } 140 | } 141 | 142 | return classNameList; 143 | } 144 | 145 | /** 146 | * 扫描文件目录下的类 147 | * @param path 148 | * @return 149 | */ 150 | private List scanFile(String path, String basePkg) { 151 | File f = new File(path); 152 | 153 | List classNameList = new ArrayList<>(10); 154 | 155 | // 得到目录下所有文件(目录) 156 | File[] files = f.listFiles(); 157 | if (null != files) { 158 | int LEN = files.length; 159 | 160 | for (int ix = 0 ; ix < LEN ; ++ix) { 161 | File file = files[ix]; 162 | 163 | // 判断是否还是一个目录 164 | if (file.isDirectory()) { 165 | // 递归遍历目录 166 | List list = scanFile(file.getAbsolutePath(), PathUtils.concat(basePkg, ".", file.getName())); 167 | classNameList.addAll(list); 168 | 169 | } else if (file.getName().endsWith(ResourceType.CLASS_FILE.getTypeString())) { 170 | // 如果是以.class结尾 171 | String className = PathUtils.trimSuffix(file.getName()); 172 | // 如果类名中有"$"不计算在内 173 | if (-1 != className.lastIndexOf("$")) { 174 | continue; 175 | } 176 | 177 | // 命中 178 | String result = PathUtils.concat(basePkg, ".", className); 179 | classNameList.add(result); 180 | } 181 | } 182 | } 183 | 184 | return classNameList; 185 | } 186 | 187 | /** 188 | * 过虑掉没有指定注解的类 189 | * @param classList 190 | * @return 191 | */ 192 | @TargetApi(Build.VERSION_CODES.N) 193 | private List filterComponents(List classList) { 194 | List newList = new ArrayList<>(20); 195 | 196 | classList.forEach(name -> { 197 | try { 198 | Class clazz = Class.forName(name); 199 | Annotation an = clazz.getAnnotation(this.anClazz); 200 | if (null != an) { 201 | newList.add(name); 202 | } 203 | 204 | } catch (ClassNotFoundException e) { 205 | e.printStackTrace(); 206 | } 207 | }); 208 | 209 | return newList; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |