├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── 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 │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ ├── layout │ │ │ │ ├── activity_expandable_listview.xml │ │ │ │ ├── fragment_test.xml │ │ │ │ ├── child_item.xml │ │ │ │ ├── parent_item.xml │ │ │ │ ├── item_listview.xml │ │ │ │ ├── tab1.xml │ │ │ │ ├── tab2.xml │ │ │ │ ├── tab3.xml │ │ │ │ ├── activity_tabhost.xml │ │ │ │ ├── activity_main.xml │ │ │ │ └── activity_adapter_view_test.xml │ │ │ ├── values-night │ │ │ │ └── themes.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── peakmain │ │ │ │ └── asmactualcombat │ │ │ │ ├── viewmodel │ │ │ │ └── ClickDealViewModel.kt │ │ │ │ ├── view │ │ │ │ ├── FixedHeightGridView.java │ │ │ │ └── FixedHeightListView.java │ │ │ │ ├── activity │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── TestActivity.java │ │ │ │ ├── AdapterViewTestActivity.java │ │ │ │ └── TabHostTestActivity.java │ │ │ │ ├── fragment │ │ │ │ └── TestClickFragment.java │ │ │ │ ├── adapter │ │ │ │ └── TextViewListViewAdapter.java │ │ │ │ ├── utils │ │ │ │ └── TestUtils.java │ │ │ │ └── App.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── peakmain │ │ │ └── asmactualcombat │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── peakmain │ │ └── asmactualcombat │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── plugin ├── .gitignore ├── consumer-rules.pro ├── peakmain.gpg ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── gradle-plugins │ │ │ └── com.peakmain.plugin.properties │ │ └── groovy │ │ └── com │ │ └── peakmain │ │ └── analytics │ │ └── plugin │ │ ├── utils │ │ ├── StringBuilderUtils.groovy │ │ ├── OpcodesUtils.groovy │ │ ├── log │ │ │ ├── LogUI.groovy │ │ │ └── Logger.groovy │ │ ├── MethodFieldUtils.groovy │ │ └── NetworkFieldUtils.groovy │ │ ├── entity │ │ ├── MethodCalledBean.groovy │ │ └── PeakmainMethodCell.groovy │ │ ├── PeakmainPlugin.groovy │ │ ├── visitor │ │ ├── NetworkMethodCalledReplaceAdapter.groovy │ │ ├── PeakmainVisitor.groovy │ │ ├── MonitorMethodCalledReplaceAdapter.groovy │ │ ├── MonitorMethodCalledClearAdapter.groovy │ │ └── base │ │ │ ├── MonitorMethodPatternAdapter.groovy │ │ │ └── MonitorDefalutMethodAdapter.groovy │ │ └── ext │ │ ├── MonitorConfig.groovy │ │ ├── NetworkHookMethodConfig.groovy │ │ └── PeakmainHookConfig.groovy ├── local.gradle ├── upload.gradle ├── build.gradle └── proguard-rules.pro ├── sdk ├── .gitignore ├── consumer-rules.pro ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── ids.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── peakmain │ │ │ │ └── sdk │ │ │ │ ├── utils │ │ │ │ ├── network │ │ │ │ │ ├── UserAgent.java │ │ │ │ │ ├── NetworkGlide.java │ │ │ │ │ └── Mob.java │ │ │ │ ├── ReplaceReflexMethodUtils.java │ │ │ │ ├── FragmentCacheUtil.java │ │ │ │ ├── LogManager.java │ │ │ │ ├── SystemUtils.java │ │ │ │ ├── AopUtils.java │ │ │ │ ├── Base64Coder.java │ │ │ │ ├── ReflectUtil.java │ │ │ │ └── PreferencesUtil.java │ │ │ │ ├── annotation │ │ │ │ ├── LogFrameInfo.java │ │ │ │ ├── SensorsDataTrackViewOnClick.java │ │ │ │ ├── DataFragmentTitle.java │ │ │ │ └── LogMessage.java │ │ │ │ ├── interfaces │ │ │ │ ├── OnUploadSensorsDataListener.java │ │ │ │ ├── ISensorsDataInstance.java │ │ │ │ └── OnReplaceMethodListener.java │ │ │ │ ├── constants │ │ │ │ └── SensorsDataConstants.java │ │ │ │ ├── manager │ │ │ │ └── SensorsDatabaseHelper.java │ │ │ │ ├── SensorsDataInstance.java │ │ │ │ ├── SensorsDataAPI.java │ │ │ │ ├── SensorsDataContentProvider.java │ │ │ │ └── bean │ │ │ │ └── SensorsEventBean.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── peakmain │ │ │ └── sdk │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── peakmain │ │ └── sdk │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── .idea ├── .gitignore ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── compiler.xml ├── kotlinc.xml ├── vcs.xml ├── gradle.xml ├── jarRepositories.xml ├── inspectionProfiles │ └── Project_Default.xml └── misc.xml ├── repo └── com │ └── peakmain │ └── android.plugin │ ├── maven-metadata.xml.md5 │ ├── maven-metadata.xml.sha1 │ ├── 1.0.0 │ ├── android.plugin-1.0.0.jar.md5 │ ├── android.plugin-1.0.0.pom.md5 │ ├── android.plugin-1.0.0-javadoc.jar.md5 │ ├── android.plugin-1.0.0-sources.jar.md5 │ ├── android.plugin-1.0.0.jar.sha1 │ ├── android.plugin-1.0.0.pom.sha1 │ ├── android.plugin-1.0.0-groovydoc.jar.md5 │ ├── android.plugin-1.0.0-groovydoc.jar.sha1 │ ├── android.plugin-1.0.0-javadoc.jar.sha1 │ ├── android.plugin-1.0.0-sources.jar.sha1 │ ├── android.plugin-1.0.0.jar │ ├── android.plugin-1.0.0-javadoc.jar │ ├── android.plugin-1.0.0-sources.jar │ ├── android.plugin-1.0.0-groovydoc.jar │ └── android.plugin-1.0.0.pom │ └── maven-metadata.xml ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── jitpack.yml ├── .gitignore ├── config.gradle ├── gradle.properties ├── gradlew.bat ├── README.md └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /sdk/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /sdk/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugin/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/maven-metadata.xml.md5: -------------------------------------------------------------------------------- 1 | 1aff9fd18322a3b736300a731672b239 -------------------------------------------------------------------------------- /plugin/peakmain.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/plugin/peakmain.gpg -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/maven-metadata.xml.sha1: -------------------------------------------------------------------------------- 1 | fc3e850bc127b742963bfc2521a96b60fadd172d -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.jar.md5: -------------------------------------------------------------------------------- 1 | fd6124103aa9a77e38eaf78e9558166d -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.pom.md5: -------------------------------------------------------------------------------- 1 | 1f4a8c2099f7fc1746b8bed2e5c8d073 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-javadoc.jar.md5: -------------------------------------------------------------------------------- 1 | 2cc9b1363bfc937a7649e1aa16cea730 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-sources.jar.md5: -------------------------------------------------------------------------------- 1 | 32d450b9507a682871fd3e8605a16eba -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.jar.sha1: -------------------------------------------------------------------------------- 1 | b1369af4e2ec9f4ab89b1a61a19ec57bdb5c1cc5 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.pom.sha1: -------------------------------------------------------------------------------- 1 | 4091e952207b4d3f651142fb23baae002a0a11c2 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-groovydoc.jar.md5: -------------------------------------------------------------------------------- 1 | 0ac51ea00d12ba6ce9f1a20e85b9f379 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-groovydoc.jar.sha1: -------------------------------------------------------------------------------- 1 | fbb8bc2211ff080e1824de7a463f086f0051ba54 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-javadoc.jar.sha1: -------------------------------------------------------------------------------- 1 | 56a89147078682bfb97de30a858b4920e26b746a -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-sources.jar.sha1: -------------------------------------------------------------------------------- 1 | 39df0624188e77e61afecdd148c4f6a2f37a0aef -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sdk' 2 | include ':plugin' 3 | include ':app' 4 | rootProject.name = "AsmActualCombat" 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AsmActualCombat 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sdk install java 11.0.10-open 3 | - sdk use java 11.0.10-open 4 | 5 | 6 | jdk: 7 | - openjdk11 -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /plugin/src/main/resources/META-INF/gradle-plugins/com.peakmain.plugin.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.peakmain.analytics.plugin.PeakmainPlugin -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/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/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/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/Peakmain/AsmActualCombat/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/Peakmain/AsmActualCombat/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.jar -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-javadoc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-javadoc.jar -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-sources.jar -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-groovydoc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Peakmain/AsmActualCombat/HEAD/repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0-groovydoc.jar -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sdk/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jan 19 15:44:53 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | android = [ 3 | compileSdkVersion: 31, 4 | targetSdkVersion : 31, 5 | minSdkVersion : 19, 6 | versionCode : 20220707, 7 | versionName : "1.1.0", 8 | ] 9 | dependencies = [ 10 | jpush: ['cn.jiguang.sdk:jpush:4.6.0', 11 | 'cn.jiguang.sdk:jcore:3.1.2',], 12 | ] 13 | } -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/maven-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.peakmain 4 | android.plugin 5 | 6 | 1.0.0 7 | 8 | 1.0.0 9 | 10 | 20231012030831 11 | 12 | 13 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/network/UserAgent.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils.network; 2 | 3 | 4 | /** 5 | * author :Peakmain 6 | * createTime:2022/6/14 7 | * mail:2726449200@qq.com 8 | * describe: 9 | */ 10 | public class UserAgent { 11 | 12 | public static String getUa(com.qiniu.android.http.UserAgent userAgent, String part) { 13 | return ""; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/viewmodel/ClickDealViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.viewmodel 2 | 3 | import com.peakmain.basiclibrary.base.viewmodel.BaseViewModel 4 | 5 | /** 6 | * author :Peakmain 7 | * createTime:2022/3/28 8 | * mail:2726449200@qq.com 9 | * describe: 10 | */ 11 | class ClickDealViewModel: BaseViewModel() { 12 | override fun initModel() { 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/network/NetworkGlide.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils.network; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * author :Peakmain 8 | * createTime:2022/6/16 9 | * mail:2726449200@qq.com 10 | * describe: 11 | */ 12 | public class NetworkGlide { 13 | public Map getHeaders() { 14 | return new HashMap<>(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/test/java/com/peakmain/asmactualcombat/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /plugin/local.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | apply plugin: 'maven' 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | uploadArchives { 8 | repositories.mavenDeployer { 9 | //本地仓库路径,以放到项目根目录下的 repo 的文件夹为例 10 | repository(url: uri('../repo')) 11 | 12 | //groupId 13 | pom.groupId = 'com.peakmain' 14 | 15 | //artifactId 16 | pom.artifactId = 'android.plugin' 17 | 18 | //插件版本号 19 | pom.version = '1.0.0' 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /sdk/src/test/java/com/peakmain/sdk/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk; 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 | } -------------------------------------------------------------------------------- /sdk/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_expandable_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/annotation/LogFrameInfo.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.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 | * author :Peakmain 10 | * createTime:2022/4/13 11 | * mail:2726449200@qq.com 12 | * describe:打印Method stack Map Frame 13 | */ 14 | 15 | @Target({ElementType.METHOD}) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface LogFrameInfo { 18 | } 19 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/annotation/SensorsDataTrackViewOnClick.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.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 | * author:Peakmain 10 | * createTime:2021/6/15 11 | * mail:2726449200@qq.com 12 | * describe: 13 | */ 14 | @Target({ElementType.METHOD}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface SensorsDataTrackViewOnClick { 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/child_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 13 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/annotation/DataFragmentTitle.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.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 | * author :Peakmain 10 | * createTime:2022/7/23 11 | * mail:2726449200@qq.com 12 | * describe:通过注解自定义 Fragment 的标题(title 属性) 13 | */ 14 | @Target({ElementType.TYPE}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface DataFragmentTitle { 17 | String title() default ""; 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/parent_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab1.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab2.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab3.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/annotation/LogMessage.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.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 | * author :Peakmain 10 | * createTime:2021/6/16 11 | * describe: 12 | */ 13 | 14 | @Target({ElementType.METHOD}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface LogMessage { 17 | /** 18 | * 是否打印方法耗时时间 19 | */ 20 | boolean isLogTime() default false; 21 | 22 | /** 23 | * 24 | * 是否打印方法的参数和返回值 25 | */ 26 | boolean isLogParametersReturnValue() default false; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/interfaces/OnUploadSensorsDataListener.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.interfaces; 2 | 3 | import com.peakmain.sdk.constants.SensorsDataConstants; 4 | 5 | /** 6 | * author :Peakmain 7 | * createTime:2022/3/29 8 | * mail:2726449200@qq.com 9 | * describe:上传埋点信息接口 10 | */ 11 | public interface OnUploadSensorsDataListener { 12 | /** 13 | * 上传埋点 14 | * 15 | * @param state APP_START_EVENT_STATE = 1; 16 | * APP_END__EVENT_STATE = 2; 17 | * APP_VIEW_SCREEN__EVENT_STATE = 3; 18 | * APP_VIEW_CLICK__EVENT_STATE = 4; 19 | * @param data 埋点数据 20 | */ 21 | void onUploadSensors(@SensorsDataConstants.STATE int state, String data); 22 | } 23 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/interfaces/ISensorsDataInstance.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.interfaces; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.peakmain.sdk.SensorsDataAPI; 7 | 8 | import org.json.JSONObject; 9 | 10 | /** 11 | * author :Peakmain 12 | * createTime:2022/7/8 13 | * mail:2726449200@qq.com 14 | * describe: 15 | */ 16 | public interface ISensorsDataInstance { 17 | 18 | 19 | void onEvent(String eventName, String eventValue); 20 | void track(@NonNull final String eventName, @Nullable JSONObject properties); 21 | void track(@NonNull final String eventName, @Nullable JSONObject properties,@Nullable OnUploadSensorsDataListener onUploadSensorsDataListener); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /plugin/upload.gradle: -------------------------------------------------------------------------------- 1 | 2 | version = '1.1.4' 3 | group = 'io.github.peakmain' 4 | gradlePlugin { 5 | plugins { 6 | peakmainPlugin { 7 | id = 'io.github.peakmain' 8 | implementationClass = 'com.peakmain.analytics.plugin.PeakmainPlugin' 9 | } 10 | } 11 | } 12 | pluginBundle { 13 | // These settings are set for the whole plugin bundle 14 | website = 'https://github.com/Peakmain/AsmActualCombat' 15 | vcsUrl = 'https://github.com/Peakmain/AsmActualCombat' 16 | 17 | description = 'Peakmain ASM plugin!' 18 | 19 | plugins { 20 | peakmainPlugin { 21 | // id is captured from java-gradle-plugin configuration 22 | displayName = 'com.peakmain.plugin' 23 | tags = ['android', 'asm_plugin'] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugin/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | plugins { 3 | id 'maven-publish' 4 | id 'java-gradle-plugin' 5 | id 'com.gradle.plugin-publish' version '0.18.0' 6 | } 7 | apply plugin: 'groovy' 8 | apply plugin: 'maven' 9 | apply from :'upload.gradle' 10 | apply from :'local.gradle' 11 | dependencies { 12 | implementation gradleApi() 13 | implementation localGroovy() 14 | 15 | implementation 'org.ow2.asm:asm:9.2' 16 | implementation 'org.ow2.asm:asm-commons:9.2' 17 | implementation 'org.ow2.asm:asm-analysis:9.2' 18 | implementation 'org.ow2.asm:asm-util:9.2' 19 | implementation 'org.ow2.asm:asm-tree:9.2' 20 | compileOnly 'com.android.tools.build:gradle:4.0.1', { 21 | exclude group: 'org.ow2.asm' 22 | } 23 | } 24 | 25 | repositories { 26 | google() 27 | mavenCentral() 28 | } 29 | 30 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/view/FixedHeightGridView.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.GridView; 6 | 7 | /** 8 | * author :Peakmain 9 | * createTime:2022/3/28 10 | * mail:2726449200@qq.com 11 | * describe: 12 | */ 13 | public class FixedHeightGridView extends GridView { 14 | public FixedHeightGridView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | @Override 19 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, 21 | MeasureSpec.AT_MOST); 22 | 23 | super.onMeasure(widthMeasureSpec, expandSpec); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /sdk/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 -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/view/FixedHeightListView.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ListView; 6 | 7 | /** 8 | * author :Peakmain 9 | * createTime:2022/3/28 10 | * mail:2726449200@qq.com 11 | * describe: 12 | */ 13 | public class FixedHeightListView extends ListView { 14 | public FixedHeightListView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | @Override 19 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, 21 | 22 | MeasureSpec.AT_MOST); 23 | 24 | super.onMeasure(widthMeasureSpec, expandSpec); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /plugin/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 -------------------------------------------------------------------------------- /app/src/androidTest/java/com/peakmain/asmactualcombat/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.peakmain.asmactualcombat", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_tabhost.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /sdk/src/androidTest/java/com/peakmain/sdk/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.peakmain.sdk.test", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/StringBuilderUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils 2 | 3 | import org.objectweb.asm.MethodVisitor 4 | import org.objectweb.asm.Opcodes 5 | 6 | /** 7 | * author :Peakmain 8 | * createTime:2022/4/6 9 | * mail:2726449200@qq.com 10 | * describe:StringBuilder的工具类 11 | */ 12 | class StringBuilderUtils { 13 | private MethodVisitor mv 14 | 15 | StringBuilderUtils(MethodVisitor methodVisitor) { 16 | this.mv = methodVisitor 17 | } 18 | 19 | void appendLdcString(String value) { 20 | mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder") 21 | mv.visitInsn(Opcodes.DUP) 22 | mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); 23 | mv.visitLdcInsn(value) 24 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false) 25 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false) 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.activity 2 | 3 | import android.content.Intent 4 | import cn.jiguang.w.c 5 | import com.peakmain.basiclibrary.base.activity.BaseActivity 6 | import com.peakmain.asmactualcombat.viewmodel.ClickDealViewModel 7 | import com.peakmain.asmactualcombat.R 8 | import com.peakmain.asmactualcombat.databinding.ActivityMainBinding 9 | import com.peakmain.asmactualcombat.utils.Utils 10 | import com.peakmain.ui.utils.ToastUtils 11 | 12 | /** 13 | * author :Peakmain 14 | * createTime:2022/1/14 15 | * mail:2726449200@qq.com 16 | * describe: 17 | */ 18 | class MainActivity(override val layoutId: Int = R.layout.activity_main) : 19 | BaseActivity() { 20 | 21 | override fun initView() { 22 | mBinding.buttonClick.setOnClickListener { 23 | startActivity(Intent(this, ClickDealActivity::class.java)) 24 | } 25 | mBinding.buttonClick1.setOnClickListener { 26 | //startActivity(Intent(this,TestActivity::class.java)) 27 | ToastUtils.showLong(Utils.getAndroidId(this)) 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /sdk/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | 5 | android { 6 | compileSdkVersion rootProject.ext.android.compileSdkVersion 7 | 8 | defaultConfig { 9 | minSdkVersion rootProject.ext.android.minSdkVersion 10 | targetSdkVersion rootProject.ext.android.targetSdkVersion 11 | versionCode rootProject.ext.android.versionCode 12 | versionName rootProject.ext.android.versionName 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | consumerProguardFiles "consumer-rules.pro" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_1_8 26 | targetCompatibility JavaVersion.VERSION_1_8 27 | } 28 | } 29 | 30 | dependencies { 31 | 32 | implementation 'androidx.appcompat:appcompat:1.2.0' 33 | implementation 'org.jetbrains:annotations:15.0' 34 | implementation 'com.qiniu:qiniu-android-sdk:7.3.15' 35 | implementation 'androidx.preference:preference:1.1.1' 36 | } -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/interfaces/OnReplaceMethodListener.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.interfaces; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.net.wifi.ScanResult; 7 | import android.net.wifi.WifiInfo; 8 | import android.net.wifi.WifiManager; 9 | import android.telephony.SubscriptionInfo; 10 | import android.telephony.TelephonyManager; 11 | 12 | import com.peakmain.sdk.constants.SensorsDataConstants; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * author :Peakmain 18 | * createTime:2022/4/15 19 | * mail:2726449200@qq.com 20 | * describe:替换方法监听事件 21 | */ 22 | public interface OnReplaceMethodListener { 23 | String onReplaceMethodListener(@SensorsDataConstants.TELEPHONY_STATE int telephoneState, TelephonyManager manager, int slotIndex); 24 | 25 | 26 | WifiInfo onReplaceMethodListener(WifiManager wifiManager); 27 | 28 | List onReplaceWifiManagerMethodListener(WifiManager wifiManager); 29 | 30 | String onReplaceMethodListener(SubscriptionInfo subscriptionInfo); 31 | 32 | List onReplaceMethodListener(PackageManager manager); 33 | 34 | String onReplaceMethodListener(ContentResolver resolver, String name); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/entity/MethodCalledBean.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.entity 2 | 3 | /** 4 | * author :Peakmain 5 | * createTime:2022/4/1 6 | * mail:2726449200@qq.com 7 | * describe: 8 | */ 9 | class MethodCalledBean { 10 | String methodOwner 11 | String methodName 12 | String[] methodDescriptor 13 | String newMethodOwner 14 | String newMethodName 15 | int newOpcode 16 | 17 | HashMap newMethodDescriptor 18 | 19 | 20 | MethodCalledBean(String methodOwner, String methodName, String[] methodDescriptor) { 21 | this.methodOwner = methodOwner 22 | this.methodName = methodName 23 | this.methodDescriptor = methodDescriptor 24 | } 25 | 26 | MethodCalledBean(String methodOwner, String methodName, String[] methodDescriptor, String newMethodOwner, String newMethodName, int newOpcode, HashMap newMethodDescriptor) { 27 | this.methodOwner = methodOwner 28 | this.methodName = methodName 29 | this.methodDescriptor = methodDescriptor 30 | this.newMethodOwner = newMethodOwner 31 | this.newMethodName = newMethodName 32 | this.newOpcode = newOpcode 33 | this.newMethodDescriptor = newMethodDescriptor 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/OpcodesUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils 2 | 3 | import org.objectweb.asm.Opcodes 4 | 5 | class OpcodesUtils implements Opcodes { 6 | public static final int ASM_VERSION = Opcodes.ASM9 7 | static boolean isSynthetic(int access) { 8 | return (access & ACC_SYNTHETIC) != 0 9 | } 10 | 11 | static boolean isPrivate(int access) { 12 | return (access & ACC_PRIVATE) != 0 13 | } 14 | 15 | static boolean isPublic(int access) { 16 | return (access & ACC_PUBLIC) != 0 17 | } 18 | 19 | static boolean isStatic(int access) { 20 | return (access & ACC_STATIC) != 0 21 | } 22 | 23 | static boolean isNative(int access) { 24 | return (access & ACC_NATIVE) != 0 25 | } 26 | 27 | static boolean isAbstract(int access) { 28 | return (access & ACC_ABSTRACT) != 0 29 | } 30 | /** 31 | * 是否是接口 32 | */ 33 | static boolean isInterface(int access) { 34 | return (access & ACC_INTERFACE) != 0 35 | } 36 | /** 37 | * 是否是枚举类型 38 | */ 39 | static boolean isEnum(int access) { 40 | return (access & ACC_ENUM) != 0 41 | 42 | } 43 | 44 | static boolean isInitMethod(String name) { 45 | return name == "" 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/log/LogUI.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils.log 2 | /** 3 | * 具体规则 4 | * 字背景颜色范围: 40--49 字颜色: 30--39 5 | * 40: 黑 30: 黑 6 | * 41:红 31: 红 7 | * 42:绿 32: 绿 8 | * 43:黄 33: 黄 9 | * 44:蓝 34: 蓝 10 | * 45:紫 35: 紫 11 | * 46:深绿 36: 深绿 12 | * 47:白色 37: 白色 13 | * 14 | * 输出特效格式控制 15 | * 033[0m 关闭所有属性 16 | * 033[1m 设置高亮度 17 | * 03[4m 下划线 18 | * 033[5m 闪烁 19 | * 033[7m 反显 20 | * 033[8m 消隐 21 | * 033[30m -- \033[37m 设置前景色 22 | * 033[40m -- \033[47m 设置背景色 23 | */ 24 | enum LogUI { 25 | //color 26 | C_ERROR("\033[40;31m"), 27 | C_WARN("\033[40;33m"), 28 | C_BLACK_GREEN("\033[40;32m"), 29 | //end 30 | E_NORMAL("\033[0m"); 31 | 32 | private final String value 33 | 34 | LogUI(String value) { 35 | this.value = value 36 | } 37 | 38 | String getValue() { 39 | return this.value 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 17 | 23 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/entity/PeakmainMethodCell.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.entity 2 | 3 | class PeakmainMethodCell { 4 | /** 5 | * 原方法名 6 | */ 7 | String name 8 | /** 9 | * 原方法描述 10 | */ 11 | String desc 12 | /** 13 | * 方法所在的接口或类 14 | */ 15 | String parent 16 | /** 17 | * 采集数据的方法名 18 | */ 19 | String agentName 20 | /** 21 | * 采集数据的方法描述 22 | */ 23 | String agentDesc 24 | /** 25 | * 采集数据的方法参数起始索引( 0:this,1+:普通参数 ) 26 | */ 27 | int paramsStart 28 | /** 29 | * 采集数据的方法参数个数 30 | */ 31 | int paramsCount 32 | /** 33 | * 参数类型对应的ASM指令,加载不同类型的参数需要不同的指令 34 | */ 35 | List opcodes 36 | 37 | PeakmainMethodCell(String name, String desc, String agentName) { 38 | this.name = name 39 | this.desc = desc 40 | this.agentName = agentName 41 | } 42 | 43 | PeakmainMethodCell(String name, String desc, String parent, String agentName, String agentDesc, int paramsStart, int paramsCount, List opcodes) { 44 | this.name = name 45 | this.desc = desc 46 | this.parent = parent 47 | this.agentName = agentName 48 | this.agentDesc = agentDesc 49 | this.paramsStart = paramsStart 50 | this.paramsCount = paramsCount 51 | this.opcodes = opcodes 52 | } 53 | } -------------------------------------------------------------------------------- /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=-Xmx2048m -Dfile.encoding=UTF-8 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 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | monitorPlugin.disableAppPlugin=false 23 | android.useNewApkCreator=false 24 | 25 | 26 | applicationId="com.peakmain.asmactualcombat" 27 | jpushKey=c96e188b4adafb8551aea1a3 -------------------------------------------------------------------------------- /repo/com/peakmain/android.plugin/1.0.0/android.plugin-1.0.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.peakmain 6 | android.plugin 7 | 1.0.0 8 | 9 | 10 | org.ow2.asm 11 | asm 12 | 9.2 13 | runtime 14 | 15 | 16 | org.ow2.asm 17 | asm-commons 18 | 9.2 19 | runtime 20 | 21 | 22 | org.ow2.asm 23 | asm-analysis 24 | 9.2 25 | runtime 26 | 27 | 28 | org.ow2.asm 29 | asm-util 30 | 9.2 31 | runtime 32 | 33 | 34 | org.ow2.asm 35 | asm-tree 36 | 9.2 37 | runtime 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/ReplaceReflexMethodUtils.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.peakmain.sdk.map.p; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * author :Peakmain 11 | * createTime:2022/6/10 12 | * mail:2726449200@qq.com 13 | * describe: 14 | */ 15 | public class ReplaceReflexMethodUtils { 16 | 17 | public static Method a(Class clazz, String name, Class... var2) { 18 | if("getImei".equals(name)){ 19 | Log.e("TAG","getImei"); 20 | return null; 21 | } 22 | try { 23 | return clazz.getDeclaredMethod(c(name), var2); 24 | } catch (Throwable var3) { 25 | return null; 26 | } 27 | } 28 | public static String c(String var0) { 29 | return var0.length() < 2 ? "" : p.a(var0.substring(1)); 30 | } 31 | public static Object a(String var0, String name, Object[] var2, Class[] var3) throws Exception { 32 | if("getImei".equals(name)){ 33 | Log.e("TAG","getImei"); 34 | return null; 35 | } 36 | return a(Class.forName(var0), name, var2, var3); 37 | } 38 | private static Object a(Class var0, String var1, Object[] var2, Class[] var3) throws Exception { 39 | Method var4; 40 | if (!(var4 = var0.getDeclaredMethod(var1, var3)).isAccessible()) { 41 | var4.setAccessible(true); 42 | } 43 | 44 | return var4.invoke((Object)null, var2); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/fragment/TestClickFragment.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.fragment; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.widget.AppCompatButton; 12 | import androidx.fragment.app.Fragment; 13 | 14 | import com.peakmain.asmactualcombat.R; 15 | import com.peakmain.sdk.annotation.DataFragmentTitle; 16 | import com.peakmain.ui.utils.ToastUtils; 17 | 18 | /** 19 | * author :Peakmain 20 | * createTime:2022/3/28 21 | * mail:2726449200@qq.com 22 | * describe: 23 | */ 24 | @DataFragmentTitle(title="测试Fragment") 25 | public class TestClickFragment extends Fragment { 26 | @Nullable 27 | @Override 28 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 29 | View view = inflater.inflate(R.layout.fragment_test, container, false); 30 | AppCompatButton button = view.findViewById(R.id.button); 31 | button.setTag(R.id.sensors_analytics_tag_view_fragment_name,TestClickFragment.class.getCanonicalName()); 32 | button.setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View view) { 35 | ToastUtils.showShort("TestFragment click"); 36 | } 37 | }); 38 | return view; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_adapter_view_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 17 | 18 | 22 | 23 | 29 | 30 | 36 | 37 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/FragmentCacheUtil.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import androidx.collection.LruCache; 6 | 7 | import java.lang.ref.WeakReference; 8 | 9 | /** 10 | * author :Peakmain 11 | * createTime:2022/7/23 12 | * mail:2726449200@qq.com 13 | * describe: 14 | */ 15 | public class FragmentCacheUtil { 16 | private static final LruCache> sFragmentLruCache = new LruCache<>(Integer.MAX_VALUE); 17 | public static void setFragmentToCache(String fragmentName, Object object) { 18 | if (!TextUtils.isEmpty(fragmentName) && null != object) { 19 | sFragmentLruCache.put(fragmentName, new WeakReference<>(object)); 20 | } 21 | } 22 | 23 | public static Object getFragmentFromCache(String fragmentName) { 24 | try { 25 | if (!TextUtils.isEmpty(fragmentName)) { 26 | WeakReference weakReference = null; 27 | weakReference = sFragmentLruCache.get(fragmentName); 28 | Object object; 29 | if (null != weakReference) { 30 | object = weakReference.get(); 31 | if (null != object) { 32 | return object; 33 | } 34 | } 35 | object = Class.forName(fragmentName).newInstance(); 36 | sFragmentLruCache.put(fragmentName, new WeakReference<>(object)); 37 | return object; 38 | } 39 | } catch (Exception e) { 40 | LogManager.printStackTrace(e); 41 | } 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/PeakmainPlugin.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin 2 | 3 | import com.android.build.gradle.AppExtension 4 | import com.peakmain.analytics.plugin.ext.MonitorConfig 5 | import com.peakmain.analytics.plugin.transform.MonitorTransform 6 | import com.peakmain.analytics.plugin.utils.log.Logger 7 | import org.gradle.api.Plugin 8 | import org.gradle.api.Project 9 | 10 | /** 11 | * author :Peakmain 12 | * createTime:1/19/22 13 | * mail:2726449200@qq.com 14 | * describe: 15 | */ 16 | class PeakmainPlugin implements Plugin { 17 | @Override 18 | void apply(Project project) { 19 | MonitorConfig extension = project.extensions.create('monitorPlugin', MonitorConfig) 20 | boolean disablePlugin = false 21 | Properties properties = new Properties() 22 | //gradle.properties是否存在 23 | if (project.rootProject.file('gradle.properties').exists()) { 24 | //gradle.properties文件->输入流 25 | properties.load(project.rootProject.file('gradle.properties').newDataInputStream()) 26 | disablePlugin = Boolean.parseBoolean(properties.getProperty("monitorPlugin.disableAppPlugin", "false")) 27 | } 28 | //如果disablePlugin可用 29 | if (!disablePlugin) { 30 | Logger.printPluginStart() 31 | 32 | AppExtension appExtension = project.extensions.findByType(AppExtension.class) 33 | def transform = new MonitorTransform(project) 34 | appExtension.registerTransform(transform) 35 | project.afterEvaluate { 36 | extension.convertConfig() 37 | transform.monitorConfig = extension 38 | } 39 | } else { 40 | println("------------您已关闭了埋点插件--------------") 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/adapter/TextViewListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import com.peakmain.asmactualcombat.R; 11 | 12 | import java.util.Locale; 13 | 14 | /** 15 | * author :Peakmain 16 | * createTime:2022/3/28 17 | * mail:2726449200@qq.com 18 | * describe: 19 | */ 20 | public class TextViewListViewAdapter extends BaseAdapter { 21 | private LayoutInflater mLayoutInflater; 22 | 23 | public TextViewListViewAdapter(Context context) { 24 | mLayoutInflater = LayoutInflater.from(context); 25 | } 26 | 27 | @Override 28 | public int getCount() { 29 | return 5; 30 | } 31 | 32 | @Override 33 | public Object getItem(int position) { 34 | return null; 35 | } 36 | 37 | @Override 38 | public long getItemId(int position) { 39 | return 0; 40 | } 41 | 42 | @Override 43 | public View getView(int position, View convertView, ViewGroup parent) { 44 | if (convertView == null) { 45 | convertView = mLayoutInflater.inflate(R.layout.item_listview, parent, false); 46 | ViewHolder holder = new ViewHolder(convertView); 47 | convertView.setTag(holder); 48 | } 49 | ViewHolder holder = (ViewHolder) convertView.getTag(); 50 | holder.title.setText(String.format(Locale.CHINA, "位置 %d", position)); 51 | 52 | return convertView; 53 | } 54 | 55 | private static class ViewHolder { 56 | ViewHolder(View viewRoot) { 57 | title = viewRoot.findViewById(R.id.title); 58 | } 59 | 60 | public TextView title; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/activity/TestActivity.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.activity; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.Nullable; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | 8 | import com.peakmain.asmactualcombat.R; 9 | import com.peakmain.sdk.annotation.LogFrameInfo; 10 | import com.peakmain.sdk.annotation.LogMessage; 11 | 12 | /** 13 | * author :Peakmain 14 | * createTime:2022/3/28 15 | * mail:2726449200@qq.com 16 | * describe:测试(不用看) 17 | */ 18 | public class TestActivity extends AppCompatActivity { 19 | @Override 20 | protected void onCreate(@Nullable Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | } 24 | 25 | @LogMessage 26 | public String getMethod(boolean b) { 27 | try { 28 | Thread.sleep(1000); 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | return "getMethod"; 33 | } 34 | 35 | @LogMessage(isLogTime = true) 36 | public String getMethodTime(long l) { 37 | try { 38 | Thread.sleep(1000); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | return "getMethod"; 43 | } 44 | 45 | @LogMessage(isLogParametersReturnValue = true) 46 | public String getMethodParametersReturnValue(String name) { 47 | try { 48 | Thread.sleep(1000); 49 | } catch (InterruptedException e) { 50 | e.printStackTrace(); 51 | } 52 | return "treasure"; 53 | } 54 | 55 | @LogMessage(isLogTime = true, isLogParametersReturnValue = true) 56 | public String test(int a) { 57 | try { 58 | Thread.sleep(1000); 59 | } catch (InterruptedException e) { 60 | e.printStackTrace(); 61 | } 62 | return "peakmain"; 63 | } 64 | 65 | @LogFrameInfo 66 | public String testLogMethodStackMapFrame(int a) { 67 | try { 68 | Thread.sleep(1000); 69 | } catch (InterruptedException e) { 70 | e.printStackTrace(); 71 | } 72 | return "peakmain"; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/network/Mob.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils.network; 2 | 3 | 4 | /** 5 | * author :Peakmain 6 | * createTime:2022/6/14 7 | * mail:2726449200@qq.com 8 | * describe: 9 | */ 10 | public class Mob { 11 | /* public static String httpGet(NetworkHelper networkHelper, String url, ArrayList> values, ArrayList> headers, NetworkHelper.NetworkTimeOut timeout) throws Throwable { 12 | if (headers != null) { 13 | headers.clear(); 14 | } 15 | return networkHelper.httpGet(url, values, headers, timeout); 16 | } 17 | 18 | public static void rawGet(NetworkHelper networkHelper, String url, ArrayList> headers, RawNetworkCallback callback, NetworkHelper.NetworkTimeOut timeout) throws Throwable { 19 | if (headers != null) { 20 | headers.clear(); 21 | } 22 | networkHelper.rawGet(url, headers, callback, timeout); 23 | } 24 | 25 | public void httpPost(NetworkHelper networkHelper, String url, ArrayList> headers, int chunkLength, HttpResponseCallback callback, NetworkHelper.NetworkTimeOut timeout) throws Throwable { 26 | if (headers != null) { 27 | headers.clear(); 28 | } 29 | networkHelper.httpPost(url, headers, chunkLength, callback, timeout); 30 | } 31 | 32 | public void httpPost(NetworkHelper networkHelper,String url, ArrayList> values, ArrayList> files, ArrayList> headers, int chunkLength, HttpResponseCallback callback, NetworkHelper.NetworkTimeOut timeout) throws Throwable { 33 | if (headers != null) { 34 | headers.clear(); 35 | } 36 | networkHelper.httpPost(url,values,files,headers,chunkLength,callback,timeout); 37 | } 38 | public void httpPost(NetworkHelper networkHelper,String url, ArrayList> values, byte[] data, ArrayList> headers, int chunkLength, HttpResponseCallback callback, NetworkHelper.NetworkTimeOut timeout) throws Throwable { 39 | if (headers != null) { 40 | headers.clear(); 41 | } 42 | networkHelper.httpPost(url,values,data,headers,chunkLength,callback,timeout); 43 | }*/ 44 | } 45 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/utils/TestUtils.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.utils; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.WifiInfo; 5 | import android.net.wifi.WifiManager; 6 | import android.os.Build; 7 | import android.provider.Settings; 8 | import android.telephony.TelephonyManager; 9 | 10 | /** 11 | * author :Peakmain 12 | * createTime:2022/4/20 13 | * mail:2726449200@qq.com 14 | * describe: 15 | */ 16 | public class TestUtils { 17 | public static String getDeviceId(Context context) { 18 | String tac = ""; 19 | TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 20 | if (manager.getDeviceId() == null || manager.getDeviceId().equals("")) { 21 | if (Build.VERSION.SDK_INT >= 23) { 22 | tac = manager.getDeviceId(0); 23 | } 24 | } else { 25 | tac = manager.getDeviceId(); 26 | } 27 | return tac; 28 | } 29 | 30 | public static String getMeid(Context context) { 31 | TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 33 | return manager.getMeid(); 34 | } 35 | return "getMeid"; 36 | } 37 | 38 | /** 39 | * Android 6.0 之前(不包括6.0) 40 | */ 41 | public static String getMacDefault(Context context) { 42 | String mac = "未获取到设备Mac地址"; 43 | if (context == null) return mac; 44 | WifiManager wifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 45 | WifiInfo info = null; 46 | try { 47 | info = wifi.getConnectionInfo(); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | /* 52 | if (info == null) return mac; 53 | mac = info.getMacAddress(); 54 | 55 | if (!TextUtils.isEmpty(mac)) mac = mac.toUpperCase(Locale.ENGLISH); 56 | */ 57 | 58 | return mac; 59 | } 60 | 61 | public static String getAndroidId(Context context) { 62 | return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'com.peakmain.plugin' 5 | } 6 | android { 7 | compileSdkVersion rootProject.ext.android.compileSdkVersion 8 | 9 | defaultConfig { 10 | applicationId applicationId 11 | minSdkVersion rootProject.ext.android.minSdkVersion 12 | targetSdkVersion rootProject.ext.android.targetSdkVersion 13 | versionCode rootProject.ext.android.versionCode 14 | versionName rootProject.ext.android.versionName 15 | multiDexEnabled true 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | debug { 25 | manifestPlaceholders = [ 26 | JPUSH_PKGNAME: applicationId, 27 | JPUSH_APPKEY : jpushKey as String, 28 | JPUSH_CHANNEL: "developer-default", 29 | ] 30 | } 31 | } 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | buildFeatures { 40 | dataBinding { 41 | enabled true 42 | } 43 | } 44 | } 45 | 46 | dependencies { 47 | 48 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 49 | implementation 'androidx.core:core-ktx:1.3.2' 50 | implementation 'androidx.appcompat:appcompat:1.2.0' 51 | implementation 'com.google.android.material:material:1.6.1' 52 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 53 | implementation project(path: ':sdk') 54 | implementation 'com.github.Peakmain:BasicLibrary:+' 55 | implementation 'com.github.Peakmain:BasicUI:+' 56 | implementation 'com.github.bumptech.glide:glide:4.9.0' 57 | annotationProcessor "com.android.databinding:compiler:3.1.4" 58 | implementation(rootProject.ext.dependencies.jpush) 59 | implementation 'com.qiniu:qiniu-android-sdk:7.3.15' 60 | } 61 | monitorPlugin { 62 | whiteList = [ 63 | "com.peakmain.asmactualcombat.utils.TestUtils", 64 | "com.peakmain.plugin" 65 | ] 66 | methodStatus = 1 67 | disableStackMapFrame = false 68 | interceptPackageName = "com.peakmain" 69 | } 70 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/LogManager.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.annotation.Keep; 6 | 7 | import com.peakmain.sdk.BuildConfig; 8 | import com.peakmain.sdk.SensorsDataAPI; 9 | 10 | import java.text.DateFormat; 11 | import java.text.SimpleDateFormat; 12 | import java.util.Arrays; 13 | import java.util.Date; 14 | 15 | /** 16 | * author :Peakmain 17 | * createTime:2022/3/28 18 | * mail:2726449200@qq.com 19 | * describe: 20 | */ 21 | public class LogManager { 22 | private static final String TAG = SensorsDataAPI.class.getCanonicalName(); 23 | private static final DateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 24 | 25 | @Keep 26 | public static void e(String value) { 27 | if (!BuildConfig.DEBUG) 28 | return; 29 | Log.e(TAG, value); 30 | } 31 | 32 | @Keep 33 | public static void d(String value) { 34 | if (!BuildConfig.DEBUG) 35 | return; 36 | Log.d(TAG, value); 37 | } 38 | 39 | public static void println(boolean value) { 40 | e(value + ""); 41 | } 42 | 43 | public static void println(byte value) { 44 | e(value + ""); 45 | } 46 | 47 | public static void println(char value) { 48 | e(value + ""); 49 | } 50 | 51 | public static void println(short value) { 52 | e(value + ""); 53 | } 54 | 55 | public static void println(int value) { 56 | e(String.valueOf(value)); 57 | } 58 | 59 | public static void println(float value) { 60 | e(value + ""); 61 | } 62 | 63 | public static void println(long value) { 64 | e(value + ""); 65 | } 66 | 67 | public static void println(double value) { 68 | e(value + ""); 69 | } 70 | 71 | public static void println(Object value) { 72 | if (value == null) { 73 | d(""); 74 | } else if (value instanceof String) { 75 | d(value + ""); 76 | } else if (value instanceof Date) { 77 | d(fm.format(value) + ""); 78 | } else if (value instanceof char[]) { 79 | d(Arrays.toString((char[]) value) + ""); 80 | } else { 81 | d(value.getClass() + ":" + value.toString()); 82 | } 83 | } 84 | 85 | public static void printlnStr(String value) { 86 | e(value); 87 | } 88 | 89 | 90 | public static void printStackTrace(Exception e) { 91 | if (e != null) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/constants/SensorsDataConstants.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.constants; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * author :Peakmain 10 | * createTime:2022/4/1 11 | * mail:2726449200@qq.com 12 | * describe: 13 | */ 14 | public class SensorsDataConstants { 15 | public static final String SDK_VERSION = "1.1.3"; 16 | public static final String APP_START_EVENT_NAME = "AppStart"; 17 | public static final String APP_END__EVENT_NAME = "AppEnd"; 18 | public static final String APP_VIEW_SCREEN__EVENT_NAME = "AppViewScreen"; 19 | public static final String APP_VIEW_CLICK__EVENT_NAME = "AppClick"; 20 | 21 | public static final int APP_START_EVENT_STATE = 1; 22 | public static final int APP_END__EVENT_STATE = 2; 23 | public static final int APP_VIEW_SCREEN__EVENT_STATE = 3; 24 | public static final int APP_VIEW_CLICK__EVENT_STATE = 4; 25 | 26 | @IntDef({APP_START_EVENT_STATE, APP_VIEW_SCREEN__EVENT_STATE, APP_END__EVENT_STATE, APP_VIEW_CLICK__EVENT_STATE}) 27 | @Retention(RetentionPolicy.SOURCE) 28 | public @interface STATE { 29 | } 30 | 31 | public static final int GET_DEVICE_ID = 1; 32 | public static final int GET_MEID = 2; 33 | public static final int GET_IMEI = 3; 34 | public static final int GET_SUBSCRIBER_ID = 4; 35 | public static final int GET_SIM_SERIAL_NUMBER = 5; 36 | public static final int GET_MAC_ADDRESS = 6; 37 | public static final int GET_SSID = 7; 38 | public static final int GET_BSSID = 8; 39 | public static final int GET_IP_ADDRESS = 9; 40 | 41 | @IntDef({GET_DEVICE_ID, GET_MEID, GET_IMEI, GET_SUBSCRIBER_ID, GET_SIM_SERIAL_NUMBER}) 42 | @Retention(RetentionPolicy.SOURCE) 43 | public @interface TELEPHONY_STATE { 44 | } 45 | 46 | @IntDef({GET_MAC_ADDRESS, GET_SSID, GET_BSSID, GET_IP_ADDRESS}) 47 | @Retention(RetentionPolicy.SOURCE) 48 | public @interface WIFI_STATE { 49 | } 50 | 51 | 52 | public static final String ELEMENT_ID = "element_id"; 53 | public static final String ELEMENT_TYPE = "element_type"; 54 | public static final String ELEMENT_CONTENT = "element_content"; 55 | public static final String ACTIVITY_NAME = "activity"; 56 | public static final String PAGE_TITLE = "page_title"; 57 | public static final String ELEMENT_POSITION = "element_position"; 58 | public static final String ELEMENT_PATH = "element_path"; 59 | public static final String PAGE_PATH = "page_path"; 60 | public static final String TITLE = "title"; 61 | 62 | public static final String REFER_PAGE_PATH = "referrer_page_path"; 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/NetworkMethodCalledReplaceAdapter.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor 2 | 3 | import com.peakmain.analytics.plugin.entity.MethodCalledBean 4 | import com.peakmain.analytics.plugin.ext.MonitorConfig 5 | import com.peakmain.analytics.plugin.ext.MonitorHookMethodConfig 6 | import com.peakmain.analytics.plugin.ext.NetworkHookMethodConfig 7 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 8 | import com.peakmain.analytics.plugin.utils.NetworkFieldUtils 9 | import com.peakmain.analytics.plugin.utils.OpcodesUtils 10 | import com.peakmain.analytics.plugin.visitor.base.MonitorDefalutMethodAdapter 11 | import org.objectweb.asm.ClassVisitor 12 | import org.objectweb.asm.MethodVisitor 13 | import org.objectweb.asm.Type 14 | 15 | /** 16 | * author :Peakmain 17 | * createTime:2022/6/14 18 | * mail:2726449200@qq.com 19 | * describe:网络库的请求头部替换 20 | */ 21 | class NetworkMethodCalledReplaceAdapter extends MonitorDefalutMethodAdapter { 22 | private int mAccess 23 | private ClassVisitor classVisitor 24 | private String mClassName 25 | private MonitorConfig monitorConfig 26 | private String methodDesc 27 | private MethodVisitor methodVisitor 28 | /** 29 | * Constructs a new {@link AdviceAdapter}. 30 | * 31 | * @param mv @param access the method's access flags (see {@link Opcodes}). 32 | * @param name the method's name. 33 | * @param desc 34 | */ 35 | NetworkMethodCalledReplaceAdapter(MethodVisitor mv, int access, String name, String desc, ClassVisitor classVisitor, String className, MonitorConfig monitorConfig) { 36 | super(mv, access, name, desc) 37 | mAccess = access 38 | this.classVisitor = classVisitor 39 | mClassName = className 40 | this.monitorConfig = monitorConfig 41 | methodDesc = desc 42 | methodVisitor = mv 43 | } 44 | 45 | 46 | @Override 47 | void visitMethodInsn(int opcodeAndSource, String owner, String name, String descriptor, boolean isInterface) { 48 | HashMap methodReplaceBeans = NetworkHookMethodConfig.methodCalledBeans 49 | String desc = owner + name + descriptor 50 | if (methodReplaceBeans.containsKey(desc)) { 51 | if (monitorConfig.enableLog) { 52 | println("拦截网络请求的class:" + mClassName + ",方法的名字:" + name + ",方法的描述符:" + descriptor) 53 | } 54 | MethodCalledBean bean = methodReplaceBeans.get(desc) 55 | super.visitMethodInsn(bean.newOpcode, bean.newMethodOwner, bean.newMethodName, bean.newMethodDescriptor.get(descriptor), false) 56 | } else { 57 | super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface) 58 | } 59 | } 60 | 61 | 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/activity/AdapterViewTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | import android.view.View; 6 | import android.widget.AdapterView; 7 | import android.widget.BaseAdapter; 8 | import android.widget.GridView; 9 | import android.widget.ListView; 10 | import android.widget.Toast; 11 | 12 | import androidx.annotation.Nullable; 13 | import androidx.appcompat.app.ActionBar; 14 | import androidx.appcompat.app.AppCompatActivity; 15 | 16 | import com.peakmain.asmactualcombat.R; 17 | import com.peakmain.asmactualcombat.adapter.TextViewListViewAdapter; 18 | 19 | /** 20 | * author :Peakmain 21 | * createTime:2022/3/28 22 | * mail:2726449200@qq.com 23 | * describe: 24 | */ 25 | public class AdapterViewTestActivity extends AppCompatActivity { 26 | @Override 27 | protected void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_adapter_view_test); 30 | initListView(); 31 | initGridView(); 32 | 33 | ActionBar actionBar = getSupportActionBar(); 34 | if(actionBar != null){ 35 | actionBar.setHomeButtonEnabled(true); 36 | actionBar.setDisplayHomeAsUpEnabled(true); 37 | } 38 | } 39 | 40 | @SuppressWarnings("Convert2Lambda") 41 | private void initGridView() { 42 | GridView gridView = findViewById(R.id.gridView); 43 | BaseAdapter adapter = new TextViewListViewAdapter(this); 44 | gridView.setAdapter(adapter); 45 | gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 46 | @Override 47 | public void onItemClick(AdapterView parent, View view, int position, long id) { 48 | Toast.makeText(AdapterViewTestActivity.this, "dd:" + position, Toast.LENGTH_SHORT).show(); 49 | } 50 | }); 51 | } 52 | 53 | @SuppressWarnings("Convert2Lambda") 54 | private void initListView() { 55 | ListView listView = findViewById(R.id.listView); 56 | BaseAdapter adapter = new TextViewListViewAdapter(this); 57 | listView.setAdapter(adapter); 58 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 59 | @Override 60 | public void onItemClick(AdapterView parent, View view, int position, long id) { 61 | Toast.makeText(AdapterViewTestActivity.this, "dd:" + position, Toast.LENGTH_SHORT).show(); 62 | } 63 | }); 64 | } 65 | 66 | @Override 67 | public boolean onOptionsItemSelected(MenuItem item) { 68 | switch (item.getItemId()) { 69 | case android.R.id.home: 70 | this.onBackPressed(); 71 | return true; 72 | } 73 | return super.onOptionsItemSelected(item); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/SystemUtils.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.res.Resources; 7 | import android.os.Build; 8 | 9 | import java.util.Locale; 10 | 11 | /** 12 | * author :Peakmain 13 | * createTime:2022/7/7 14 | * mail:2726449200@qq.com 15 | * describe: 16 | */ 17 | public class SystemUtils { 18 | public static long getVersionCode(Context context) { 19 | long versionCode = 0; 20 | try { 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 22 | versionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).getLongVersionCode(); 23 | } else { 24 | versionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; 25 | } 26 | } catch (PackageManager.NameNotFoundException e) { 27 | e.printStackTrace(); 28 | } 29 | return versionCode; 30 | } 31 | 32 | public static String getVersionName(Context context) { 33 | String versionName = null; 34 | try { 35 | versionName = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; 36 | } catch (PackageManager.NameNotFoundException e) { 37 | e.printStackTrace(); 38 | } 39 | return versionName; 40 | } 41 | 42 | /** 43 | * 获取当前手机系统语言。 44 | * 45 | * @return 返回当前系统语言。例如:当前设置的是“中文-中国”,则返回“zh-CN” 46 | */ 47 | public static String getSystemLanguage() { 48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 49 | return Resources.getSystem().getConfiguration().getLocales().get(0).getLanguage(); 50 | } else { 51 | return Resources.getSystem().getConfiguration().locale.getLanguage(); 52 | } 53 | } 54 | 55 | /** 56 | * 获取app的ApplicationId 57 | */ 58 | public static String getProcessName(Context context) { 59 | if (context == null) return ""; 60 | try { 61 | return context.getApplicationInfo().processName; 62 | } catch (Exception e) { 63 | LogManager.println(e); 64 | } 65 | return ""; 66 | } 67 | /** 68 | * 获取应用名称 69 | * 70 | * @param context Context 71 | * @return 应用名称 72 | */ 73 | public static CharSequence getAppName(Context context) { 74 | if (context == null) return ""; 75 | try { 76 | PackageManager packageManager = context.getPackageManager(); 77 | ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); 78 | return applicationInfo.loadLabel(packageManager); 79 | } catch (Throwable e) { 80 | e.printStackTrace(); 81 | } 82 | return ""; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsmActualCombat 2 | **使用文档链接:https://github.com/Peakmain/AsmActualCombat/wiki** 3 | 4 | ### How To 5 | 6 | #### 旧版本添加方式 7 | 8 | **ASM插件依赖** 9 | Add it in your root build.gradle at the end of repositories: 10 | ``` 11 | buildscript { 12 | repositories { 13 | maven { 14 | url "https://plugins.gradle.org/m2/" 15 | } 16 | } 17 | dependencies { 18 | classpath "io.github.peakmain:plugin:1.1.4" 19 | } 20 | } 21 | 22 | apply plugin: "com.peakmain.plugin" 23 | ``` 24 | **拦截事件sdk的依赖** 25 | - Step 1. Add the JitPack repository to your build file 26 | Add it in your root build.gradle at the end of repositories: 27 | ``` 28 | allprojects { 29 | repositories { 30 | ... 31 | maven { url 'https://jitpack.io' } 32 | } 33 | } 34 | ``` 35 | - Step 2. Add the dependency 36 | ``` 37 | dependencies { 38 | implementation 'com.github.Peakmain:AsmActualCombat:1.1.5' 39 | } 40 | ``` 41 | #### 新版本添加方式 42 | 43 | **settings.gradle** 44 | ``` 45 | pluginManagement { 46 | repositories { 47 | //插件依赖 48 | maven { 49 | url "https://plugins.gradle.org/m2/" 50 | } 51 | } 52 | } 53 | dependencyResolutionManagement { 54 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 55 | repositories { 56 | //sdk仓库 57 | maven { url 'https://jitpack.io' } 58 | } 59 | } 60 | ``` 61 | 62 | **插件依赖** 63 | 64 | 根目录下的build.gradle文件 65 | ``` 66 | plugins { 67 | //插件依赖和版本 68 | id "io.github.peakmain" version "1.1.4" apply false 69 | } 70 | ``` 71 | **sdk版本依赖** 72 | 73 | ``` 74 | implementation 'com.github.Peakmain:AsmActualCombat:1.1.5' 75 | ``` 76 | 77 | ### 功能介绍 78 | #### ASM全埋点功能 79 | - AppStart事件:应用程序启动启动事件。 80 | - AppEnd事件:应用程序退出事件。 81 | - AppViewScreen事件:应用程序页面浏览事件 82 | - AppClick 事件:应用程序控件(View)点击事件,如:ImageView,Button,Dialog等 83 | - 默认包含防止多次点击事件的处理 84 | - 可动态设置方法对点击事件处理之前进行拦截,目前只支持对setOnClickListener进行拦截 85 | ##### 隐私方法调用处理 86 | - 对调用隐私方法的方法体替换成自己的方法(支持动态替换方法) 87 | - 支持的方法如下 88 | ![image](https://user-images.githubusercontent.com/26482737/170660484-740f1399-3a28-4245-9e2b-adc4fb268633.png) 89 | ``` 90 | monitorPlugin { 91 | whiteList = [//设置白名单 92 | "com.peakmain.asmactualcombat.utils.TestUtils", 93 | "com.peakmain.plugin" 94 | ] 95 | methodStatus = 1//1代表方法体替换,其他都是正常情况 96 | enableLog=true//是否开启日志打印,默认不打印 97 | } 98 | 99 | ``` 100 | 101 | #### 辅助功能 102 | - 可获取方法的耗时时间 103 | - 打印方法的参数和返回值 104 | - 打印方法的Frame 105 | - 可动态配置是否开启插件,默认是开启 106 | 107 | ### 关于我 108 | - 我的Github:https://github.com/peakmain 109 | - 我的简书:https://www.jianshu.com/u/3ff32f5aea98 110 | - 我的掘金:https://juejin.cn/user/175532853176152 111 | 112 | ### Donations 113 | 如果您觉得我的开源库帮您节省了大量的开发时间,请扫描下方的二维码随意打赏,您的支持将激励我不断前进 114 | ![微信](https://user-images.githubusercontent.com/26482737/184805287-0561a7e2-da13-4ef4-b367-c5e8672c121d.jpg) 115 | ![支付宝](https://user-images.githubusercontent.com/26482737/184805306-f44511a7-7660-4fe1-9f07-305005576c2c.jpg) 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/activity/TabHostTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.MenuItem; 6 | import android.widget.TabHost; 7 | import android.widget.Toast; 8 | 9 | import androidx.annotation.Nullable; 10 | import androidx.appcompat.app.ActionBar; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | 13 | import com.peakmain.asmactualcombat.R; 14 | 15 | /** 16 | * author :Peakmain 17 | * createTime:2022/3/28 18 | * mail:2726449200@qq.com 19 | * describe: 20 | */ 21 | public class TabHostTestActivity extends AppCompatActivity { 22 | @Override 23 | protected void onCreate(@Nullable Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_tabhost); 26 | 27 | ActionBar actionBar = getSupportActionBar(); 28 | if(actionBar != null){ 29 | actionBar.setHomeButtonEnabled(true); 30 | actionBar.setDisplayHomeAsUpEnabled(true); 31 | } 32 | 33 | initTabHost(); 34 | } 35 | 36 | @SuppressWarnings("Convert2Lambda") 37 | private void initTabHost() { 38 | TabHost tabHost = findViewById(R.id.tabhost); 39 | tabHost.setup(); 40 | 41 | LayoutInflater.from(this).inflate(R.layout.tab1, tabHost.getTabContentView()); 42 | LayoutInflater.from(this).inflate(R.layout.tab2, tabHost.getTabContentView()); 43 | LayoutInflater.from(this).inflate(R.layout.tab3, tabHost.getTabContentView()); 44 | 45 | tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("标签页一").setContent(R.id.tab01)); 46 | tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("标签页二").setContent(R.id.tab02)); 47 | tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator("标签页三").setContent(R.id.tab03)); 48 | 49 | //标签切换事件处理,setOnTabChangedListener 50 | tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() { 51 | @Override 52 | // tabId是newTabSpec第一个参数设置的tab页名,并不是layout里面的标识符id 53 | public void onTabChanged(String tabId) { 54 | if (tabId.equals("tab1")) { //第一个标签 55 | Toast.makeText(TabHostTestActivity.this, "点击标签页一", Toast.LENGTH_SHORT).show(); 56 | } 57 | if (tabId.equals("tab2")) { //第二个标签 58 | Toast.makeText(TabHostTestActivity.this, "点击标签页二", Toast.LENGTH_SHORT).show(); 59 | } 60 | if (tabId.equals("tab3")) { //第三个标签 61 | Toast.makeText(TabHostTestActivity.this, "点击标签页三", Toast.LENGTH_SHORT).show(); 62 | } 63 | } 64 | }); 65 | } 66 | 67 | @Override 68 | public boolean onOptionsItemSelected(MenuItem item) { 69 | switch (item.getItemId()) { 70 | case android.R.id.home: 71 | this.onBackPressed(); 72 | return true; 73 | } 74 | return super.onOptionsItemSelected(item); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/AopUtils.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.ViewParent; 9 | import android.view.Window; 10 | 11 | import com.peakmain.sdk.R; 12 | 13 | /** 14 | * author :Peakmain 15 | * createTime:2022/7/23 16 | * mail:2726449200@qq.com 17 | * describe: 18 | */ 19 | public class AopUtils { 20 | /** 21 | * 获取点击 view 的 fragment 对象 22 | * 23 | * @param view 点击的 view 24 | * @return object 这里是 fragment 实例对象 25 | */ 26 | public static Object getFragmentFromView(View view) { 27 | return getFragmentFromView(view, null); 28 | } 29 | /** 30 | * 获取点击 view 的 fragment 对象 31 | * 32 | * @param view 点击的 view 33 | * @param activity Activity 34 | * @return object 这里是 fragment 实例对象 35 | */ 36 | public static Object getFragmentFromView(View view, Activity activity) { 37 | try { 38 | if (view != null) { 39 | String fragmentName = (String) view.getTag(R.id.sensors_analytics_tag_view_fragment_name); 40 | if (TextUtils.isEmpty(fragmentName)) { 41 | if (activity == null) { 42 | //获取所在的 Context 43 | Context context = view.getContext(); 44 | //将 Context 转成 Activity 45 | activity = SensorsDataUtils.getActivityFromContext(context); 46 | } 47 | if (activity != null) { 48 | Window window = activity.getWindow(); 49 | if (window != null && window.isActive()) { 50 | Object tag = window.getDecorView().getRootView().getTag(R.id.sensors_analytics_tag_view_fragment_name); 51 | if (tag != null) { 52 | fragmentName = traverseParentViewTag(view); 53 | } 54 | } 55 | } 56 | } 57 | return FragmentCacheUtil.getFragmentFromCache(fragmentName); 58 | } 59 | } catch (Exception e) { 60 | LogManager.printStackTrace(e); 61 | } 62 | return null; 63 | } 64 | 65 | private static String traverseParentViewTag(View view) { 66 | try { 67 | ViewParent parentView = view.getParent(); 68 | String fragmentName = null; 69 | while (TextUtils.isEmpty(fragmentName) && parentView instanceof View) { 70 | fragmentName = (String) ((View) parentView).getTag(R.id.sensors_analytics_tag_view_fragment_name); 71 | parentView = parentView.getParent(); 72 | } 73 | return fragmentName; 74 | } catch (Exception ex) { 75 | LogManager.printStackTrace(ex); 76 | } 77 | return ""; 78 | } 79 | 80 | public static boolean isValid(int id) { 81 | return id != -1 && (id & 0xff000000) != 0 && (id & 0x00ff0000) != 0; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/manager/SensorsDatabaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.manager; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | 9 | /** 10 | * author :Peakmain 11 | * createTime:2022/3/31 12 | * mail:2726449200@qq.com 13 | * describe: 14 | */ 15 | public class SensorsDatabaseHelper { 16 | private static final String SensorsDataContentProvider = ".SensorsDataContentProvider/"; 17 | public static final String APP_STARTED = "$app_started"; 18 | public static final String APP_END_STATE = "$app_end_state"; 19 | public static final String APP_PAUSED_TIME = "$app_paused_time"; 20 | private final ContentResolver mContentResolver; 21 | private final Uri mAppStart; 22 | private final Uri mAppEndState; 23 | private final Uri mAppPausedTime; 24 | 25 | public SensorsDatabaseHelper(Context context, String packageName) { 26 | mContentResolver = context.getContentResolver(); 27 | mAppStart = Uri.parse("content://" + packageName + SensorsDataContentProvider + "app_started"); 28 | mAppEndState = Uri.parse("content://" + packageName + SensorsDataContentProvider + "app_end_state"); 29 | mAppPausedTime = Uri.parse("content://" + packageName + SensorsDataContentProvider + "app_paused_time"); 30 | } 31 | 32 | public void saveAppStartState(boolean isAppStart) { 33 | ContentValues contentValues = new ContentValues(); 34 | contentValues.put(APP_STARTED, isAppStart); 35 | mContentResolver.insert(mAppStart, contentValues); 36 | } 37 | 38 | public void saveAppPauseTime(long isPausedTime) { 39 | ContentValues contentValues = new ContentValues(); 40 | contentValues.put(APP_PAUSED_TIME, isPausedTime); 41 | mContentResolver.insert(mAppPausedTime, contentValues); 42 | } 43 | 44 | public long getAppPausedTime() { 45 | long pausedTime = 0; 46 | Cursor cursor = mContentResolver.query(mAppPausedTime, new String[]{APP_PAUSED_TIME}, null, null, null); 47 | if (cursor != null && cursor.getCount() > 0) { 48 | while (cursor.moveToNext()) { 49 | pausedTime = cursor.getLong(0); 50 | } 51 | } 52 | if (cursor != null) 53 | cursor.close(); 54 | return pausedTime; 55 | } 56 | 57 | public void saveAppEndState(boolean isAppEnd) { 58 | ContentValues contentValues = new ContentValues(); 59 | contentValues.put(APP_END_STATE, isAppEnd); 60 | mContentResolver.insert(mAppEndState, contentValues); 61 | } 62 | public boolean getAppEndState() { 63 | boolean state = true; 64 | Cursor cursor = mContentResolver.query(mAppEndState, new String[]{APP_END_STATE}, null, null, null); 65 | if (cursor != null && cursor.getCount() > 0) { 66 | while (cursor.moveToNext()) { 67 | state = cursor.getInt(0) > 0; 68 | } 69 | } 70 | 71 | if (cursor != null) { 72 | cursor.close(); 73 | } 74 | return state; 75 | } 76 | public Uri getAppStartUri() { 77 | return mAppStart; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/ext/MonitorConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.ext 2 | 3 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 4 | import org.apache.http.util.TextUtils 5 | 6 | /** 7 | * author :Peakmain 8 | * createTime:2022/3/29 9 | * mail:2726449200@qq.com 10 | * describe: 11 | */ 12 | 13 | class MonitorConfig { 14 | 15 | /** 16 | * 是否禁用多线程构建 17 | */ 18 | public boolean disableMultiThreadBuild = false 19 | /** 20 | * 是否开启增量更新 21 | */ 22 | public boolean isIncremental = false 23 | public ArrayList whiteList = [] 24 | //是否拦截网络 25 | public boolean isInterceptNetworks = true 26 | /** 27 | * 隐私方法方法的状态 28 | * @params 1 代表替换方法体 29 | * @params 其他都 30 | */ 31 | public int methodStatus = 0 32 | //是否开启日志 33 | public boolean enableLog 34 | private MethodFieldUtils.StatusEnum statusEnum = MethodFieldUtils.StatusEnum.METHOD_STATE_NORMAL 35 | private final HashSet special = [ 36 | 'com.peakmain.sdk.utils.SensorsDataUtils', 37 | 'androidx.core.app.NotificationManagerCompat', 38 | 'android.support.v4.app.NotificationManagerCompat'] 39 | HashSet exceptSet = new HashSet<>() 40 | /** 41 | * 是否禁用开启堆栈分析,默认是禁用 42 | */ 43 | public boolean disableStackMapFrame = true 44 | /** 45 | * 拦截点击的包名前缀 46 | */ 47 | public String interceptPackageName = "" 48 | 49 | void convertConfig() { 50 | for (String value : special) { 51 | value = value.replace(".", "/") 52 | exceptSet.add(value) 53 | } 54 | for (int i = 0; i < whiteList.size(); i++) { 55 | whiteList.set(i, whiteList.get(i).replace(".", "/")) 56 | } 57 | println("当前方法的Status:" + methodStatus) 58 | if (methodStatus == MethodFieldUtils.StatusEnum.METHOD_STATE_REPLACE.value) { 59 | statusEnum = MethodFieldUtils.StatusEnum.METHOD_STATE_REPLACE 60 | } else { 61 | statusEnum = MethodFieldUtils.StatusEnum.METHOD_STATE_NORMAL 62 | } 63 | if (!TextUtils.isEmpty(interceptPackageName)) { 64 | interceptPackageName = interceptPackageName.replace(".", ",") 65 | } 66 | } 67 | 68 | MethodFieldUtils.StatusEnum getStatusEnum() { 69 | return statusEnum 70 | } 71 | 72 | void reset() { 73 | //清空白名单 74 | whiteList.clear() 75 | } 76 | 77 | @Override 78 | String toString() { 79 | return "MonitorPlugin:\n[\n\t是否开启多线程编译:${!disableMultiThreadBuild},\n" + 80 | "\t是否开启增量更新:${!isIncremental},\n\t白名单是:${listToString(whiteList)}\n]" 81 | 82 | } 83 | 84 | static String listToString(ArrayList value) { 85 | Iterator it = value.iterator() 86 | if (!it.hasNext()) 87 | return "[]"; 88 | 89 | StringBuilder sb = new StringBuilder(); 90 | sb.append('\n\t[\n'); 91 | for (; ;) { 92 | String e = it.next() 93 | sb.append("\t\t").append(e) 94 | if (!it.hasNext()) 95 | return sb.append('\n\t]').toString(); 96 | sb.append(',\n').append(' '); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/PeakmainVisitor.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor 2 | 3 | 4 | import com.peakmain.analytics.plugin.entity.PeakmainMethodCell 5 | import com.peakmain.analytics.plugin.ext.MonitorConfig 6 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 7 | import com.peakmain.analytics.plugin.utils.OpcodesUtils 8 | import org.objectweb.asm.ClassVisitor 9 | import org.objectweb.asm.MethodVisitor 10 | import org.objectweb.asm.Type 11 | 12 | /** 13 | * author :Peakmain 14 | * createTime:2021/1/5 15 | * mail:2726449200@qq.com 16 | * describe: 17 | */ 18 | class PeakmainVisitor extends ClassVisitor { 19 | private ClassVisitor classVisitor 20 | private String[] mInterfaces 21 | private HashMap mMethodCells = new HashMap<>() 22 | private String mClassName 23 | private MonitorConfig mMonitorConfig 24 | 25 | PeakmainVisitor(ClassVisitor classVisitor, MonitorConfig config) { 26 | super(OpcodesUtils.ASM_VERSION, classVisitor) 27 | this.classVisitor = classVisitor 28 | this.mMonitorConfig = config 29 | 30 | } 31 | /** 32 | * @param version 类版本 33 | * @param access 修饰符 34 | * @param name 类名 35 | * @param signature 泛型信息 36 | * @param superName 父类 37 | * @param interfaces 实现的接口 38 | */ 39 | @Override 40 | void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 41 | this.mInterfaces = interfaces 42 | this.mClassName = name 43 | super.visit(version, access, name, signature, superName, interfaces) 44 | } 45 | /** 46 | * 扫描类的方法进行调用 47 | * @param access 修饰符 48 | * @param name 方法名字 49 | * @param descriptor 方法签名 50 | * @param signature 泛型信息 51 | * @param exceptions 抛出的异常 52 | * @return 53 | */ 54 | @Override 55 | MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 56 | MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions) 57 | methodVisitor = new MonitorClickAdapter(methodVisitor, access, name, descriptor, mMethodCells, mInterfaces, mMonitorConfig, mClassName) 58 | methodVisitor = new MonitorPrintParametersReturnValueAdapter(methodVisitor, access, name, descriptor, mClassName, classVisitor) 59 | if (mMonitorConfig.getStatusEnum() == MethodFieldUtils.StatusEnum.METHOD_STATE_REPLACE) { 60 | methodVisitor = new MonitorMethodCalledReplaceAdapter(methodVisitor, access, name, descriptor, classVisitor, mClassName, mMonitorConfig) 61 | } 62 | if (mMonitorConfig.isInterceptNetworks) { 63 | methodVisitor = new NetworkMethodCalledReplaceAdapter(methodVisitor, access, name, descriptor, classVisitor,mClassName,mMonitorConfig) 64 | } 65 | if (!mMonitorConfig.disableStackMapFrame) 66 | methodVisitor = new MonitorMethodStackMapFrameAdapter(mClassName, access, name, descriptor, methodVisitor) 67 | return methodVisitor 68 | } 69 | 70 | /** 71 | * 获取方法参数下标为 index 的对应 ASM index 72 | * @param types 方法参数类型数组 73 | * @param index 方法中参数下标,从 0 开始 74 | * @param isStaticMethod 该方法是否为静态方法 75 | * @return 访问该方法的 index 位参数的 ASM index 76 | */ 77 | int getVisitPosition(Type[] types, int index, boolean isStaticMethod) { 78 | if (types == null || index < 0 || index >= types.length) { 79 | throw new Error("getVisitPosition error") 80 | } 81 | if (index == 0) { 82 | return isStaticMethod ? 0 : 1 83 | } else { 84 | return getVisitPosition(types, index - 1, isStaticMethod) + types[index - 1].getSize() 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/SensorsDataInstance.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk; 2 | 3 | import android.app.Application; 4 | import android.text.TextUtils; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import com.peakmain.sdk.constants.SensorsDataConstants; 10 | import com.peakmain.sdk.interfaces.ISensorsDataInstance; 11 | import com.peakmain.sdk.interfaces.OnUploadSensorsDataListener; 12 | import com.peakmain.sdk.utils.SensorsDataUtils; 13 | import com.qiniu.android.utils.Json; 14 | 15 | import org.json.JSONException; 16 | import org.json.JSONObject; 17 | 18 | import java.text.SimpleDateFormat; 19 | import java.util.Map; 20 | 21 | /** 22 | * author :Peakmain 23 | * createTime:2022/7/8 24 | * mail:2726449200@qq.com 25 | * describe: 26 | */ 27 | public class SensorsDataInstance implements ISensorsDataInstance { 28 | 29 | private @SensorsDataConstants.STATE 30 | int mState = SensorsDataConstants.APP_VIEW_CLICK__EVENT_STATE; 31 | 32 | private static Map mDeviceInfo; 33 | 34 | public SensorsDataInstance(Application application) { 35 | mDeviceInfo = SensorsDataUtils.getDeviceInfo(application.getApplicationContext()); 36 | } 37 | 38 | @Override 39 | public void onEvent(String eventName, String eventValue) { 40 | 41 | } 42 | 43 | @Override 44 | public void track(@NonNull String eventName, @Nullable JSONObject properties) { 45 | track(eventName, properties, null); 46 | } 47 | 48 | @Override 49 | public void track(@NonNull String eventName, @Nullable JSONObject properties, OnUploadSensorsDataListener onUploadSensorsDataListener) { 50 | track(eventName, properties, null, onUploadSensorsDataListener); 51 | } 52 | 53 | public void track(@NonNull String eventName, @Nullable JSONObject properties, @Nullable JSONObject customProperties, OnUploadSensorsDataListener onUploadSensorsDataListener) { 54 | try { 55 | JSONObject jsonObject = new JSONObject(); 56 | jsonObject.put("event", eventName); 57 | 58 | JSONObject sendProperties = new JSONObject(mDeviceInfo); 59 | 60 | if (properties != null) { 61 | SensorsDataUtils.mergeJSONObject(properties, sendProperties); 62 | } 63 | if (customProperties != null) { 64 | SensorsDataUtils.mergeJSONObject(customProperties, sendProperties); 65 | } 66 | jsonObject.put("params", sendProperties); 67 | long currentTimeMillis = System.currentTimeMillis(); 68 | jsonObject.put("time", currentTimeMillis); 69 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 70 | jsonObject.put("event_date", simpleDateFormat.format(currentTimeMillis)); 71 | //获取到埋点之后,上传到服务器 72 | if (onUploadSensorsDataListener != null) { 73 | switch (eventName) { 74 | case SensorsDataConstants.APP_START_EVENT_NAME: 75 | mState = SensorsDataConstants.APP_START_EVENT_STATE; 76 | break; 77 | case SensorsDataConstants.APP_END__EVENT_NAME: 78 | mState = SensorsDataConstants.APP_END__EVENT_STATE; 79 | break; 80 | case SensorsDataConstants.APP_VIEW_SCREEN__EVENT_NAME: 81 | mState = SensorsDataConstants.APP_VIEW_SCREEN__EVENT_STATE; 82 | break; 83 | default: 84 | mState = SensorsDataConstants.APP_VIEW_CLICK__EVENT_STATE; 85 | break; 86 | } 87 | onUploadSensorsDataListener.onUploadSensors(mState, SensorsDataUtils.formatJson(jsonObject.toString())); 88 | } 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/MonitorMethodCalledReplaceAdapter.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor 2 | 3 | import com.peakmain.analytics.plugin.entity.MethodCalledBean 4 | import com.peakmain.analytics.plugin.ext.MonitorConfig 5 | import com.peakmain.analytics.plugin.ext.MonitorHookMethodConfig 6 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 7 | import com.peakmain.analytics.plugin.visitor.base.MonitorDefalutMethodAdapter 8 | import org.objectweb.asm.ClassVisitor 9 | import org.objectweb.asm.MethodVisitor 10 | 11 | /** 12 | * author :Peakmain 13 | * createTime:2022/4/2 14 | * mail:2726449200@qq.com 15 | * describe: 16 | */ 17 | class MonitorMethodCalledReplaceAdapter extends MonitorDefalutMethodAdapter { 18 | private int mAccess 19 | private ClassVisitor classVisitor 20 | private String mClassName 21 | private MonitorConfig monitorConfig 22 | /** 23 | * Constructs a new {@link AdviceAdapter}. 24 | * 25 | * @param mv @param access the method's access flags (see {@link Opcodes}). 26 | * @param name the method's name. 27 | * @param desc 28 | */ 29 | MonitorMethodCalledReplaceAdapter(MethodVisitor mv, int access, String name, String desc, ClassVisitor classVisitor, String className, MonitorConfig monitorConfig) { 30 | super(mv, access, name, desc) 31 | mAccess = access 32 | this.classVisitor = classVisitor 33 | mClassName = className 34 | this.monitorConfig = monitorConfig 35 | } 36 | 37 | @Override 38 | void visitMethodInsn(int opcodeAndSource, String owner, String name, String descriptor, boolean isInterface) { 39 | HashMap methodReplaceBeans = MonitorHookMethodConfig.methodCalledBeans 40 | String desc = owner + name + descriptor 41 | String replacefm = MethodFieldUtils.OWNER_REFLEX_IOC_FM + 42 | MethodFieldUtils.NAME_REFLEX_IOC + MethodFieldUtils.DESCRIPTOR_REFLEX_IOC_FM 43 | 44 | String replace = MethodFieldUtils.OWNER_REFLEX_IOC_X + MethodFieldUtils.NAME_REFLEX_IOC + 45 | MethodFieldUtils.DESCRIPTOR_REFLEX_IOC_X 46 | if (mClassName.contains(MethodFieldUtils.CLASS_REFLEX_LOC) && (replace == desc)) { 47 | if (monitorConfig.enableLog) { 48 | println("调用反射方法的class:" + mClassName + "调用反射的owner:" + owner + ",方法的名字:" + name + ",方法的描述符:" + descriptor) 49 | } 50 | super.visitMethodInsn(MethodFieldUtils.STATIC_OPCODE, 51 | MethodFieldUtils.NEW_METHOD_REFLEX_OWNER, 52 | MethodFieldUtils.NAME_REFLEX_IOC, 53 | MethodFieldUtils.DESCRIPTOR_REFLEX_IOC_X, 54 | false) 55 | } else if (mClassName.contains(MethodFieldUtils.CLASS_REFLEX_LOC) && replacefm == desc) { 56 | if (monitorConfig.enableLog) { 57 | println("调用反射方法的class:" + mClassName + "调用反射的owner:" + owner + ",方法的名字:" + name + ",方法的描述符:" + descriptor) 58 | } 59 | super.visitMethodInsn(MethodFieldUtils.STATIC_OPCODE, 60 | MethodFieldUtils.NEW_METHOD_REFLEX_OWNER, 61 | MethodFieldUtils.NAME_REFLEX_IOC, 62 | MethodFieldUtils.DESCRIPTOR_REFLEX_IOC_FM, 63 | false) 64 | } else if (!monitorConfig.whiteList.contains(mClassName) && !monitorConfig.exceptSet.contains(mClassName) && methodReplaceBeans.containsKey(desc)) { 65 | if (monitorConfig.enableLog) { 66 | println("调用方法的class:" + mClassName + ",方法的名字:" + name + ",方法的描述符:" + descriptor) 67 | } 68 | MethodCalledBean bean = methodReplaceBeans.get(desc) 69 | super.visitMethodInsn(bean.newOpcode, bean.newMethodOwner, bean.newMethodName, bean.newMethodDescriptor.get(descriptor), false) 70 | } else { 71 | super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface) 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/MonitorMethodCalledClearAdapter.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor 2 | 3 | import com.peakmain.analytics.plugin.entity.MethodCalledBean 4 | import com.peakmain.analytics.plugin.ext.MonitorConfig 5 | import com.peakmain.analytics.plugin.ext.MonitorHookMethodConfig 6 | import com.peakmain.analytics.plugin.utils.OpcodesUtils 7 | import com.peakmain.analytics.plugin.visitor.base.MonitorDefalutMethodAdapter 8 | import org.objectweb.asm.MethodVisitor 9 | import org.objectweb.asm.Opcodes 10 | import org.objectweb.asm.Type 11 | 12 | /** 13 | * author :Peakmain 14 | * createTime:2022/4/1 15 | * mail:2726449200@qq.com 16 | * describe:方法被调用,然后清空被调用的方法 17 | */ 18 | class MonitorMethodCalledClearAdapter extends MonitorDefalutMethodAdapter { 19 | private String mClassName 20 | 21 | private int mAccess 22 | private MonitorConfig monitorConfig 23 | private String mDesc 24 | /** 25 | * Constructs a new {@link MonitorMethodCalledClearAdapter}. 26 | * 27 | * @param mv 28 | * @param access the method's access flags (see {@link Opcodes}). 29 | * @param name the method's name. 30 | * @param desc 31 | */ 32 | MonitorMethodCalledClearAdapter(MethodVisitor mv, int access, String name, String desc, String className, MonitorConfig monitorConfig) { 33 | super(mv, access, name, desc) 34 | mClassName = className 35 | mAccess = access 36 | mDesc = desc 37 | this.monitorConfig = monitorConfig 38 | } 39 | 40 | @Override 41 | void visitMethodInsn(int opcodeAndSource, String owner, String name, String descriptor, boolean isInterface) { 42 | HashMap methodCalledBeans = MonitorHookMethodConfig.methodCalledBeans 43 | if (!monitorConfig.whiteList.contains(mClassName) && !monitorConfig.exceptSet.contains(mClassName) && methodCalledBeans.containsKey(owner + name + descriptor)) { 44 | println("调用方法的class:" + mClassName + ",方法的名字:" + name + ",方法的描述符:" + descriptor) 45 | clearMethodBody(mv, mClassName, access, name, descriptor, mDesc) 46 | return 47 | } 48 | super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); 49 | } 50 | 51 | 52 | static void clearMethodBody(MethodVisitor mv, String className, int access, String name, String descriptor, String methodDescriptor) { 53 | Type type = Type.getType(descriptor) 54 | Type methodType = Type.getType(methodDescriptor) 55 | Type methodReturnType = methodType.getReturnType() 56 | Type[] argumentsType = type.getArgumentTypes() 57 | Type returnType = type.getReturnType() 58 | int stackSize = returnType.getSize() 59 | int localSize = OpcodesUtils.isStatic(access) ? 0 : 1 60 | for (Type argType : argumentsType) { 61 | localSize += argType.size 62 | } 63 | mv.visitCode() 64 | if (methodReturnType.getSort() == Type.VOID) { 65 | mv.visitInsn(RETURN) 66 | } else if (methodReturnType.getSort() >= Type.BOOLEAN && methodReturnType.getSort() <= Type.INT) { 67 | mv.visitInsn(ICONST_1) 68 | mv.visitInsn(IRETURN) 69 | } else if (returnType.getSort() == Type.LONG) { 70 | mv.visitInsn(LCONST_0) 71 | mv.visitInsn(LRETURN) 72 | } else if (returnType.getSort() == Type.FLOAT) { 73 | mv.visitInsn(FCONST_0) 74 | mv.visitInsn(FRETURN) 75 | } else if (returnType.getSort() == Type.DOUBLE) { 76 | mv.visitInsn(DCONST_0) 77 | mv.visitInsn(DRETURN) 78 | } else if (methodReturnType.getInternalName() == "java/lang/String") { 79 | mv.visitLdcInsn("") 80 | mv.visitInsn(ARETURN) 81 | } else { 82 | mv.visitInsn(ACONST_NULL) 83 | mv.visitInsn(ARETURN) 84 | } 85 | mv.visitMaxs(stackSize, localSize) 86 | mv.visitEnd() 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/MethodFieldUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils 2 | 3 | import org.objectweb.asm.Opcodes 4 | 5 | class MethodFieldUtils { 6 | public static final String PLUGIN_VERSION = "1.1.4" 7 | enum StatusEnum { 8 | METHOD_STATE_NORMAL(0), 9 | METHOD_STATE_REPLACE(1) 10 | private int value 11 | 12 | StatusEnum(int value) { 13 | this.value = value 14 | } 15 | 16 | int getValue() { 17 | return value 18 | } 19 | } 20 | 21 | 22 | public static final String LOG_MANAGER = "com/peakmain/sdk/utils/LogManager" 23 | public static final String NEW_METHOD_OWNER = "com/peakmain/sdk/utils/ReplaceMethodUtils" 24 | public static final int STATIC_OPCODE = Opcodes.INVOKESTATIC 25 | /** 26 | * MonitorHookMethodConfig的属性 27 | */ 28 | //class 29 | static String WIFI_MANAGER_CLASS = "android/net/wifi/WifiManager" 30 | static String WIFI_INFO_CLASS = "android/net/wifi/WifiInfo" 31 | static String TELEPHONY_MANAGER_CLASS = "android/telephony/TelephonyManager" 32 | static String SETTINGS_SECURE_CLASS = 'android/provider/Settings$Secure' 33 | //methodName 34 | static String GET_DEVICE_ID_METHOD_NAME = "getDeviceId" 35 | static String GET_MEID_METHOD_NAME = "getMeid" 36 | static String GET_CONNECTION_INFO_METHOD_NAME = "getConnectionInfo" 37 | static String GET_MAC_ADDRESS_METHOD_NAME = "getMacAddress" 38 | static String GET_IP_ADDRESS_METHOD_NAME = "getIpAddress" 39 | static String GET_STRING_METHOD_NAME = "getString" 40 | static String GET_SCAN_RESULTS_METHOD_NAME = "getScanResults" 41 | static String GET_IMEI_METHOD_NAME = "getImei" 42 | static String GET_SUBSCRIBER_ID_METHOD_NAME = "getSubscriberId" 43 | static String GET_SIM_SERIAL_NUMBER_METHOD_NAME = "getSimSerialNumber" 44 | //desc 45 | static final String EMPTY_STRING_DESC = "()Ljava/lang/String;" 46 | static final String EMPTY_LIST_DESC = "()Ljava/util/List;" 47 | static final String NEW_EMPTY_LIST_DESC = "(Landroid/net/wifi/WifiManager;)Ljava/util/List;" 48 | static final String NEW_STRING_WIFI_INFO_DESC = "(Landroid/net/wifi/WifiInfo;)Ljava/lang/String;" 49 | static final String NEW_EMPTY_STRING_TELEPHONY_DESC = "(Landroid/telephony/TelephonyManager;)Ljava/lang/String;" 50 | static final String INT_STRING_DESC = "(I)Ljava/lang/String;" 51 | static final String NEW_INT_STRING_TELEPHONY_DESC = "(Landroid/telephony/TelephonyManager;I)Ljava/lang/String;" 52 | static String[] EMPTY_INT_RETURN_STRING_DESC = [EMPTY_STRING_DESC, INT_STRING_DESC] 53 | static final String EMPTY_WIFI_INFO_DESC = "()Landroid/net/wifi/WifiInfo;" 54 | static final String NEW_WIFI_INFO_WIFI_INFO_DESC = "(Landroid/net/wifi/WifiManager;)Landroid/net/wifi/WifiInfo;" 55 | static String[] EMPTY_RETURN_WIFI_INFO_DESC = [EMPTY_WIFI_INFO_DESC] 56 | static String[] EMPTY_RETURN_STRING_DESC = [EMPTY_STRING_DESC] 57 | static final String EMPTY_INT_DESC = "()I" 58 | static final String NEW_INT_WIFI_INFO_DESC = "(Landroid/net/wifi/WifiInfo;)I" 59 | static String[] EMPTY_RETURN_INT_DESC = [EMPTY_INT_DESC] 60 | static final String CONTENTRESOLVER_STRING_DESC = "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;" 61 | static String[] CONTENTRESOLVER_STRING_RETURN_STRING_DESC = [CONTENTRESOLVER_STRING_DESC] 62 | static String[] EMPTY_RETURN_LIST = [EMPTY_LIST_DESC] 63 | 64 | //反射 65 | static String CLASS_REFLEX_LOC = "com/loc" 66 | static String OWNER_REFLEX_IOC_FM = "com/loc/fm" 67 | static String NAME_REFLEX_IOC = "a" 68 | static String DESCRIPTOR_REFLEX_IOC_FM = "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;[Ljava/lang/Class;)Ljava/lang/Object;" 69 | 70 | static String OWNER_REFLEX_IOC_X = "com/loc/x" 71 | static String DESCRIPTOR_REFLEX_IOC_X = "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;" 72 | 73 | public static final String NEW_METHOD_REFLEX_OWNER = "com/peakmain/sdk/utils/ReplaceReflexMethodUtils" 74 | //获取时间属性 75 | static String getTimeFieldName(String methodName) { 76 | return "timer_" + methodName 77 | } 78 | } -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/SensorsDataAPI.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | import android.view.View; 6 | 7 | import androidx.annotation.Keep; 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | 11 | import com.peakmain.sdk.constants.SensorsDataConstants; 12 | import com.peakmain.sdk.interfaces.ISensorsDataInstance; 13 | import com.peakmain.sdk.interfaces.OnReplaceMethodListener; 14 | import com.peakmain.sdk.interfaces.OnUploadSensorsDataListener; 15 | import com.peakmain.sdk.manager.SensorsDataManager; 16 | import com.peakmain.sdk.manager.SensorsDatabaseHelper; 17 | import com.peakmain.sdk.utils.PreferencesUtil; 18 | import com.peakmain.sdk.utils.ReplaceMethodUtils; 19 | import com.peakmain.sdk.utils.SensorsDataUtils; 20 | 21 | import org.json.JSONObject; 22 | 23 | import java.text.SimpleDateFormat; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | /** 28 | * author:Peakmain 29 | * createTime:2021/6/15 30 | * mail:2726449200@qq.com 31 | * describe: 32 | */ 33 | @Keep 34 | public class SensorsDataAPI { 35 | private static volatile SensorsDataAPI INSTANCE; 36 | private static final Object mLock = new Object(); 37 | ListenerInfo mListenerInfo; 38 | 39 | 40 | private final ISensorsDataInstance iSensorsDataInstance; 41 | 42 | ListenerInfo getListenerInfo() { 43 | if (mListenerInfo != null) { 44 | return mListenerInfo; 45 | } 46 | mListenerInfo = new ListenerInfo(); 47 | return mListenerInfo; 48 | } 49 | 50 | public interface OnUserAgreementListener { 51 | /** 52 | * 是否同意用户协议接口 53 | */ 54 | boolean onUserAgreement(); 55 | } 56 | 57 | @Keep 58 | public void onEvent(String eventName, String eventValue) { 59 | iSensorsDataInstance.onEvent(eventName, eventValue); 60 | } 61 | 62 | /** 63 | * 设置方法替换接口 64 | * 65 | * @param onReplaceMethodListener onReplaceMethodListener 66 | */ 67 | public void setOnReplaceMethodListener(OnReplaceMethodListener onReplaceMethodListener) { 68 | ReplaceMethodUtils.getInstance().setOnReplaceMethodListener(onReplaceMethodListener); 69 | } 70 | 71 | public void setOnUserAgreementListener(@Nullable OnUserAgreementListener l) { 72 | getListenerInfo().mOnUserAgreement = l; 73 | } 74 | 75 | public void setOnUploadSensorsDataListener(@Nullable OnUploadSensorsDataListener l) { 76 | getListenerInfo().mOnUploadSensorsData = l; 77 | } 78 | 79 | static class ListenerInfo { 80 | OnUserAgreementListener mOnUserAgreement; 81 | OnUploadSensorsDataListener mOnUploadSensorsData; 82 | } 83 | 84 | @Keep 85 | @SuppressWarnings("UnusedReturnValue") 86 | public static SensorsDataAPI init(Application application) { 87 | if (INSTANCE == null) { 88 | synchronized (mLock) { 89 | if (null == INSTANCE) { 90 | INSTANCE = new SensorsDataAPI(application); 91 | } 92 | } 93 | } 94 | return INSTANCE; 95 | } 96 | 97 | @Keep 98 | public static SensorsDataAPI getInstance() { 99 | return INSTANCE; 100 | } 101 | 102 | 103 | public void track(String eventName) { 104 | track(eventName, new JSONObject()); 105 | } 106 | private SensorsDataAPI(Application application) { 107 | iSensorsDataInstance = new SensorsDataInstance(application); 108 | SensorsDataManager.registerActivityLifecycleCallbacks(application); 109 | SensorsDataManager.registerActivityStateObserver(application); 110 | PreferencesUtil.getInstance().init(application); 111 | } 112 | 113 | /** 114 | * Track 事件 115 | * 116 | * @param eventName String 事件名称 117 | * @param properties JSONObject 事件属性 118 | */ 119 | @Keep 120 | public void track(@NonNull final String eventName, @Nullable JSONObject properties) { 121 | iSensorsDataInstance.track(eventName, properties, getListenerInfo().mOnUploadSensorsData); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/base/MonitorMethodPatternAdapter.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor.base 2 | 3 | import com.peakmain.analytics.plugin.utils.OpcodesUtils 4 | import org.objectweb.asm.Handle 5 | import org.objectweb.asm.Label 6 | import org.objectweb.asm.MethodVisitor 7 | import org.objectweb.asm.Opcodes 8 | import org.objectweb.asm.commons.AdviceAdapter 9 | 10 | /** 11 | * author :Peakmain 12 | * createTime:2022/4/1 13 | * mail:2726449200@qq.com 14 | * describe: 15 | */ 16 | abstract class MonitorMethodPatternAdapter extends AdviceAdapter{ 17 | protected final static int METHOD_NOTHING_STATE= 0 18 | protected int state 19 | MonitorMethodPatternAdapter(MethodVisitor mv, int access, String name, String desc) { 20 | super(OpcodesUtils.ASM_VERSION, mv, access, name, desc) 21 | } 22 | @Override 23 | void visitInsn(int opcode) { 24 | visitInsn() 25 | super.visitInsn(opcode) 26 | } 27 | 28 | @Override 29 | void visitIntInsn(int opcode, int operand) { 30 | visitInsn() 31 | super.visitIntInsn(opcode, operand) 32 | } 33 | 34 | @Override 35 | void visitVarInsn(int opcode, int var) { 36 | visitInsn() 37 | super.visitVarInsn(opcode, var) 38 | } 39 | 40 | @Override 41 | void visitTypeInsn(int opcode, String type) { 42 | visitInsn() 43 | super.visitTypeInsn(opcode, type) 44 | } 45 | 46 | @Override 47 | void visitFieldInsn(int opcode, String owner, String name, String descriptor) { 48 | visitInsn() 49 | super.visitFieldInsn(opcode, owner, name, descriptor) 50 | } 51 | 52 | @Override 53 | void visitMethodInsn(int opcode, String owner, String name, String descriptor) { 54 | visitInsn() 55 | super.visitMethodInsn(opcode, owner, name, descriptor) 56 | } 57 | 58 | @Override 59 | void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { 60 | visitInsn() 61 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) 62 | } 63 | 64 | @Override 65 | void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) { 66 | visitInsn() 67 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) 68 | } 69 | 70 | @Override 71 | void visitJumpInsn(int opcode, Label label) { 72 | visitInsn() 73 | super.visitJumpInsn(opcode, label) 74 | } 75 | 76 | @Override 77 | void visitLdcInsn(Object value) { 78 | visitInsn() 79 | super.visitLdcInsn(value) 80 | } 81 | 82 | @Override 83 | void visitIincInsn(int var, int increment) { 84 | visitInsn() 85 | super.visitIincInsn(var, increment) 86 | } 87 | 88 | @Override 89 | void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { 90 | visitInsn() 91 | super.visitTableSwitchInsn(min, max, dflt, labels) 92 | } 93 | 94 | @Override 95 | void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { 96 | visitInsn() 97 | super.visitLookupSwitchInsn(dflt, keys, labels) 98 | } 99 | 100 | @Override 101 | void visitMultiANewArrayInsn(String descriptor, int numDimensions) { 102 | visitInsn() 103 | super.visitMultiANewArrayInsn(descriptor, numDimensions) 104 | } 105 | 106 | @Override 107 | void visitTryCatchBlock(Label start, Label end, Label handler, String type) { 108 | visitInsn() 109 | super.visitTryCatchBlock(start, end, handler, type) 110 | } 111 | 112 | @Override 113 | void visitLabel(Label label) { 114 | visitInsn() 115 | super.visitLabel(label) 116 | } 117 | 118 | @Override 119 | void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) { 120 | visitInsn() 121 | super.visitFrame(type, numLocal, local, numStack, stack) 122 | } 123 | 124 | @Override 125 | void visitMaxs(int maxStack, int maxLocals) { 126 | visitInsn() 127 | super.visitMaxs(maxStack, maxLocals) 128 | } 129 | 130 | protected abstract void visitInsn() 131 | } -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/visitor/base/MonitorDefalutMethodAdapter.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.visitor.base 2 | 3 | import com.peakmain.analytics.plugin.utils.OpcodesUtils 4 | import org.objectweb.asm.* 5 | import org.objectweb.asm.commons.AdviceAdapter 6 | 7 | /** 8 | * author :Peakmain 9 | * createTime:1/19/22 10 | * mail:2726449200@qq.com 11 | * describe: 12 | */ 13 | class MonitorDefalutMethodAdapter extends AdviceAdapter { 14 | 15 | /** 16 | * Constructs a new {@link AdviceAdapter}. 17 | * 18 | * @param api the ASM API version implemented by this visitor. Must be one of {@link 19 | * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}. 20 | * @param methodVisitor the method visitor to which this adapter delegates calls. 21 | * @param access the method's access flags (see {@link Opcodes}). 22 | * @param name the method's name. 23 | * @param descriptor the method's descriptor (see {@link Type Type}). 24 | */ 25 | MonitorDefalutMethodAdapter(MethodVisitor mv, int access, String name, String desc) { 26 | super(OpcodesUtils.ASM_VERSION, mv, access, name, desc) 27 | } 28 | /** 29 | * 表示 ASM 开始扫描这个方法 30 | */ 31 | @Override 32 | void visitCode() { 33 | super.visitCode() 34 | } 35 | 36 | @Override 37 | void visitMethodInsn(int opcode, String owner, String name, String desc) { 38 | super.visitMethodInsn(opcode, owner, name, desc) 39 | } 40 | 41 | @Override 42 | void visitAttribute(Attribute attribute) { 43 | super.visitAttribute(attribute) 44 | } 45 | /** 46 | * 表示方法输出完毕 47 | */ 48 | @Override 49 | void visitEnd() { 50 | super.visitEnd() 51 | } 52 | 53 | @Override 54 | void visitFieldInsn(int opcode, String owner, String name, String desc) { 55 | super.visitFieldInsn(opcode, owner, name, desc) 56 | } 57 | 58 | @Override 59 | void visitIincInsn(int var, int increment) { 60 | super.visitIincInsn(var, increment) 61 | } 62 | 63 | @Override 64 | void visitIntInsn(int i, int i1) { 65 | super.visitIntInsn(i, i1) 66 | } 67 | /** 68 | * 该方法是 visitEnd 之前调用的方法,可以反复调用。用以确定类方法在执行时候的堆栈大小。 69 | * @param maxStack 70 | * @param maxLocals 71 | */ 72 | @Override 73 | void visitMaxs(int maxStack, int maxLocals) { 74 | super.visitMaxs(maxStack, maxLocals) 75 | } 76 | 77 | @Override 78 | void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) { 79 | mv.visitFrame(type, numLocal, local, numStack, stack) 80 | } 81 | 82 | @Override 83 | void visitVarInsn(int opcode, int var) { 84 | super.visitVarInsn(opcode, var) 85 | } 86 | 87 | @Override 88 | void visitJumpInsn(int opcode, Label label) { 89 | super.visitJumpInsn(opcode, label) 90 | } 91 | 92 | @Override 93 | void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) { 94 | super.visitLookupSwitchInsn(label, ints, labels) 95 | } 96 | 97 | @Override 98 | void visitMultiANewArrayInsn(String s, int i) { 99 | super.visitMultiANewArrayInsn(s, i) 100 | } 101 | 102 | @Override 103 | void visitTableSwitchInsn(int i, int i1, Label label, Label[] labels) { 104 | super.visitTableSwitchInsn(i, i1, label, labels) 105 | } 106 | 107 | @Override 108 | void visitTryCatchBlock(Label label, Label label1, Label label2, String s) { 109 | super.visitTryCatchBlock(label, label1, label2, s) 110 | } 111 | 112 | @Override 113 | void visitTypeInsn(int opcode, String s) { 114 | super.visitTypeInsn(opcode, s) 115 | } 116 | 117 | @Override 118 | void visitLocalVariable(String s, String s1, String s2, Label label, Label label1, int i) { 119 | super.visitLocalVariable(s, s1, s2, label, label1, i) 120 | } 121 | 122 | @Override 123 | void visitInsn(int opcode) { 124 | super.visitInsn(opcode) 125 | } 126 | 127 | @Override 128 | AnnotationVisitor visitAnnotation(String s, boolean b) { 129 | return super.visitAnnotation(s, b) 130 | } 131 | 132 | @Override 133 | protected void onMethodEnter() { 134 | super.onMethodEnter() 135 | } 136 | 137 | @Override 138 | protected void onMethodExit(int opcode) { 139 | super.onMethodExit(opcode) 140 | } 141 | } -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/NetworkFieldUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils 2 | 3 | class NetworkFieldUtils { 4 | //七牛云 5 | public static final String OWNER_QI_NIU_HTTP_USER_AGENT = "com/qiniu/android/http/UserAgent" 6 | public static final String NAME_QI_NIU_HTTP_USER_AGENT = "getUa" 7 | public static final String DESCRIPTOR_QI_NIU_HTTP_USER_AGENT = "(Ljava/lang/String;)Ljava/lang/String;" 8 | 9 | //mob 10 | public static final String OWNER_MOB_HTTP = "com/mob/tools/network/NetworkHelper" 11 | public static final String NAME_MOB_GET_HTTP = "httpGet" 12 | public static final String NAME_MOB_RAW_GET_HTTP = "rawGet" 13 | public static final String NAME_MOB_POST_HTTP = "httpPost" 14 | public static final String DESCRIPTOR_MOB_GET_HTTP = 15 | '(Ljava/lang/String;Ljava/util/ArrayList;Ljava/util/ArrayList;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)Ljava/lang/String;' 16 | 17 | public static final String DESCRIPTOR_MOB_RAW_GET_HTTP = 18 | '(Ljava/lang/String;Ljava/util/ArrayList;Lcom/mob/tools/network/RawNetworkCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 19 | public static final String DESCRIPTOR_MOB_POST_HTTP = 20 | '(Ljava/lang/String;Ljava/util/ArrayList;[BLjava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 21 | public static final String DESCRIPTOR_MOB_POST_HTTP1 = 22 | '(Ljava/lang/String;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 23 | public static final String DESCRIPTOR_MOB_POST_HTTP2 = 24 | '(Ljava/lang/String;Ljava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 25 | //glideUrl 26 | public static final String OWNER_GLIDE_URL_HTTP = "com/bumptech/glide/load/model/GlideUrl" 27 | public static final String NAME_GLIDE_URL_HTTP = "getHeaders" 28 | public static final String DESCRIPTOR_GLIDE_URL_HTTP = "()Ljava/util/Map;" 29 | //替换的类和方法 30 | public static final String OWNER_NEW_QI_NIU_HTTP_USER_AGENT = "com/peakmain/sdk/utils/network/UserAgent" 31 | public static final String OWNER_NEW_GLIDE_URL_HTTP = "com/peakmain/sdk/utils/network/NetworkGlide" 32 | public static final String DESCRIPTOR_NEW_QI_NIU_HTTP_USER_AGENT = "(Lcom/qiniu/android/http/UserAgent;Ljava/lang/String;)Ljava/lang/String;" 33 | public static final String OWNER_NEW_MOB_HTTP = "com/peakmain/sdk/utils/network/Mob" 34 | public static final String DESCRIPTOR_NEW_MOB_GET_HTTP = 35 | '(Lcom/mob/tools/network/NetworkHelper;Ljava/lang/String;Ljava/util/ArrayList;Ljava/util/ArrayList;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)Ljava/lang/String;' 36 | 37 | public static final String DESCRIPTOR_NEW_MOB_RAW_GET_HTTP = 38 | '(Lcom/mob/tools/network/NetworkHelper;Ljava/lang/String;Ljava/util/ArrayList;Lcom/mob/tools/network/RawNetworkCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 39 | public static final String DESCRIPTOR_NEW_MOB_POST_HTTP = 40 | '(Lcom/mob/tools/network/NetworkHelper;Ljava/lang/String;Ljava/util/ArrayList;[BLjava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 41 | public static final String DESCRIPTOR_NEW_MOB_POST_HTTP1 = 42 | '(Lcom/mob/tools/network/NetworkHelper;Ljava/lang/String;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 43 | public static final String DESCRIPTOR_NEW_MOB_POST_HTTP2 = 44 | '(Lcom/mob/tools/network/NetworkHelper;Ljava/lang/String;Ljava/util/ArrayList;ILcom/mob/tools/network/HttpResponseCallback;Lcom/mob/tools/network/NetworkHelper$NetworkTimeOut;)V' 45 | 46 | 47 | public static final String DESCRIPTOR_NEW_GLIDE_URL_HTTP = "(Lcom/bumptech/glide/load/model/GlideUrl;)Ljava/util/Map;" 48 | static String[] QI_NIU_METHOD_DESCRIPTOR = [DESCRIPTOR_QI_NIU_HTTP_USER_AGENT] 49 | static String[] MOB_GET_METHOD_DESCRIPTOR = [DESCRIPTOR_MOB_GET_HTTP] 50 | static String[] MOB_RAW_GET_METHOD_DESCRIPTOR = [DESCRIPTOR_MOB_RAW_GET_HTTP] 51 | static String[] GLIDE_METHOD_DESCRIPTOR = [DESCRIPTOR_GLIDE_URL_HTTP] 52 | static String[] MOB_POST_METHOD_DESCRIPTOR = [DESCRIPTOR_MOB_POST_HTTP,DESCRIPTOR_MOB_POST_HTTP1,DESCRIPTOR_MOB_POST_HTTP2] 53 | } -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/utils/log/Logger.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.utils.log 2 | 3 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 4 | 5 | /*** 6 | * .::::. 7 | * .::::::::. 8 | * ::::::::::: 9 | * ..:::::::::::' 10 | * '::::::::::::' 11 | * .:::::::::: 12 | * '::::::::::::::.. 13 | * ..::::::::::::. 14 | * ``:::::::::::::::: 15 | * ::::``:::::::::' .:::. 16 | * ::::' ':::::' .::::::::. 17 | * .::::' :::: .:::::::'::::. 18 | * .:::' ::::: .:::::::::' ':::::. 19 | * .::' :::::.:::::::::' ':::::. 20 | * .::' ::::::::::::::' ``::::. 21 | * ...::: ::::::::::::' ``::. 22 | * ```` ':. ':::::::::' ::::.. 23 | * '.:::::' ':'````.. 24 | */ 25 | class Logger { 26 | private static final String VERSION = MethodFieldUtils.PLUGIN_VERSION 27 | private static boolean debug = false 28 | 29 | static void printPluginStart() { 30 | println() 31 | println("${LogUI.C_BLACK_GREEN.value}" + "####################################################################" + "${LogUI.E_NORMAL.value}") 32 | println("${LogUI.C_BLACK_GREEN.value}" + "######## ########" + "${LogUI.E_NORMAL.value}") 33 | println("${LogUI.C_BLACK_GREEN.value}" + "######## ########" + "${LogUI.E_NORMAL.value}") 34 | println("${LogUI.C_BLACK_GREEN.value}" + "######## 欢迎使用PeakmainPlugin埋点编译插件 v" + VERSION + "${LogUI.E_NORMAL.value}") 35 | println("${LogUI.C_BLACK_GREEN.value}" + "######## ########" + "${LogUI.E_NORMAL.value}") 36 | println("${LogUI.C_BLACK_GREEN.value}" + "######## ########" + "${LogUI.E_NORMAL.value}") 37 | println("${LogUI.C_BLACK_GREEN.value}" + "####################################################################" + "${LogUI.E_NORMAL.value}") 38 | println() 39 | } 40 | /** 41 | * 设置是否打印日志 42 | */ 43 | static void setDebug(boolean isDebug) { 44 | debug = isDebug 45 | } 46 | /** 47 | * 打印日志 48 | */ 49 | def static info(Object msg) { 50 | if (debug) 51 | try { 52 | println "[PeakmainPlugin]: ${msg}" 53 | } catch (Exception e) { 54 | e.printStackTrace() 55 | } 56 | } 57 | 58 | def static error(Object msg) { 59 | if (!debug) 60 | return 61 | try { 62 | println("${LogUI.C_ERROR.value}[PeakmainPlugin]: ${msg}${LogUI.E_NORMAL.value}") 63 | } catch (Exception e) { 64 | e.printStackTrace() 65 | } 66 | } 67 | 68 | def static warn(Object msg) { 69 | if (!debug) 70 | return 71 | try { 72 | println("${LogUI.C_WARN.value}[PeakmainPlugin]: ${msg}${LogUI.E_NORMAL.value}") 73 | } catch (Exception e) { 74 | e.printStackTrace() 75 | } 76 | } 77 | 78 | def static logForEach(Object... msg) { 79 | if (!debug) { 80 | return 81 | } 82 | msg.each { 83 | Object m -> 84 | try { 85 | if (m != null) { 86 | if (m.class.isArray()) { 87 | print "[" 88 | def length = Array.getLength(m); 89 | if (length > 0) { 90 | for (int i = 0; i < length; i++) { 91 | def get = Array.get(m, i); 92 | if (get != null) { 93 | print "${get}\t" 94 | } else { 95 | print "null\t" 96 | } 97 | } 98 | } 99 | print "]\t" 100 | } else { 101 | print "${m}\t" 102 | } 103 | } else { 104 | print "null\t" 105 | } 106 | } catch (Exception e) { 107 | e.printStackTrace() 108 | } 109 | } 110 | println "" 111 | } 112 | 113 | 114 | } -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/ext/NetworkHookMethodConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.ext 2 | 3 | 4 | import com.peakmain.analytics.plugin.entity.MethodCalledBean 5 | import com.peakmain.analytics.plugin.utils.MethodFieldUtils 6 | import com.peakmain.analytics.plugin.utils.NetworkFieldUtils 7 | 8 | class NetworkHookMethodConfig { 9 | public final static HashMap methodCalledBeans = new HashMap<>() 10 | static { 11 | /** 12 | * 七牛云 13 | */ 14 | HashMap qiNiuMap = new HashMap<>() 15 | qiNiuMap.put(NetworkFieldUtils.DESCRIPTOR_QI_NIU_HTTP_USER_AGENT, NetworkFieldUtils.DESCRIPTOR_NEW_QI_NIU_HTTP_USER_AGENT) 16 | MethodCalledBean qiNiuBean = new MethodCalledBean( 17 | NetworkFieldUtils.OWNER_QI_NIU_HTTP_USER_AGENT, 18 | NetworkFieldUtils.NAME_QI_NIU_HTTP_USER_AGENT, 19 | NetworkFieldUtils.QI_NIU_METHOD_DESCRIPTOR, 20 | NetworkFieldUtils.OWNER_NEW_QI_NIU_HTTP_USER_AGENT, 21 | NetworkFieldUtils.NAME_QI_NIU_HTTP_USER_AGENT, 22 | MethodFieldUtils.STATIC_OPCODE, 23 | qiNiuMap) 24 | addMethodCalledBean(qiNiuBean) 25 | /** 26 | * Mob GET 27 | */ 28 | HashMap mobGetMap = new HashMap<>() 29 | mobGetMap.put(NetworkFieldUtils.DESCRIPTOR_MOB_GET_HTTP, NetworkFieldUtils.DESCRIPTOR_NEW_MOB_GET_HTTP) 30 | MethodCalledBean mobGetMethodBean = new MethodCalledBean( 31 | NetworkFieldUtils.OWNER_MOB_HTTP, 32 | NetworkFieldUtils.NAME_MOB_GET_HTTP, 33 | NetworkFieldUtils.MOB_GET_METHOD_DESCRIPTOR, 34 | NetworkFieldUtils.OWNER_NEW_MOB_HTTP, 35 | NetworkFieldUtils.NAME_MOB_GET_HTTP, 36 | MethodFieldUtils.STATIC_OPCODE, 37 | mobGetMap) 38 | addMethodCalledBean(mobGetMethodBean) 39 | /** 40 | * Mob RawGet 41 | */ 42 | HashMap mobRawGetMap = new HashMap<>() 43 | mobRawGetMap.put(NetworkFieldUtils.DESCRIPTOR_MOB_RAW_GET_HTTP, NetworkFieldUtils.DESCRIPTOR_NEW_MOB_RAW_GET_HTTP) 44 | MethodCalledBean mobRawGetMethodBean = new MethodCalledBean( 45 | NetworkFieldUtils.OWNER_MOB_HTTP, 46 | NetworkFieldUtils.NAME_MOB_RAW_GET_HTTP, 47 | NetworkFieldUtils.MOB_RAW_GET_METHOD_DESCRIPTOR, 48 | NetworkFieldUtils.OWNER_NEW_MOB_HTTP, 49 | NetworkFieldUtils.NAME_MOB_RAW_GET_HTTP, 50 | MethodFieldUtils.STATIC_OPCODE, 51 | mobRawGetMap 52 | ) 53 | addMethodCalledBean(mobRawGetMethodBean) 54 | /** 55 | * Mob Post 56 | */ 57 | HashMap mobPostMap = new HashMap<>() 58 | mobPostMap.put(NetworkFieldUtils.DESCRIPTOR_MOB_POST_HTTP,NetworkFieldUtils.DESCRIPTOR_NEW_MOB_POST_HTTP) 59 | mobPostMap.put(NetworkFieldUtils.DESCRIPTOR_MOB_POST_HTTP1,NetworkFieldUtils.DESCRIPTOR_NEW_MOB_POST_HTTP1) 60 | mobPostMap.put(NetworkFieldUtils.DESCRIPTOR_MOB_POST_HTTP2,NetworkFieldUtils.DESCRIPTOR_NEW_MOB_POST_HTTP2) 61 | MethodCalledBean mobPostMethodBean=new MethodCalledBean( 62 | NetworkFieldUtils.OWNER_MOB_HTTP, 63 | NetworkFieldUtils.NAME_MOB_POST_HTTP, 64 | NetworkFieldUtils.MOB_POST_METHOD_DESCRIPTOR, 65 | NetworkFieldUtils.OWNER_NEW_MOB_HTTP, 66 | NetworkFieldUtils.NAME_MOB_POST_HTTP, 67 | MethodFieldUtils.STATIC_OPCODE, 68 | mobPostMap 69 | ) 70 | addMethodCalledBean(mobPostMethodBean) 71 | 72 | 73 | /** 74 | * GlideUrl getHead 75 | */ 76 | /* HashMap glideUrlMap = new HashMap<>() 77 | glideUrlMap.put(NetworkFieldUtils.DESCRIPTOR_GLIDE_URL_HTTP, NetworkFieldUtils.DESCRIPTOR_NEW_GLIDE_URL_HTTP) 78 | MethodCalledBean glideMethodBean = new MethodCalledBean( 79 | NetworkFieldUtils.OWNER_GLIDE_URL_HTTP, 80 | NetworkFieldUtils.NAME_GLIDE_URL_HTTP, 81 | NetworkFieldUtils.GLIDE_METHOD_DESCRIPTOR, 82 | NetworkFieldUtils.OWNER_NEW_GLIDE_URL_HTTP, 83 | NetworkFieldUtils.NAME_GLIDE_URL_HTTP, 84 | MethodFieldUtils.STATIC_OPCODE, 85 | glideUrlMap 86 | ) 87 | addMethodCalledBean(glideMethodBean)*/ 88 | 89 | 90 | } 91 | 92 | static void addMethodCalledBean(MethodCalledBean methodCalledBean) { 93 | for (String desc : methodCalledBean.getMethodDescriptor()) { 94 | methodCalledBeans.put(methodCalledBean.getMethodOwner() + methodCalledBean.getMethodName() + desc, methodCalledBean) 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /app/src/main/java/com/peakmain/asmactualcombat/App.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.asmactualcombat; 2 | 3 | import android.app.Application; 4 | import android.content.ContentResolver; 5 | import android.content.Context; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.net.wifi.ScanResult; 9 | import android.net.wifi.WifiInfo; 10 | import android.net.wifi.WifiManager; 11 | import android.telephony.SubscriptionInfo; 12 | import android.telephony.TelephonyManager; 13 | import android.util.Log; 14 | 15 | import androidx.multidex.MultiDex; 16 | 17 | import com.peakmain.sdk.BuildConfig; 18 | import com.peakmain.sdk.SensorsDataAPI; 19 | import com.peakmain.sdk.constants.SensorsDataConstants; 20 | import com.peakmain.sdk.interfaces.OnReplaceMethodListener; 21 | import com.peakmain.sdk.interfaces.OnUploadSensorsDataListener; 22 | import com.peakmain.sdk.utils.SensorsDataUtils; 23 | import com.peakmain.ui.utils.LogUtils; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import cn.jpush.android.api.JPushInterface; 29 | 30 | /** 31 | * author :Peakmain 32 | * createTime:2021/6/15 33 | * describe: 34 | */ 35 | public class App extends Application { 36 | @Override 37 | protected void attachBaseContext(Context base) { 38 | super.attachBaseContext(base); 39 | MultiDex.install(this); 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | JPushInterface.setDebugMode(true); 46 | JPushInterface.init(this); 47 | SensorsDataAPI.init(this); 48 | SensorsDataAPI.getInstance().setOnUserAgreementListener(() -> true); 49 | SensorsDataAPI.getInstance().setOnUploadSensorsDataListener((state, data) -> { 50 | switch (state) { 51 | case SensorsDataConstants.APP_START_EVENT_STATE: 52 | case SensorsDataConstants.APP_END__EVENT_STATE: 53 | case SensorsDataConstants.APP_VIEW_SCREEN__EVENT_STATE: 54 | if (BuildConfig.DEBUG) { 55 | Log.e("TAG", "埋点\n" + data); 56 | } 57 | break; 58 | default: 59 | if (BuildConfig.DEBUG) { 60 | Log.e("TAG", data); 61 | } 62 | break; 63 | } 64 | }); 65 | SensorsDataAPI.getInstance().setOnReplaceMethodListener(new OnReplaceMethodListener() { 66 | @Override 67 | public String onReplaceMethodListener(int telephoneState, TelephonyManager manager, int slotIndex) { 68 | switch (telephoneState) { 69 | case SensorsDataConstants.GET_DEVICE_ID: 70 | LogUtils.e("替换GET_DEVICE_ID"); 71 | break; 72 | case SensorsDataConstants.GET_MEID: 73 | LogUtils.e("替换GET_MEID"); 74 | break; 75 | case SensorsDataConstants.GET_IMEI: 76 | LogUtils.e("替换GET_IMEI"); 77 | break; 78 | case SensorsDataConstants.GET_SUBSCRIBER_ID: 79 | LogUtils.e("替换GET_SUBSCRIBER_ID"); 80 | break; 81 | case SensorsDataConstants.GET_SIM_SERIAL_NUMBER: 82 | LogUtils.e("替换GET_SIM_SERIAL_NUMBER"); 83 | break; 84 | default: 85 | break; 86 | } 87 | return ""; 88 | } 89 | 90 | @Override 91 | public WifiInfo onReplaceMethodListener(WifiManager wifiManager) { 92 | LogUtils.e("替换WifiManager"); 93 | return null; 94 | } 95 | 96 | @Override 97 | public List onReplaceWifiManagerMethodListener(WifiManager wifiManager) { 98 | LogUtils.e("替换onReplaceWifiManagerMethodListener"); 99 | return null; 100 | } 101 | 102 | @Override 103 | public String onReplaceMethodListener(SubscriptionInfo subscriptionInfo) { 104 | LogUtils.e("替换SubscriptionInfo"); 105 | return ""; 106 | } 107 | 108 | @Override 109 | public List onReplaceMethodListener(PackageManager manager) { 110 | LogUtils.e("替换PackageManager"); 111 | return new ArrayList<>(); 112 | } 113 | 114 | @Override 115 | public String onReplaceMethodListener(ContentResolver resolver, String name) { 116 | LogUtils.e("替换ContentResolver"); 117 | return "onReplaceMethodListener"; 118 | } 119 | }); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/SensorsDataContentProvider.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentResolver; 5 | import android.content.ContentValues; 6 | import android.content.Context; 7 | import android.content.SharedPreferences; 8 | import android.content.UriMatcher; 9 | import android.database.Cursor; 10 | import android.database.MatrixCursor; 11 | import android.net.Uri; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | 16 | import com.peakmain.sdk.manager.SensorsDatabaseHelper; 17 | 18 | /** 19 | * author :Peakmain 20 | * createTime:2022/3/31 21 | * mail:2726449200@qq.com 22 | * describe: 23 | */ 24 | public class SensorsDataContentProvider extends ContentProvider { 25 | private final static int APP_START = 1; 26 | private final static int APP_END_STATE = 2; 27 | private final static int APP_PAUSED_TIME = 3; 28 | 29 | private static SharedPreferences sharedPreferences; 30 | private static SharedPreferences.Editor mEditor; 31 | private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 32 | private ContentResolver mContentResolver; 33 | 34 | @Override 35 | public boolean onCreate() { 36 | if (getContext() != null) { 37 | String packageName = getContext().getPackageName(); 38 | uriMatcher.addURI(packageName + ".SensorsDataContentProvider", "app_started", APP_START); 39 | uriMatcher.addURI(packageName + ".SensorsDataContentProvider", "app_end_state", APP_END_STATE); 40 | uriMatcher.addURI(packageName + ".SensorsDataContentProvider", "app_paused_time", APP_PAUSED_TIME); 41 | sharedPreferences = getContext().getSharedPreferences("com.peakmain.sdk.SensorsDataAPI", Context.MODE_PRIVATE); 42 | mEditor = sharedPreferences.edit(); 43 | mEditor.apply(); 44 | mContentResolver = getContext().getContentResolver(); 45 | } 46 | return false; 47 | } 48 | 49 | @Nullable 50 | @Override 51 | public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { 52 | int code = uriMatcher.match(uri); 53 | MatrixCursor matrixCursor = null; 54 | switch (code) { 55 | case APP_START: 56 | int appStart = sharedPreferences.getBoolean(SensorsDatabaseHelper.APP_STARTED, true) ? 1 : 0; 57 | matrixCursor = new MatrixCursor(new String[]{SensorsDatabaseHelper.APP_STARTED}); 58 | matrixCursor.addRow(new Object[]{appStart}); 59 | break; 60 | case APP_END_STATE: 61 | int appEnd = sharedPreferences.getBoolean(SensorsDatabaseHelper.APP_END_STATE, true) ? 1 : 0; 62 | matrixCursor = new MatrixCursor(new String[]{SensorsDatabaseHelper.APP_END_STATE}); 63 | matrixCursor.addRow(new Object[]{appEnd}); 64 | break; 65 | case APP_PAUSED_TIME: 66 | long pausedTime = sharedPreferences.getLong(SensorsDatabaseHelper.APP_PAUSED_TIME, 0); 67 | matrixCursor = new MatrixCursor(new String[]{SensorsDatabaseHelper.APP_PAUSED_TIME}); 68 | matrixCursor.addRow(new Object[]{pausedTime}); 69 | break; 70 | default: 71 | break; 72 | } 73 | return matrixCursor; 74 | } 75 | 76 | @Nullable 77 | @Override 78 | public String getType(@NonNull Uri uri) { 79 | return null; 80 | } 81 | 82 | @Nullable 83 | @Override 84 | public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { 85 | if (values == null) { 86 | return uri; 87 | } 88 | int code = uriMatcher.match(uri); 89 | switch (code) { 90 | case APP_START: 91 | boolean appStart = values.getAsBoolean(SensorsDatabaseHelper.APP_STARTED); 92 | mEditor.putBoolean(SensorsDatabaseHelper.APP_STARTED, appStart); 93 | mContentResolver.notifyChange(uri, null); 94 | break; 95 | case APP_END_STATE: 96 | boolean appEnd = values.getAsBoolean(SensorsDatabaseHelper.APP_END_STATE); 97 | mEditor.putBoolean(SensorsDatabaseHelper.APP_END_STATE, appEnd); 98 | break; 99 | case APP_PAUSED_TIME: 100 | long pausedTime = values.getAsLong(SensorsDatabaseHelper.APP_PAUSED_TIME); 101 | mEditor.putLong(SensorsDatabaseHelper.APP_PAUSED_TIME, pausedTime); 102 | break; 103 | default: 104 | break; 105 | } 106 | mEditor.commit(); 107 | return null; 108 | } 109 | 110 | @Override 111 | public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { 112 | return 0; 113 | } 114 | 115 | @Override 116 | public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { 117 | return 0; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /plugin/src/main/groovy/com/peakmain/analytics/plugin/ext/PeakmainHookConfig.groovy: -------------------------------------------------------------------------------- 1 | package com.peakmain.analytics.plugin.ext 2 | 3 | import com.peakmain.analytics.plugin.entity.PeakmainMethodCell 4 | import org.objectweb.asm.Opcodes 5 | 6 | class PeakmainHookConfig { 7 | /** 8 | * android.gradle 3.2.1 版本中,针对 Lambda 表达式处理 9 | */ 10 | public final static HashMap LAMBDA_METHODS = new HashMap<>() 11 | static { 12 | PeakmainMethodCell onClick = new PeakmainMethodCell( 13 | 'onClick', 14 | '(Landroid/view/View;)V', 15 | 'Landroid/view/View$OnClickListener;', 16 | 'trackViewOnClickLambda', 17 | '(Landroid/view/View;)V', 18 | 1, 1, 19 | [Opcodes.ALOAD]) 20 | LAMBDA_METHODS.put(onClick.parent + onClick.name + onClick.desc, onClick) 21 | PeakmainMethodCell onCheckedChanged = new PeakmainMethodCell( 22 | 'onCheckedChanged', 23 | '(Landroid/widget/CompoundButton;Z)V', 24 | 'Landroid/widget/CompoundButton$OnCheckedChangeListener;', 25 | 'trackViewOnClickLambda', 26 | '(Landroid/view/View;)V', 27 | 1, 1, 28 | [Opcodes.ALOAD]) 29 | LAMBDA_METHODS.put(onCheckedChanged.parent + onCheckedChanged.name + onCheckedChanged.desc, onCheckedChanged) 30 | 31 | PeakmainMethodCell onRatingChanged = new PeakmainMethodCell( 32 | 'onRatingChanged', 33 | '(Landroid/widget/RatingBar;FZ)V', 34 | 'Landroid/widget/RatingBar$OnRatingBarChangeListener;', 35 | 'trackViewOnClickLambda', 36 | '(Landroid/view/View;)V', 37 | 1, 1, 38 | [Opcodes.ALOAD]) 39 | LAMBDA_METHODS.put(onRatingChanged.parent + onRatingChanged.name + onRatingChanged.desc, onRatingChanged) 40 | 41 | 42 | PeakmainMethodCell onStopTrackingTouch = new PeakmainMethodCell( 43 | 'onStopTrackingTouch', 44 | '(Landroid/widget/SeekBar;)V', 45 | 'Landroid/widget/SeekBar$OnSeekBarChangeListener;', 46 | 'trackViewOnClickLambda', 47 | '(Landroid/view/View;)V', 48 | 1, 1, 49 | [Opcodes.ALOAD]) 50 | LAMBDA_METHODS.put(onStopTrackingTouch.parent + onStopTrackingTouch.name + onStopTrackingTouch.desc, onStopTrackingTouch) 51 | 52 | PeakmainMethodCell onClick1 = new PeakmainMethodCell( 53 | 'onClick', 54 | '(Landroid/content/DialogInterface;I)V', 55 | 'Landroid/content/DialogInterface$OnClickListener;', 56 | 'trackViewOnClick', 57 | '(Landroid/content/DialogInterface;I)V', 58 | 1, 2, 59 | [Opcodes.ALOAD, Opcodes.ILOAD]) 60 | LAMBDA_METHODS.put(onClick1.parent + onClick1.name + onClick1.desc, onClick1) 61 | 62 | PeakmainMethodCell onItemClick = new PeakmainMethodCell( 63 | 'onItemClick', 64 | '(Landroid/widget/AdapterView;Landroid/view/View;IJ)V', 65 | 'Landroid/widget/AdapterView$OnItemClickListener;', 66 | 'trackViewOnClick', 67 | '(Landroid/widget/AdapterView;Landroid/view/View;I)V', 68 | 1, 3, 69 | [Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ILOAD]) 70 | LAMBDA_METHODS.put(onItemClick.parent + onItemClick.name + onItemClick.desc, onItemClick) 71 | 72 | PeakmainMethodCell onGroupClick = new PeakmainMethodCell( 73 | 'onGroupClick', 74 | '(Landroid/widget/ExpandableListView;Landroid/view/View;IJ)Z', 75 | 'Landroid/widget/ExpandableListView$OnGroupClickListener;', 76 | 'trackExpandableListViewGroupOnClick', 77 | '(Landroid/widget/ExpandableListView;Landroid/view/View;I)V', 78 | 1, 3, 79 | [Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ILOAD]) 80 | LAMBDA_METHODS.put(onGroupClick.parent + onGroupClick.name + onGroupClick.desc, onGroupClick) 81 | 82 | PeakmainMethodCell onChildClick = new PeakmainMethodCell( 83 | 'onChildClick', 84 | '(Landroid/widget/ExpandableListView;Landroid/view/View;IIJ)Z', 85 | 'Landroid/widget/ExpandableListView$OnChildClickListener;', 86 | 'trackExpandableListViewChildOnClick', 87 | '(Landroid/widget/ExpandableListView;Landroid/view/View;II)V', 88 | 1, 4, 89 | [Opcodes.ALOAD, Opcodes.ALOAD, Opcodes.ILOAD, Opcodes.ILOAD]) 90 | LAMBDA_METHODS.put(onChildClick.parent + onChildClick.name + onChildClick.desc, onChildClick) 91 | 92 | PeakmainMethodCell onTabChanged = new PeakmainMethodCell( 93 | 'onTabChanged', 94 | '(Ljava/lang/String;)V', 95 | 'Landroid/widget/TabHost$OnTabChangeListener;', 96 | 'trackTabHost', 97 | '(Ljava/lang/String;)V', 98 | 1, 1, 99 | [Opcodes.ALOAD]) 100 | LAMBDA_METHODS.put(onTabChanged.parent + onTabChanged.name + onTabChanged.desc, onTabChanged) 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/bean/SensorsEventBean.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.bean; 2 | 3 | /** 4 | * author :Peakmain 5 | * createTime:2022/7/24 6 | * mail:2726449200@qq.com 7 | * describe: 8 | */ 9 | 10 | public class SensorsEventBean { 11 | 12 | private String event; 13 | private ParamsBean params; 14 | private Long time; 15 | private String event_date; 16 | 17 | public static class ParamsBean { 18 | private String sdk_lib; 19 | private Integer screen_width; 20 | private Integer screen_height; 21 | private String app_version; 22 | private String os; 23 | private String os_version; 24 | private String language; 25 | private String model; 26 | private String lib_version; 27 | private String brand; 28 | private String platform; 29 | private String element_path; 30 | private String page_path; 31 | private String page_title; 32 | private String title; 33 | private String element_type; 34 | private String element_id; 35 | private String element_content; 36 | 37 | public String getSdk_lib() { 38 | return sdk_lib; 39 | } 40 | 41 | public void setSdk_lib(String sdk_lib) { 42 | this.sdk_lib = sdk_lib; 43 | } 44 | 45 | public Integer getScreen_width() { 46 | return screen_width; 47 | } 48 | 49 | public void setScreen_width(Integer screen_width) { 50 | this.screen_width = screen_width; 51 | } 52 | 53 | public Integer getScreen_height() { 54 | return screen_height; 55 | } 56 | 57 | public void setScreen_height(Integer screen_height) { 58 | this.screen_height = screen_height; 59 | } 60 | 61 | public String getApp_version() { 62 | return app_version; 63 | } 64 | 65 | public void setApp_version(String app_version) { 66 | this.app_version = app_version; 67 | } 68 | 69 | public String getOs() { 70 | return os; 71 | } 72 | 73 | public void setOs(String os) { 74 | this.os = os; 75 | } 76 | 77 | public String getOs_version() { 78 | return os_version; 79 | } 80 | 81 | public void setOs_version(String os_version) { 82 | this.os_version = os_version; 83 | } 84 | 85 | public String getLanguage() { 86 | return language; 87 | } 88 | 89 | public void setLanguage(String language) { 90 | this.language = language; 91 | } 92 | 93 | public String getModel() { 94 | return model; 95 | } 96 | 97 | public void setModel(String model) { 98 | this.model = model; 99 | } 100 | 101 | public String getLib_version() { 102 | return lib_version; 103 | } 104 | 105 | public void setLib_version(String lib_version) { 106 | this.lib_version = lib_version; 107 | } 108 | 109 | public String getBrand() { 110 | return brand; 111 | } 112 | 113 | public void setBrand(String brand) { 114 | this.brand = brand; 115 | } 116 | 117 | public String getPlatform() { 118 | return platform; 119 | } 120 | 121 | public void setPlatform(String platform) { 122 | this.platform = platform; 123 | } 124 | 125 | public String getElement_path() { 126 | return element_path; 127 | } 128 | 129 | public void setElement_path(String element_path) { 130 | this.element_path = element_path; 131 | } 132 | 133 | public String getPage_path() { 134 | return page_path; 135 | } 136 | 137 | public void setPage_path(String page_path) { 138 | this.page_path = page_path; 139 | } 140 | 141 | public String getPage_title() { 142 | return page_title; 143 | } 144 | 145 | public void setPage_title(String page_title) { 146 | this.page_title = page_title; 147 | } 148 | 149 | public String getTitle() { 150 | return title; 151 | } 152 | 153 | public void setTitle(String title) { 154 | this.title = title; 155 | } 156 | 157 | public String getElement_type() { 158 | return element_type; 159 | } 160 | 161 | public void setElement_type(String element_type) { 162 | this.element_type = element_type; 163 | } 164 | 165 | public String getElement_id() { 166 | return element_id; 167 | } 168 | 169 | public void setElement_id(String element_id) { 170 | this.element_id = element_id; 171 | } 172 | 173 | public String getElement_content() { 174 | return element_content; 175 | } 176 | 177 | public void setElement_content(String element_content) { 178 | this.element_content = element_content; 179 | } 180 | } 181 | 182 | public String getEvent() { 183 | return event; 184 | } 185 | 186 | public void setEvent(String event) { 187 | this.event = event; 188 | } 189 | 190 | public ParamsBean getParams() { 191 | return params; 192 | } 193 | 194 | public void setParams(ParamsBean params) { 195 | this.params = params; 196 | } 197 | 198 | public Long getTime() { 199 | return time; 200 | } 201 | 202 | public void setTime(Long time) { 203 | this.time = time; 204 | } 205 | 206 | public String getEvent_date() { 207 | return event_date; 208 | } 209 | 210 | public void setEvent_date(String event_date) { 211 | this.event_date = event_date; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/Base64Coder.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | 5 | /** 6 | * author :Peakmain 7 | * createTime:2022/7/8 8 | * mail:2726449200@qq.com 9 | * describe: 10 | */ 11 | public class Base64Coder { 12 | 13 | /* 指定默认编码 */ 14 | public static final String CHARSET_UTF8 = "UTF-8"; 15 | 16 | // Mapping table from 6-bit nibbles to Base64 characters. 17 | private static final char[] map1 = new char[64]; 18 | // Mapping table from Base64 characters to 6-bit nibbles. 19 | private static final byte[] map2 = new byte[128]; 20 | 21 | static { 22 | int i = 0; 23 | for (char c = 'A'; c <= 'Z'; c++) 24 | map1[i++] = c; 25 | for (char c = 'a'; c <= 'z'; c++) 26 | map1[i++] = c; 27 | for (char c = '0'; c <= '9'; c++) 28 | map1[i++] = c; 29 | map1[i++] = '+'; 30 | map1[i] = '/'; 31 | } 32 | 33 | static { 34 | for (int i = 0; i < map2.length; i++) 35 | map2[i] = -1; 36 | for (int i = 0; i < 64; i++) 37 | map2[map1[i]] = (byte) i; 38 | } 39 | 40 | /** 41 | * Encodes a string into Base64 format. 42 | * No blanks or line breaks are inserted. 43 | * 44 | * @param s a String to be encoded. 45 | * @return A String with the Base64 encoded data. 46 | */ 47 | public static String encodeString(String s) { 48 | return new String(encode(s.getBytes(StandardCharsets.UTF_8))); 49 | } 50 | 51 | /** 52 | * Encodes a byte array into Base64 format. 53 | * No blanks or line breaks are inserted. 54 | * 55 | * @param in an array containing the data bytes to be encoded. 56 | * @return A character array with the Base64 encoded data. 57 | */ 58 | public static char[] encode(byte[] in) { 59 | return encode(in, in.length); 60 | } 61 | 62 | /** 63 | * Encodes a byte array into Base64 format. 64 | * No blanks or line breaks are inserted. 65 | * 66 | * @param in an array containing the data bytes to be encoded. 67 | * @param iLen number of bytes to process in in. 68 | * @return A character array with the Base64 encoded data. 69 | */ 70 | public static char[] encode(byte[] in, int iLen) { 71 | int oDataLen = (iLen * 4 + 2) / 3; // output length without padding 72 | int oLen = ((iLen + 2) / 3) * 4; // output length including padding 73 | char[] out = new char[oLen]; 74 | int ip = 0; 75 | int op = 0; 76 | while (ip < iLen) { 77 | int i0 = in[ip++] & 0xff; 78 | int i1 = ip < iLen ? in[ip++] & 0xff : 0; 79 | int i2 = ip < iLen ? in[ip++] & 0xff : 0; 80 | int o0 = i0 >>> 2; 81 | int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 82 | int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 83 | int o3 = i2 & 0x3F; 84 | out[op++] = map1[o0]; 85 | out[op++] = map1[o1]; 86 | out[op] = op < oDataLen ? map1[o2] : '='; 87 | op++; 88 | out[op] = op < oDataLen ? map1[o3] : '='; 89 | op++; 90 | } 91 | return out; 92 | } 93 | 94 | /** 95 | * Decodes a string from Base64 format. 96 | * 97 | * @param s a Base64 String to be decoded. 98 | * @return A String containing the decoded data. 99 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 100 | */ 101 | public static String decodeString(String s) { 102 | return new String(decode(s)); 103 | } 104 | 105 | /** 106 | * Decodes a byte array from Base64 format. 107 | * 108 | * @param s a Base64 String to be decoded. 109 | * @return An array containing the decoded data bytes. 110 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 111 | */ 112 | public static byte[] decode(String s) { 113 | return decode(s.toCharArray()); 114 | } 115 | 116 | /** 117 | * Decodes a byte array from Base64 format. 118 | * No blanks or line breaks are allowed within the Base64 encoded data. 119 | * 120 | * @param in a character array containing the Base64 encoded data. 121 | * @return An array containing the decoded data bytes. 122 | * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 123 | */ 124 | public static byte[] decode(char[] in) { 125 | int iLen = in.length; 126 | if (iLen % 4 != 0) 127 | throw new IllegalArgumentException( 128 | "Length of Base64 encoded input string is not a multiple of 4."); 129 | while (iLen > 0 && in[iLen - 1] == '=') 130 | iLen--; 131 | int oLen = (iLen * 3) / 4; 132 | byte[] out = new byte[oLen]; 133 | int ip = 0; 134 | int op = 0; 135 | while (ip < iLen) { 136 | int i0 = in[ip++]; 137 | int i1 = in[ip++]; 138 | int i2 = ip < iLen ? in[ip++] : 'A'; 139 | int i3 = ip < iLen ? in[ip++] : 'A'; 140 | if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) 141 | throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 142 | int b0 = map2[i0]; 143 | int b1 = map2[i1]; 144 | int b2 = map2[i2]; 145 | int b3 = map2[i3]; 146 | if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) 147 | throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 148 | int o0 = (b0 << 2) | (b1 >>> 4); 149 | int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); 150 | int o2 = ((b2 & 3) << 6) | b3; 151 | out[op++] = (byte) o0; 152 | if (op < oLen) 153 | out[op++] = (byte) o1; 154 | if (op < oLen) 155 | out[op++] = (byte) o2; 156 | } 157 | return out; 158 | } 159 | 160 | 161 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start 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 start 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 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | /** 6 | * author :Peakmain 7 | * createTime:2022/7/23 8 | * mail:2726449200@qq.com 9 | * describe: 10 | */ 11 | public class ReflectUtil { 12 | 13 | static T findField(Class clazz, Object instance, String... fieldName) { 14 | T t = null; 15 | Field field = findFieldObj(clazz, fieldName); 16 | if (field == null) { 17 | return t; 18 | } 19 | try { 20 | return (T) field.get(instance); 21 | } catch (IllegalAccessException e) { 22 | return t; 23 | } catch (Exception e) { 24 | return t; 25 | } 26 | } 27 | 28 | static T findField(String[] className, Object instance, String... fieldName) { 29 | Class currentClass = getCurrentClass(className); 30 | if (currentClass != null) { 31 | return findField(currentClass, instance, fieldName); 32 | } 33 | return null; 34 | } 35 | 36 | public static Class getCurrentClass(String[] className) { 37 | if (className == null || className.length == 0) { 38 | return null; 39 | } 40 | Class currentClass = null; 41 | for (int i = 0; i < className.length; i++) { 42 | try { 43 | currentClass = Class.forName(className[i]); 44 | } catch (Exception e) { 45 | currentClass = null; 46 | } 47 | if (currentClass != null) { 48 | break; 49 | } 50 | } 51 | return currentClass; 52 | } 53 | 54 | static boolean isInstance(Object object, String... args) { 55 | if (args == null || args.length == 0) { 56 | return false; 57 | } 58 | Class clazz = null; 59 | boolean result = false; 60 | for (String arg : args) { 61 | try { 62 | clazz = Class.forName(arg); 63 | result = clazz.isInstance(object); 64 | } catch (Exception e) { 65 | //ignored 66 | } 67 | if (result) { 68 | break; 69 | } 70 | } 71 | return result; 72 | } 73 | 74 | public static T callMethod(Object instance, String methodName, Object... args) { 75 | Class[] argsClass = new Class[args.length]; 76 | for (int i = 0; i < args.length; i++) { 77 | argsClass[i] = args[i].getClass(); 78 | } 79 | Method method = getMethod(instance.getClass(), methodName, argsClass); 80 | if (method != null) { 81 | try { 82 | return (T) method.invoke(instance, args); 83 | } catch (Exception e) { 84 | // Ignored 85 | } 86 | } 87 | return null; 88 | } 89 | 90 | public static T callStaticMethod(Class clazz, String methodName, Object... args) { 91 | Class[] argsClass = new Class[args.length]; 92 | for (int i = 0; i < args.length; i++) { 93 | argsClass[i] = args[i].getClass(); 94 | } 95 | if (clazz != null) { 96 | Method method = getMethod(clazz, methodName, argsClass); 97 | if (method != null) { 98 | try { 99 | return (T) method.invoke(null, args); 100 | } catch (Exception e) { 101 | // Ignored 102 | } 103 | } 104 | } 105 | return null; 106 | } 107 | 108 | static Method getDeclaredRecur(Class clazz, String methodName, Class... params) { 109 | while (clazz != Object.class) { 110 | try { 111 | Method method = clazz.getDeclaredMethod(methodName, params); 112 | if (method != null) { 113 | return method; 114 | } 115 | } catch (NoSuchMethodException e) { 116 | clazz = clazz.getSuperclass(); 117 | } 118 | } 119 | return null; 120 | } 121 | 122 | static Method getMethod(Class clazz, String methodName, Class... params) { 123 | try { 124 | return clazz.getMethod(methodName, params); 125 | } catch (NoSuchMethodException e) { 126 | return null; 127 | } 128 | } 129 | 130 | static Field findFieldObj(Class clazz, String... fieldName) { 131 | try { 132 | if (fieldName == null || fieldName.length == 0) { 133 | return null; 134 | } 135 | Field field = null; 136 | for (int i = 0; i < fieldName.length; i++) { 137 | try { 138 | field = clazz.getDeclaredField(fieldName[i]); 139 | } catch (NoSuchFieldException ex) { 140 | field = null; 141 | } 142 | if (field != null) { 143 | break; 144 | } 145 | } 146 | if(field == null){ 147 | return null; 148 | } 149 | field.setAccessible(true); 150 | return field; 151 | } catch (Exception e) { 152 | return null; 153 | } 154 | } 155 | 156 | static Field findFieldObjRecur(Class current, String fieldName) { 157 | while (current != Object.class) { 158 | try { 159 | Field field = current.getDeclaredField(fieldName); 160 | field.setAccessible(true); 161 | return field; 162 | } catch (NoSuchFieldException e) { 163 | current = current.getSuperclass(); 164 | } 165 | } 166 | return null; 167 | } 168 | 169 | static T findFieldRecur(Object instance, String fieldName) { 170 | Field field = findFieldObjRecur(instance.getClass(), fieldName); 171 | if (field != null) { 172 | try { 173 | return (T) field.get(instance); 174 | } catch (IllegalAccessException e) { 175 | } 176 | } 177 | return null; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sdk/src/main/java/com/peakmain/sdk/utils/PreferencesUtil.java: -------------------------------------------------------------------------------- 1 | package com.peakmain.sdk.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.util.Base64; 6 | import android.util.Log; 7 | 8 | import androidx.preference.PreferenceManager; 9 | 10 | import java.io.ByteArrayInputStream; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.io.ObjectInputStream; 14 | import java.io.ObjectOutputStream; 15 | import java.io.Serializable; 16 | 17 | /** 18 | * author :Peakmain 19 | * createTime:2022/7/8 20 | * mail:2726449200@qq.com 21 | * describe: 22 | */ 23 | public class PreferencesUtil { 24 | private SharedPreferences preferences = null; 25 | private SharedPreferences.Editor editor = null; 26 | private static volatile PreferencesUtil preferencesUtil; 27 | 28 | public static PreferencesUtil getInstance() { 29 | if (preferencesUtil == null) { 30 | synchronized (PreferencesUtil.class) { 31 | if (preferencesUtil == null) { 32 | // 使用双重同步锁 33 | preferencesUtil = new PreferencesUtil(); 34 | } 35 | } 36 | } 37 | return preferencesUtil; 38 | } 39 | 40 | public void init(Context context){ 41 | preferences = PreferenceManager.getDefaultSharedPreferences(context 42 | .getApplicationContext()); 43 | } 44 | 45 | /** 46 | * 问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this; 47 | * 这样问题就来了,我们的这个类中的sInstance是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说, 48 | * 我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,造成了内存泄漏。 49 | * 所以这里使用context.getApplicationContext() 50 | */ 51 | private PreferencesUtil() { 52 | 53 | } 54 | 55 | /** 56 | * 保存数据 , 所有的类型都适用 57 | * 58 | * @param key 59 | * @param object 60 | */ 61 | public synchronized void saveParam(String key, Object object) { 62 | if (editor == null) 63 | editor = preferences.edit(); 64 | // 得到object的类型 65 | String type = object.getClass().getSimpleName(); 66 | if ("String".equals(type)) { 67 | // 保存String 类型 68 | editor.putString(key, (String) object); 69 | } else if ("Integer".equals(type)) { 70 | // 保存integer 类型 71 | editor.putInt(key, (Integer) object); 72 | } else if ("Boolean".equals(type)) { 73 | // 保存 boolean 类型 74 | editor.putBoolean(key, (Boolean) object); 75 | } else if ("Float".equals(type)) { 76 | // 保存float类型 77 | editor.putFloat(key, (Float) object); 78 | } else if ("Long".equals(type)) { 79 | // 保存long类型 80 | editor.putLong(key, (Long) object); 81 | } else { 82 | if (!(object instanceof Serializable)) { 83 | throw new IllegalArgumentException(object.getClass().getName() + " 必须实现Serializable接口!"); 84 | } 85 | 86 | // 不是基本类型则是保存对象 87 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 88 | try { 89 | ObjectOutputStream oos = new ObjectOutputStream(baos); 90 | oos.writeObject(object); 91 | String productBase64 = Base64.encodeToString( 92 | baos.toByteArray(), Base64.DEFAULT); 93 | editor.putString(key, productBase64); 94 | Log.d(this.getClass().getSimpleName(), "save object success"); 95 | } catch (IOException e) { 96 | e.printStackTrace(); 97 | Log.e(this.getClass().getSimpleName(), "save object error"); 98 | } 99 | } 100 | editor.commit(); 101 | } 102 | 103 | /** 104 | * 移除信息 105 | */ 106 | public synchronized void remove(String key) { 107 | if (editor == null) 108 | editor = preferences.edit(); 109 | editor.remove(key); 110 | editor.commit(); 111 | } 112 | 113 | 114 | /** 115 | * 得到保存数据的方法,所有类型都适用 116 | * 117 | * @param key 118 | * @param defaultObject 119 | * @return 120 | */ 121 | public Object getParam(String key, Object defaultObject) { 122 | if (defaultObject == null) { 123 | return getObject(key); 124 | } 125 | 126 | String type = defaultObject.getClass().getSimpleName(); 127 | 128 | if ("String".equals(type)) { 129 | return preferences.getString(key, (String) defaultObject); 130 | } else if ("Integer".equals(type)) { 131 | return preferences.getInt(key, (Integer) defaultObject); 132 | } else if ("Boolean".equals(type)) { 133 | return preferences.getBoolean(key, (Boolean) defaultObject); 134 | } else if ("Float".equals(type)) { 135 | return preferences.getFloat(key, (Float) defaultObject); 136 | } else if ("Long".equals(type)) { 137 | return preferences.getLong(key, (Long) defaultObject); 138 | } 139 | return getObject(key); 140 | } 141 | 142 | /** 143 | * Whether to use for the first time 144 | * 145 | * @return 146 | */ 147 | public boolean isFirst() { 148 | return (Boolean) getParam("isFirst", true); 149 | } 150 | 151 | /** 152 | * set user first use is false 153 | * 154 | * @return 155 | */ 156 | public void setFirst(Boolean isFirst) { 157 | saveParam("isFirst", isFirst); 158 | } 159 | 160 | /** 161 | * Set up the first time login 162 | * 163 | * @return 164 | */ 165 | public boolean isLogin() { 166 | return (Boolean) getParam("isLogin", false); 167 | } 168 | 169 | /** 170 | * @return 171 | */ 172 | public void setLogin(Boolean isLogin) { 173 | saveParam("isLogin", isLogin); 174 | } 175 | 176 | public Object getObject(String key) { 177 | String wordBase64 = preferences.getString(key, ""); 178 | byte[] base64 = Base64.decode(wordBase64.getBytes(), Base64.DEFAULT); 179 | ByteArrayInputStream bais = new ByteArrayInputStream(base64); 180 | try { 181 | ObjectInputStream bis = new ObjectInputStream(bais); 182 | Object object = bis.readObject(); 183 | Log.d(this.getClass().getSimpleName(), "Get object success"); 184 | return object; 185 | } catch (Exception e) { 186 | 187 | } 188 | Log.e(this.getClass().getSimpleName(), "Get object is error"); 189 | return null; 190 | } 191 | } --------------------------------------------------------------------------------