├── .github
└── FUNDING.yml
├── .gitignore
├── .jitpack.yml
├── LICENSE
├── MIT License
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── release
│ └── output.json
├── spiderman.jks
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── simple
│ │ └── spiderman
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── example
│ │ │ └── simple
│ │ │ └── spiderman
│ │ │ ├── App.java
│ │ │ ├── CrashViewModel.kt
│ │ │ ├── MainActivity.java
│ │ │ └── TestActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── activity_test.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.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
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── simple
│ └── spiderman
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── spiderman-callback
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── simple
│ └── spiderman
│ ├── SpiderMan.java
│ └── SpiderManInitProvider.java
├── spiderman-libs
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── simple
│ │ └── spiderman
│ │ └── utils
│ │ ├── CrashModel.java
│ │ └── SpiderManUtils.java
│ └── res
│ ├── values-en
│ └── strings.xml
│ └── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── colors_dark.xml
│ ├── colors_light.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── values.xml
├── spiderman-no-op
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── simple
│ │ └── spiderman
│ │ └── SpiderMan.java
│ └── res
│ └── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── colors_dark.xml
│ ├── colors_light.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── values.xml
├── spiderman
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── simple
│ │ └── spiderman
│ │ ├── CrashActivity.java
│ │ ├── SpiderMan.java
│ │ ├── SpiderManFileProvider.java
│ │ └── SpiderManInitProvider.java
│ └── res
│ ├── layout
│ └── activity_crash.xml
│ ├── menu
│ └── menu_more.xml
│ ├── values-en
│ └── strings.xml
│ ├── values
│ ├── attrs.xml
│ ├── colors.xml
│ ├── colors_dark.xml
│ ├── colors_light.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── values.xml
│ └── xml
│ └── spiderman_file_paths.xml
└── statics
├── crash_info.png
├── crash_info_share.png
├── dark_en.png
├── light_en.png
└── q_group.jpg
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://simplepeng.github.io/merge_pay_code/
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | /.idea
8 | .DS_Store
9 | /build
10 | /captures
11 | .externalNativeBuild
12 |
--------------------------------------------------------------------------------
/.jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk11
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Peng Chen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MIT License:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 simplepeng
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpiderMan
2 |
3 | [](https://jitpack.io/#simplepeng/SpiderMan)   
4 |
5 |
6 | SpiderMan能为您做的事:
7 |
8 | * 在Android手机上自动显示闪退崩溃信息,直接分享给相关开发人员!
9 | * 再也不用担心测试妹妹给你重现怎样操作才能触发闪退崩溃的尴尬!
10 | * 再也不用担心产品给你说哪儿哪儿会闪退崩溃,但是又不能场景还原的无奈!
11 | * 再也不用担心某些国产Rom禁止异常log输出!
12 | * 再也不用担心开发工具异常log信息输出时灵时不灵!
13 |
14 | | Debug环境 | Share |
15 | | :-----------------------------------: | :------------------------------------------------: |
16 | |  |  |
17 |
18 | ## 引入依赖
19 |
20 | 从`v1.1.8`开始使用`jitpack`仓库,记得添加`jitpack`仓库的引用。
21 |
22 | ```groovy
23 | maven { url 'https://jitpack.io' }
24 | ```
25 |
26 | 在`app`的`build.gradle`引入依赖:
27 |
28 | ```groovy
29 | def spider_man = "v1.2.1"
30 | ```
31 |
32 | ### 方式一
33 |
34 | ```groovy
35 | debugImplementation "com.github.simplepeng.SpiderMan:spiderman:${spider_man}"
36 | releaseImplementation "com.github.simplepeng.SpiderMan:spiderman-no-op:${spider_man}"
37 | ```
38 |
39 | ### 方式二
40 |
41 | ```java
42 | implementation "com.github.simplepeng.SpiderMan:spiderman:${spider_man}"
43 | ```
44 |
45 | 上面`方式一`debug环境有奔溃信息提示,release环境则没有,`方式二`都有,但是记得添加混淆。
46 |
47 | ## 直接显示错误页面
48 |
49 | 有时候可能因为一些特殊环境下才会发生的崩溃很难复现,所以我们不得以会将一些代码放到`try/catch`中运行,这样虽然保证了可以不崩溃,但是当发生崩溃时又会很容易忽略掉错误信息。现在我们可以直接在`catch`代码块中调用`SpiderMan.show(Throwable e)`方法,这样就可以直接显示崩溃提示页面。
50 |
51 | ```java
52 | try {
53 | String text = null;
54 | text.toUpperCase();
55 | } catch (Exception e) {
56 | SpiderMan.show(e);
57 | }
58 | ```
59 |
60 | ## Crash回调
61 |
62 | 发生crash时,如果你希望能拿到异常信息,保存到本地或者其他自定义操作,那么你可以使用下面的回调方法。
63 |
64 | ```java
65 | //回调crash
66 | SpiderMan.setOnCrashListener(new SpiderMan.OnCrashListener() {
67 | @Override
68 | public void onCrash(Thread t, Throwable ex) {
69 | saveCrash(t, ex);
70 | }
71 | });
72 | ```
73 |
74 | `SpiderManUtils`提供了一些封装好的方法,例如`saveTextToFile`,`parseCrash`,自行按需使用。
75 |
76 | 如果release也需要回调,请使用release回调库,从`1.1.9`开始提供。
77 |
78 | ```groovy
79 | releaseImplementation "com.github.simplepeng.SpiderMan:spiderman-callback:${spider_man}"
80 | ```
81 |
82 | ## 冲突
83 |
84 | ### androidx
85 |
86 | 项目已经依赖了`androidx.appcompat:appcompat`包,如果产生冲突请使用下面的方式依赖。
87 |
88 | ```groovy
89 | debugImplementation("com.github.simplepeng.SpiderMan:spiderman:${spider_man}") {
90 | exclude group: "androidx.appcompat"
91 | }
92 | releaseImplementation("com.github.simplepeng.SpiderMan:spiderman-no-op:${spider_man}") {
93 | exclude group: "androidx.appcompat"
94 | }
95 | ```
96 |
97 | ### support
98 |
99 | 项目已经依赖了`com.android.support:appcompat-v7`包,如果产生冲突请使用下面的方式依赖。
100 |
101 | ```groovy
102 | debugImplementation("com.github.simplepeng.SpiderMan:spiderman:${spider_man}") {
103 | exclude group: "com.android.support"
104 | }
105 |
106 | releaseImplementation("com.github.simplepeng.SpiderMan:spiderman-no-op:${spider_man}") {
107 | exclude group: "com.android.support"
108 | }
109 | ```
110 |
111 | ## 混淆
112 |
113 | ```java
114 | -keep class com.simple.spiderman.** { *; }
115 | -keepnames class com.simple.spiderman.** { *; }
116 | -keep public class * extends android.app.Activity
117 | -keep class * implements Android.os.Parcelable {
118 | public static final Android.os.Parcelable$Creator *;
119 | }
120 | # support
121 | -keep public class * extends android.support.annotation.** { *; }
122 | -keep public class * extends android.support.v4.content.FileProvider
123 | # androidx
124 | -keep public class * extends androidx.annotation.** { *; }
125 | -keep public class * extends androidx.core.content.FileProvider
126 | ```
127 |
128 | ## 自定义界面样式
129 |
130 | ```java
131 | SpiderMan.setTheme(R.style.SpiderManTheme_Dark);
132 | ```
133 |
134 | `SpiderMan`内置了两种主题样式`light`和`dark`。
135 |
136 | | light | dark | custom |
137 | | :--------------------------------------------------: | :--------------------------------------------------: | :--------------------------------------------------: |
138 | |  |  |  |
139 |
140 | 所有自定义属性定义在`attrs.xml`中
141 |
142 | * smToolbar:toolbar的背景色
143 | * smToolbarText:toolb title的颜色
144 | * smToolbarShareText:分享文字按钮的颜色
145 | * smContentBackground:toolb下方内容的背景色
146 | * smIdentText:标签名字的颜色
147 | * smDescText:标签描述的颜色
148 |
149 | 具体可以参考`app`中的用法。
150 |
151 | ## 赞助
152 |
153 | 如果您觉得`SpideMan`帮助了您,可选择精准扶贫🙇🙇🙇
154 |
155 | 您的支持是作者继续努力创作的动力😁😁😁
156 |
157 | 萌戳下方链接精准扶贫⤵️⤵️⤵️
158 |
159 | **[扶贫方式](https://simplepeng.github.io/merge_pay_code/)**
160 |
161 | ## 技术支持Q群:1078185041
162 |
163 |
164 |
165 | ## 版本迭代
166 |
167 | * v1.2.0:解决协程Crash异常信息不对的问题
168 | * v1.1.9:增加`crash-callback`module,升级gradle版本
169 | * v1.1.8:使用`jitpack`仓库
170 | * v1.1.7: 自动初始化
171 | * v1.1.6: 解决view id重名引发的bug
172 | * v1.1.5: 增加`cpu-abi`,`versionCode`,`versionName`输出
173 | * v1.1.4: 切换到androidx
174 | * v1.1.3: change minSdkVersion to 14
175 | * v1.1.2: 解决FileProvider file_path重名bug(bug来源LuckSiege/PictureSelector)
176 | * v1.1.1: 新增直接显示错误页面的方法`SpiderMan.show(Throwable e)`,优化错误类型
177 | * v1.1.0: 增加自定义界面主题和国际化
178 | * v1.0.9: 增加appcompat包冲突解决方案
179 | * v1.0.8: 发现很多小伙伴不会代理异常收集,所以删除了异常回调
180 | * v1.0.7: 删除spiderman-no-op never-crash,优化报错类型显示
181 | * v1.0.6: 增加spiderman-no-op
182 | * v1.0.5: 奔溃文本分享美化排版
183 | * v1.0.4: 崩溃输出改为error级别
184 | * v1.0.3: 增加 拷贝/分享 崩溃文字/图片信息
185 | * v1.0.2: 重构,新增设备信息
186 | * v1.0.1: 去除 allowBackup,label
187 | * v1.0.0: 首次上传
188 |
189 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /.idea
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk rootProject.ext.compileSdkVersion
8 |
9 | defaultConfig {
10 | applicationId "example.simple.spiderman"
11 | minSdk rootProject.ext.minSdkVersion
12 | targetSdk rootProject.ext.targetSdkVersion
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | signingConfigs {
19 | release {
20 | storeFile file("spiderman.jks")
21 | storePassword "123456"
22 | keyAlias "spiderman"
23 | keyPassword "123456"
24 | v2SigningEnabled true
25 | }
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | signingConfig signingConfigs.release
32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
33 | }
34 | debug {
35 | minifyEnabled false
36 | signingConfig signingConfigs.release
37 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
38 | }
39 | }
40 |
41 | compileOptions {
42 | sourceCompatibility JavaVersion.VERSION_1_8
43 | targetCompatibility JavaVersion.VERSION_1_8
44 | }
45 | kotlinOptions {
46 | jvmTarget = '11'
47 | }
48 |
49 | }
50 |
51 | dependencies {
52 | implementation fileTree(include: ['*.jar'], dir: 'libs')
53 | implementation 'androidx.appcompat:appcompat:1.0.0'
54 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
55 | implementation 'androidx.core:core-ktx:1.13.1'
56 | implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
57 |
58 | // def spider_man = "1.1.7"
59 | // def spider_man_no_op = "1.1.5"
60 |
61 | // implementation project(':spiderman')
62 |
63 | // debugImplementation project(':spiderman')
64 | // releaseImplementation project(':spiderman-no-op')
65 | // debugImplementation project(':spiderman-callback')
66 |
67 | // debugImplementation project(':spiderman-no-op')
68 |
69 | // debugImplementation "com.simple:spiderman:$spider_man"
70 | // releaseImplementation "com.simple:spiderman-no-op:$spider_man_no_op"
71 |
72 | // debugImplementation ("com.simple:spiderman:$spider_man"){
73 | // exclude group: "com.android.support"
74 | // }
75 | // releaseImplementation ("com.simple:spiderman-no-op:$spider_man"){
76 | // exclude group: "com.android.support"
77 | // }
78 |
79 | //androidx
80 | // debugImplementation("com.simple:spiderman:$spider_man") {
81 | // exclude group: "androidx.appcompat"
82 | // }
83 | // releaseImplementation("com.simple:spiderman-no-op:$spider_man") {
84 | // exclude group: "androidx.appcompat"
85 | // }
86 |
87 | //开始使用jitpack
88 | def spider_man = "v1.2.1"
89 | debugImplementation "com.github.simplepeng.SpiderMan:spiderman:${spider_man}"
90 | releaseImplementation "com.github.simplepeng.SpiderMan:spiderman-no-op:${spider_man}"
91 | // releaseImplementation "com.github.simplepeng.SpiderMan:spiderman-callback:${spider_man}"
92 | }
93 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | -keep class com.simple.spiderman.** { *; }
24 | -keepnames class com.simple.spiderman.** { *; }
25 | -keep public class * extends android.app.Activity
26 | -keep public class * extends android.support.annotation.** { *; }
27 | -keep public class * extends android.support.v4.content.FileProvider
28 | -keep class * implements Android.os.Parcelable {
29 | public static final Android.os.Parcelable$Creator *;
30 | }
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/release/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
--------------------------------------------------------------------------------
/app/spiderman.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/spiderman.jks
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/simple/spiderman/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.simple.spiderman", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/example/simple/spiderman/App.java:
--------------------------------------------------------------------------------
1 | package example.simple.spiderman;
2 |
3 | import android.app.Application;
4 | import android.widget.Toast;
5 |
6 | import com.simple.spiderman.SpiderMan;
7 | import com.simple.spiderman.utils.CrashModel;
8 | import com.simple.spiderman.utils.SpiderManUtils;
9 |
10 | import java.io.File;
11 |
12 |
13 | /**
14 | * author : ChenPeng
15 | * date : 2018/4/21
16 | * description :
17 | */
18 | public class App extends Application {
19 |
20 | @Override
21 | public void onCreate() {
22 | super.onCreate();
23 |
24 | //更改主题颜色
25 | SpiderMan.setTheme(R.style.SpiderManTheme_Dark);
26 |
27 | //回调crash
28 | SpiderMan.setOnCrashListener(new SpiderMan.OnCrashListener() {
29 | @Override
30 | public void onCrash(Thread t, Throwable ex) {
31 | saveCrash(t, ex);
32 | }
33 | });
34 |
35 | }
36 |
37 | private void saveCrash(Thread t, Throwable ex) {
38 | CrashModel model = SpiderManUtils.parseCrash(this, ex);
39 | String time = String.valueOf(System.currentTimeMillis());
40 | String logPath = this.getApplicationContext().getCacheDir().getAbsolutePath() + File.separator + "log-" + time + ".txt";
41 | String text = SpiderManUtils.getShareText(this.getApplicationContext(), model);
42 | saveToFile(text, logPath);
43 | // showToast(model.toString());
44 | }
45 |
46 | public static void saveToFile(String text, String filePath) {
47 | try {
48 | SpiderManUtils.saveTextToFile(text, filePath);
49 | } catch (Throwable e) {
50 | e.printStackTrace();
51 | }
52 | }
53 |
54 | private void showToast(String text) {
55 | Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/example/simple/spiderman/CrashViewModel.kt:
--------------------------------------------------------------------------------
1 | package example.simple.spiderman
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.simple.spiderman.SpiderMan
6 | import kotlinx.coroutines.Dispatchers
7 | import kotlinx.coroutines.launch
8 |
9 | class CrashViewModel : ViewModel() {
10 |
11 | fun makeCrash() {
12 | // 1 / 0
13 | // val text: String? = null;
14 | // text!!.toUpperCase();
15 |
16 | viewModelScope.launch(Dispatchers.IO) {
17 | 1 / 0
18 | // val text: String? = null;
19 | // text!!.toUpperCase();
20 | }
21 |
22 | // thread {
23 | // 1 / 0
24 | // }
25 | }
26 |
27 | fun makeCrashWithTryCatch() {
28 | viewModelScope.launch(Dispatchers.IO) {
29 | try {
30 | 1 / 0
31 | } catch (e: Exception) {
32 | SpiderMan.show(e)
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/example/simple/spiderman/MainActivity.java:
--------------------------------------------------------------------------------
1 | package example.simple.spiderman;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.appcompat.app.AppCompatActivity;
6 | import androidx.lifecycle.ViewModelProvider;
7 |
8 | import android.view.View;
9 | import android.widget.TextView;
10 |
11 | import com.simple.spiderman.SpiderMan;
12 |
13 |
14 | public class MainActivity extends AppCompatActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_main);
20 |
21 | CrashViewModel viewModel = new ViewModelProvider(this).get(CrashViewModel.class);
22 |
23 | TextView tv_buildType = findViewById(R.id.tv_buildType);
24 | tv_buildType.setText(BuildConfig.BUILD_TYPE);
25 | findViewById(R.id.btn_crash).setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View view) {
28 | viewModel.makeCrash();
29 | // String text = null;
30 | // text.toUpperCase();
31 | // startActivity(new Intent(MainActivity.this,TestActivity.class));
32 | }
33 | });
34 |
35 | findViewById(R.id.btn_show).setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View view) {
38 | // viewModel.makeCrashWithTryCatch();
39 | try {
40 | String text = null;
41 | text.toUpperCase();
42 | } catch (Exception e) {
43 | SpiderMan.show(e);
44 | }
45 | }
46 | });
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/example/simple/spiderman/TestActivity.java:
--------------------------------------------------------------------------------
1 | package example.simple.spiderman;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.Nullable;
5 | import androidx.appcompat.app.AppCompatActivity;
6 |
7 |
8 |
9 | public class TestActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(@Nullable Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_test);
15 | String s = null;
16 | s.toCharArray();
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
21 |
22 |
38 |
39 |
57 |
58 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/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/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #e91e63
5 | #b0003a
6 | #ff6090
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SpiderMan
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/test/java/com/simple/spiderman/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
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 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | // kotlin_version = '2.0.10'
6 | // kotlin_version = '1.6.21'
7 | kotlin_version = '1.8.0'
8 | }
9 | repositories {
10 | google()
11 | jcenter()
12 | mavenCentral()
13 | }
14 | dependencies {
15 | classpath 'com.android.tools.build:gradle:7.4.2'
16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | google()
26 | // jcenter()
27 | mavenCentral()
28 | maven { url 'https://jitpack.io' }
29 | }
30 | }
31 |
32 | task clean(type: Delete) {
33 | delete rootProject.buildDir
34 | }
35 |
36 | ext {
37 | sm_version = "1.1.9"
38 | sm_no_op_version = "1.1.9"
39 |
40 | compileSdkVersion = 34
41 | minSdkVersion = 21
42 | targetSdkVersion = 34
43 |
44 | appcompat = "28.0.0"
45 | }
46 |
--------------------------------------------------------------------------------
/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 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 03 11:10:12 CST 2019
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-7.5-bin.zip
7 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.5-bin.zip
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':spiderman','spiderman-no-op'
2 | include ':spiderman-callback'
3 | include ':spiderman-libs'
4 |
--------------------------------------------------------------------------------
/spiderman-callback/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/spiderman-callback/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'maven-publish'
4 | }
5 |
6 | afterEvaluate {
7 | publishing {
8 | publications {
9 | release(MavenPublication) {
10 | from components.release
11 | }
12 | }
13 | }
14 | }
15 |
16 | android {
17 | resourcePrefix "simple"
18 |
19 | compileSdk rootProject.ext.compileSdkVersion
20 |
21 | defaultConfig {
22 | minSdk rootProject.ext.minSdkVersion
23 | targetSdk rootProject.ext.targetSdkVersion
24 | }
25 |
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 |
35 | api 'androidx.appcompat:appcompat:1.3.1'
36 | api project(path: ':spiderman-libs')
37 | }
--------------------------------------------------------------------------------
/spiderman-callback/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/spiderman-callback/consumer-rules.pro
--------------------------------------------------------------------------------
/spiderman-callback/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
--------------------------------------------------------------------------------
/spiderman-callback/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/spiderman-callback/src/main/java/com/simple/spiderman/SpiderMan.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import androidx.annotation.StyleRes;
8 |
9 | import com.simple.spiderman.utils.SpiderManUtils;
10 |
11 | @SuppressLint("StaticFieldLeak")
12 | public class SpiderMan implements Thread.UncaughtExceptionHandler {
13 |
14 | public static final String TAG = "SpiderMan";
15 |
16 | private static Context mContext;
17 |
18 | private static OnCrashListener mOnCrashListener;
19 |
20 | private static Thread.UncaughtExceptionHandler mAlreadyExistedExceptionHandler;
21 |
22 | private SpiderMan() {
23 | if (Thread.getDefaultUncaughtExceptionHandler() != null && Thread.getDefaultUncaughtExceptionHandler() != this) {
24 | mAlreadyExistedExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
25 | }
26 | Thread.setDefaultUncaughtExceptionHandler(this);
27 | }
28 |
29 | protected static void init(Context context) {
30 | mContext = context;
31 | new SpiderMan();
32 | }
33 |
34 | @Override
35 | public void uncaughtException(Thread t, Throwable ex) {
36 | callbackCrash(t, ex);
37 | transmitException(t, ex);
38 | SpiderManUtils.killApp();
39 | }
40 |
41 | public static void setTheme(@StyleRes int themeId) {
42 |
43 | }
44 |
45 | public static void show(Throwable e) {
46 |
47 | }
48 |
49 | public static Context getContext() {
50 | if (mContext == null) {
51 | throw new NullPointerException("Please call init method in Application onCreate");
52 | }
53 | return mContext;
54 | }
55 |
56 | public static void setOnCrashListener(OnCrashListener listener) {
57 | mOnCrashListener = listener;
58 | }
59 |
60 | public interface OnCrashListener {
61 | void onCrash(Thread t, Throwable ex);
62 | }
63 |
64 | private static void callbackCrash(Thread t, Throwable ex) {
65 | if (mOnCrashListener == null) return;
66 | mOnCrashListener.onCrash(t, ex);
67 | }
68 |
69 | private void transmitException(Thread t, Throwable ex) {
70 | if (mAlreadyExistedExceptionHandler == null) return;
71 | if (mAlreadyExistedExceptionHandler == this) return;
72 | mAlreadyExistedExceptionHandler.uncaughtException(t, ex);
73 | }
74 | }
--------------------------------------------------------------------------------
/spiderman-callback/src/main/java/com/simple/spiderman/SpiderManInitProvider.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | import com.simple.spiderman.utils.SpiderManUtils;
13 |
14 | public class SpiderManInitProvider extends ContentProvider {
15 | @Override
16 | public boolean onCreate() {
17 | Context application = getContext().getApplicationContext();
18 | if (application == null) {
19 | application = SpiderManUtils.getApplicationByReflect();
20 | }
21 | SpiderMan.init(application);
22 | return true;
23 | }
24 |
25 | @Nullable
26 | @Override
27 | public Cursor query(@NonNull Uri uri,
28 | @Nullable String[] projection,
29 | @Nullable String selection,
30 | @Nullable String[] selectionArgs,
31 | @Nullable String sortOrder) {
32 | return null;
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public String getType(@NonNull Uri uri) {
38 | return null;
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public Uri insert(@NonNull Uri uri,
44 | @Nullable ContentValues values) {
45 | return null;
46 | }
47 |
48 | @Override
49 | public int delete(@NonNull Uri uri,
50 | @Nullable String selection,
51 | @Nullable String[] selectionArgs) {
52 | return 0;
53 | }
54 |
55 | @Override
56 | public int update(@NonNull Uri uri,
57 | @Nullable ContentValues values,
58 | @Nullable String selection,
59 | @Nullable String[] selectionArgs) {
60 | return 0;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/spiderman-libs/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/spiderman-libs/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'maven-publish'
4 | }
5 |
6 | afterEvaluate {
7 | publishing {
8 | publications {
9 | release(MavenPublication) {
10 | from components.release
11 | }
12 | }
13 | }
14 | }
15 |
16 | android {
17 | resourcePrefix "simple"
18 |
19 | compileSdk rootProject.ext.compileSdkVersion
20 |
21 | defaultConfig {
22 | minSdk rootProject.ext.minSdkVersion
23 | targetSdk rootProject.ext.targetSdkVersion
24 | }
25 |
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 |
35 | api 'androidx.appcompat:appcompat:1.3.1'
36 | }
--------------------------------------------------------------------------------
/spiderman-libs/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/spiderman-libs/consumer-rules.pro
--------------------------------------------------------------------------------
/spiderman-libs/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
--------------------------------------------------------------------------------
/spiderman-libs/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/java/com/simple/spiderman/utils/CrashModel.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman.utils;
2 |
3 | import android.os.Build;
4 | import android.text.TextUtils;
5 |
6 | import androidx.annotation.Keep;
7 | import androidx.annotation.Nullable;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * author : ChenPeng
13 | * date : 2018/4/21
14 | * description :
15 | */
16 | @Keep
17 | public class CrashModel implements Serializable {
18 |
19 | /**
20 | * 崩溃主体信息
21 | */
22 | // @Nullable
23 | // private Throwable ex;
24 | /**
25 | * 包名,暂时未使用
26 | */
27 | private String packageName;
28 | /**
29 | * 崩溃主信息
30 | */
31 | private String exceptionMsg;
32 | /**
33 | * 崩溃类名
34 | */
35 | private String className;
36 | /**
37 | * 崩溃文件名
38 | */
39 | private String fileName;
40 | /**
41 | * 崩溃方法
42 | */
43 | private String methodName;
44 | /**
45 | * 崩溃行数
46 | */
47 | private int lineNumber;
48 | /**
49 | * 崩溃类型
50 | */
51 | private String exceptionType;
52 | /**
53 | * 全部信息
54 | */
55 | private String fullException;
56 | /**
57 | * 崩溃时间
58 | */
59 | private long time;
60 | /**
61 | * 设备信息
62 | */
63 | private final Device device = new Device();
64 | /**
65 | *
66 | */
67 | private String versionCode;
68 | private String versionName;
69 |
70 | // protected CrashModel(Parcel in) {
71 | // try {
72 | // ex = (Throwable) in.readSerializable();
73 | // exceptionMsg = in.readString();
74 | // className = in.readString();
75 | // fileName = in.readString();
76 | // methodName = in.readString();
77 | // lineNumber = in.readInt();
78 | // exceptionType = in.readString();
79 | // fullException = in.readString();
80 | // time = in.readLong();
81 | // versionCode = in.readString();
82 | // versionName = in.readString();
83 | // } catch (Throwable e) {
84 | // e.printStackTrace();
85 | // }
86 | // }
87 |
88 | // public CrashModel() {
89 | // }
90 |
91 | // public static final Creator CREATOR = new Creator() {
92 | // @Override
93 | // public CrashModel createFromParcel(Parcel in) {
94 | // return new CrashModel(in);
95 | // }
96 | //
97 | // @Override
98 | // public CrashModel[] newArray(int size) {
99 | // return new CrashModel[size];
100 | // }
101 | // };
102 |
103 | // @Nullable
104 | // public Throwable getEx() {
105 | // return ex;
106 | // }
107 |
108 | // public void setEx(Throwable ex) {
109 | // this.ex = ex;
110 | // }
111 |
112 | public String getExceptionMsg() {
113 | return exceptionMsg;
114 | }
115 |
116 | public void setExceptionMsg(String exceptionMsg) {
117 | this.exceptionMsg = exceptionMsg;
118 | }
119 |
120 | public String getClassName() {
121 | return className;
122 | }
123 |
124 | public void setClassName(String className) {
125 | this.className = className;
126 | }
127 |
128 | public String getFileName() {
129 | return TextUtils.isEmpty(fileName) ? className : fileName;
130 | }
131 |
132 | public void setFileName(String fileName) {
133 | this.fileName = fileName;
134 | }
135 |
136 | public String getMethodName() {
137 | return methodName;
138 | }
139 |
140 | public void setMethodName(String methodName) {
141 | this.methodName = methodName;
142 | }
143 |
144 | public int getLineNumber() {
145 | return lineNumber;
146 | }
147 |
148 | public void setLineNumber(int lineNumber) {
149 | this.lineNumber = lineNumber;
150 | }
151 |
152 | public String getExceptionType() {
153 | return exceptionType;
154 | }
155 |
156 | public void setExceptionType(String exceptionType) {
157 | this.exceptionType = exceptionType;
158 | }
159 |
160 | public String getFullException() {
161 | return fullException;
162 | }
163 |
164 | public void setFullException(String fullException) {
165 | this.fullException = fullException;
166 | }
167 |
168 | public String getPackageName() {
169 | return getClassName().replace(getFileName(), "");
170 | }
171 |
172 | public long getTime() {
173 | return time;
174 | }
175 |
176 | public void setTime(long time) {
177 | this.time = time;
178 | }
179 |
180 | public Device getDevice() {
181 | return device;
182 | }
183 |
184 | public String getVersionCode() {
185 | return versionCode;
186 | }
187 |
188 | public void setVersionCode(String versionCode) {
189 | this.versionCode = versionCode;
190 | }
191 |
192 | public String getVersionName() {
193 | return versionName;
194 | }
195 |
196 | public void setVersionName(String versionName) {
197 | this.versionName = versionName;
198 | }
199 |
200 | // @Override
201 | // public int describeContents() {
202 | // return 0;
203 | // }
204 | //
205 | // @Override
206 | // public void writeToParcel(Parcel dest, int flags) {
207 | // try {
208 | // if (ex != null) {
209 | // dest.writeSerializable(ex);
210 | // }
211 | // dest.writeString(exceptionMsg);
212 | // dest.writeString(className);
213 | // dest.writeString(fileName);
214 | // dest.writeString(methodName);
215 | // dest.writeInt(lineNumber);
216 | // dest.writeString(exceptionType);
217 | // dest.writeString(fullException);
218 | // dest.writeLong(time);
219 | // dest.writeString(versionCode);
220 | // dest.writeString(versionName);
221 | // } catch (Throwable e) {
222 | // e.printStackTrace();
223 | // }
224 | // }
225 |
226 | @Keep
227 | public static class Device implements Serializable {
228 | //设备名
229 | private String model = Build.MODEL;
230 | //设备厂商
231 | private String brand = Build.BRAND;
232 | //系统sdk-code
233 | private String version = String.valueOf(Build.VERSION.SDK_INT);
234 | //系统版本号-Android5.0
235 | private String release = Build.VERSION.RELEASE;
236 | //
237 | private String cpuAbi = Build.CPU_ABI;
238 |
239 | // public Device() {
240 | // }
241 |
242 | // protected Device(Parcel in) {
243 | // try {
244 | // model = in.readString();
245 | // brand = in.readString();
246 | // version = in.readString();
247 | // release = in.readString();
248 | // cpuAbi = in.readString();
249 | // } catch (Throwable e) {
250 | // e.printStackTrace();
251 | // }
252 | // }
253 |
254 | // public static final Creator CREATOR = new Creator() {
255 | // @Override
256 | // public Device createFromParcel(Parcel in) {
257 | // return new Device(in);
258 | // }
259 | //
260 | // @Override
261 | // public Device[] newArray(int size) {
262 | // return new Device[size];
263 | // }
264 | // };
265 |
266 | public String getModel() {
267 | return model;
268 | }
269 |
270 | public String getBrand() {
271 | return brand;
272 | }
273 |
274 | public String getVersion() {
275 | return version;
276 | }
277 |
278 | public String getRelease() {
279 | return release;
280 | }
281 |
282 | public String getCpuAbi() {
283 | return cpuAbi;
284 | }
285 |
286 | // @Override
287 | // public int describeContents() {
288 | // return 0;
289 | // }
290 | //
291 | // @Override
292 | // public void writeToParcel(Parcel dest, int flags) {
293 | // try {
294 | // dest.writeString(model);
295 | // dest.writeString(brand);
296 | // dest.writeString(version);
297 | // dest.writeString(release);
298 | // dest.writeString(cpuAbi);
299 | // } catch (Throwable e) {
300 | // e.printStackTrace();
301 | // }
302 | // }
303 | }
304 |
305 | // @Override
306 | // public String toString() {
307 | // return "CrashModel{" +
308 | // "ex=" + ex +
309 | // ", packageName='" + packageName + '\'' +
310 | // ", exceptionMsg='" + exceptionMsg + '\'' +
311 | // ", className='" + className + '\'' +
312 | // ", fileName='" + fileName + '\'' +
313 | // ", methodName='" + methodName + '\'' +
314 | // ", lineNumber=" + lineNumber +
315 | // ", exceptionType='" + exceptionType + '\'' +
316 | // ", fullException='" + fullException + '\'' +
317 | // ", time=" + time +
318 | // ", device=" + device +
319 | // ", versionCode='" + versionCode + '\'' +
320 | // ", versionName='" + versionName + '\'' +
321 | // '}';
322 | // }
323 | }
324 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/java/com/simple/spiderman/utils/SpiderManUtils.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman.utils;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Application;
5 | import android.content.Context;
6 | import android.content.pm.PackageInfo;
7 | import android.content.pm.PackageManager;
8 |
9 | import java.io.File;
10 | import java.io.FileWriter;
11 | import java.io.IOException;
12 | import java.io.PrintWriter;
13 | import java.io.StringWriter;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 | import java.util.Locale;
17 |
18 | public class SpiderManUtils {
19 |
20 | /**
21 | * 把Throwable解析成CrashModel实体
22 | */
23 | public static CrashModel parseCrash(Context context, Throwable ex) {
24 | CrashModel model = new CrashModel();
25 | try {
26 | // model.setEx(ex);
27 | model.setTime(new Date().getTime());
28 | if (ex.getCause() != null) {
29 | ex = ex.getCause();
30 | }
31 | model.setExceptionMsg(ex.getMessage());
32 | StringWriter sw = new StringWriter();
33 | PrintWriter pw = new PrintWriter(sw);
34 | ex.printStackTrace(pw);
35 | pw.flush();
36 | String exceptionType = ex.getClass().getName();
37 |
38 | StackTraceElement element = parseThrowable(context, ex);
39 | if (element == null) return model;
40 |
41 | model.setLineNumber(element.getLineNumber());
42 | model.setClassName(element.getClassName());
43 | model.setFileName(element.getFileName());
44 | model.setMethodName(element.getMethodName());
45 | model.setExceptionType(exceptionType);
46 |
47 | model.setFullException(sw.toString());
48 |
49 | model.setVersionCode(SpiderManUtils.getVersionCode(context));
50 | model.setVersionName(SpiderManUtils.getVersionName(context));
51 | } catch (Exception e) {
52 | return model;
53 | }
54 | return model;
55 | }
56 |
57 | /**
58 | * 把Throwable解析成StackTraceElement
59 | */
60 | public static StackTraceElement parseThrowable(Context context, Throwable ex) {
61 | if (ex == null || ex.getStackTrace() == null || ex.getStackTrace().length == 0) return null;
62 | StackTraceElement element;
63 | String packageName = context.getPackageName();
64 | for (StackTraceElement ele : ex.getStackTrace()) {
65 | if (ele.getClassName().contains(packageName)) {
66 | element = ele;
67 | return element;
68 | }
69 | }
70 | element = ex.getStackTrace()[0];
71 | return element;
72 | }
73 |
74 | /**
75 | * 获取缓存目录
76 | */
77 | public static String getCachePath(Context context) {
78 | return context.getCacheDir().getAbsolutePath();
79 | }
80 |
81 | /**
82 | * 获取versionCode
83 | */
84 | public static String getVersionCode(Context context) {
85 | String versionCode = "";
86 | try {
87 | PackageManager pm = context.getPackageManager();
88 | PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
89 | versionCode = String.valueOf(packageInfo.versionCode);
90 | } catch (Exception e) {
91 |
92 | }
93 | return versionCode;
94 | }
95 |
96 | /**
97 | * 获取versionName
98 | */
99 | public static String getVersionName(Context context) {
100 | String versionName = "";
101 | try {
102 | PackageManager pm = context.getPackageManager();
103 | PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
104 | versionName = String.valueOf(packageInfo.versionName);
105 | } catch (Exception e) {
106 |
107 | }
108 | return versionName;
109 | }
110 |
111 | /**
112 | * 用反射获取Application
113 | */
114 | public static Application getApplicationByReflect() {
115 | try {
116 | @SuppressLint("PrivateApi")
117 | Class> activityThread = Class.forName("android.app.ActivityThread");
118 | Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
119 | Object app = activityThread.getMethod("getApplication").invoke(thread);
120 | if (app == null) {
121 | throw new NullPointerException("you should init first");
122 | }
123 | return (Application) app;
124 | } catch (Exception e) {
125 | e.printStackTrace();
126 | }
127 | throw new NullPointerException("you should init first");
128 | }
129 |
130 | /**
131 | * 杀掉App进程
132 | */
133 | public static void killApp() {
134 | android.os.Process.killProcess(android.os.Process.myPid());
135 | }
136 |
137 | /**
138 | * 获取分享的文本
139 | */
140 | public static String getShareText(Context context, CrashModel model) {
141 | StringBuilder builder = new StringBuilder();
142 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH:mm", Locale.getDefault());
143 |
144 | builder.append(context.getString(R.string.simpleCrashInfo))
145 | .append("\n")
146 | .append(model.getExceptionMsg())
147 | .append("\n");
148 | builder.append("\n");//空一行,好看点,(#^.^#)
149 |
150 | builder.append(context.getString(R.string.simpleClassName))
151 | .append(model.getFileName()).append("\n");
152 | builder.append("\n");//空一行,好看点,(#^.^#)
153 |
154 | builder.append(context.getString(R.string.simpleFunName)).append(model.getMethodName()).append("\n");
155 | builder.append("\n");//空一行,好看点,(#^.^#)
156 |
157 | builder.append(context.getString(R.string.simpleLineNum)).append(model.getLineNumber()).append("\n");
158 | builder.append("\n");//空一行,好看点,(#^.^#)
159 |
160 | builder.append(context.getString(R.string.simpleExceptionType)).append(model.getExceptionType()).append("\n");
161 | builder.append("\n");//空一行,好看点,(#^.^#)
162 |
163 | builder.append(context.getString(R.string.simpleTime)).append(df.format(model.getTime())).append("\n");
164 | builder.append("\n");//空一行,好看点,(#^.^#)
165 |
166 | CrashModel.Device device = model.getDevice();
167 |
168 | builder.append(context.getString(R.string.simpleModel)).append(model.getDevice().getModel()).append("\n");
169 | builder.append("\n");//空一行,好看点,(#^.^#)
170 |
171 | builder.append(context.getString(R.string.simpleBrand)).append(model.getDevice().getBrand()).append("\n");
172 | builder.append("\n");//空一行,好看点,(#^.^#)
173 |
174 | String platform = "Android " + device.getRelease() + "-" + device.getVersion();
175 | builder.append(context.getString(R.string.simpleVersion)).append(platform).append("\n");
176 | builder.append("\n");//空一行,好看点,(#^.^#)
177 |
178 | builder.append("CPU-ABI:").append(device.getCpuAbi()).append("\n");
179 | builder.append("\n");//空一行,好看点,(#^.^#)
180 |
181 | builder.append("versionCode:").append(model.getVersionCode()).append("\n");
182 | builder.append("\n");//空一行,好看点,(#^.^#)
183 |
184 | builder.append("versionName:").append(model.getVersionName()).append("\n");
185 | builder.append("\n");//空一行,好看点,(#^.^#)
186 |
187 | builder.append(context.getString(R.string.simpleAllInfo))
188 | .append("\n")
189 | .append(model.getFullException()).append("\n");
190 |
191 | return builder.toString();
192 | }
193 |
194 | /**
195 | * 保存文本到文件
196 | */
197 | public static void saveTextToFile(String text, File file) throws IOException {
198 | FileWriter writer = new FileWriter(file);
199 | writer.write(text);
200 | writer.flush();
201 | writer.close();
202 | }
203 |
204 | /**
205 | * 保存文本到文件
206 | */
207 | public static void saveTextToFile(String text, String path) throws IOException {
208 | File file = new File(path);
209 | saveTextToFile(text, file);
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values-en/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SpiderMan
4 | Crash Info Display
5 | Copy Text
6 | Share Text
7 | Share Image
8 | Crash Info:
9 | Class Name:
10 | Fun Name:
11 | Exception Type:
12 | Line Num:
13 | Time:
14 | Device:
15 | Brand:
16 | Version:
17 | CPU-ABI:
18 | All Info:
19 | Please authorize sd card permissions
20 | Share
21 | Please insert SD card
22 | Image file does not exist
23 | ShareTo:
24 | Copy Success
25 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/colors_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #465a64
4 | #617d8a
5 | #ffffff
6 | #ffffff
7 | #ffffff
8 | #000000
9 | #617d8a
10 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/colors_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #af0839
5 | #e71e62
6 | #ffffff
7 | #ffffff
8 | #ffffff
9 | #cbcbcb
10 | #e71e62
11 |
12 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SpiderMan
4 | 崩溃信息展示
5 | 拷贝文本
6 | 分享文本
7 | 分享长图
8 | 崩溃信息:
9 | 类名:
10 | 方法:
11 | 行数:
12 | 类型:
13 | 时间:
14 | 设备名称:
15 | 设备厂商:
16 | 系统版本:
17 | CPU-ABI:
18 | 全部信息:
19 | 请授予SD卡权限才能分享图片
20 | 分享
21 | 未插入sd卡
22 | 图片文件不存在
23 | 分享到:
24 | 拷贝成功
25 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spiderman-libs/src/main/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 18sp
4 |
--------------------------------------------------------------------------------
/spiderman-no-op/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/spiderman-no-op/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'maven-publish'
4 | }
5 |
6 | afterEvaluate {
7 | publishing {
8 | publications {
9 | release(MavenPublication) {
10 | from components.release
11 | }
12 | }
13 | }
14 | }
15 |
16 | android {
17 | resourcePrefix "simple"
18 |
19 | compileSdk rootProject.ext.compileSdkVersion
20 |
21 | defaultConfig {
22 | minSdk rootProject.ext.minSdkVersion
23 | targetSdk rootProject.ext.targetSdkVersion
24 | }
25 |
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 | api 'androidx.appcompat:appcompat:1.3.1'
35 | api project(path: ':spiderman-libs')
36 | }
37 |
--------------------------------------------------------------------------------
/spiderman-no-op/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/java/com/simple/spiderman/SpiderMan.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.content.Context;
4 |
5 | public class SpiderMan {
6 |
7 | public static final String TAG = "SpiderMan";
8 |
9 | private SpiderMan() {
10 | }
11 |
12 | protected static void init(Context context) {
13 |
14 | }
15 |
16 | public static void setTheme(int themeId) {
17 |
18 | }
19 |
20 | public static void show(Throwable e) {
21 |
22 | }
23 |
24 | public static void setOnCrashListener(OnCrashListener listener) {
25 |
26 | }
27 |
28 | public interface OnCrashListener {
29 | void onCrash(Thread t, Throwable ex);
30 | }
31 | }
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/colors_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #465a64
4 | #617d8a
5 | #ffffff
6 | #ffffff
7 | #ffffff
8 | #000000
9 | #617d8a
10 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/colors_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #af0839
5 | #e71e62
6 | #ffffff
7 | #ffffff
8 | #ffffff
9 | #cbcbcb
10 | #e71e62
11 |
12 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spiderman-no-op/src/main/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/spiderman/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/spiderman/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'maven-publish'
4 | }
5 |
6 | afterEvaluate {
7 | publishing {
8 | publications {
9 | release(MavenPublication) {
10 | from components.release
11 | }
12 | }
13 | }
14 | }
15 |
16 | android {
17 | resourcePrefix "simple"
18 |
19 | compileSdk rootProject.ext.compileSdkVersion
20 |
21 | defaultConfig {
22 | minSdk rootProject.ext.minSdkVersion
23 | targetSdk rootProject.ext.targetSdkVersion
24 | }
25 |
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(include: ['*.jar'], dir: 'libs')
34 |
35 | api 'androidx.appcompat:appcompat:1.3.1'
36 | api project(path: ':spiderman-libs')
37 | }
38 |
--------------------------------------------------------------------------------
/spiderman/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/spiderman/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
17 |
18 |
19 |
22 |
23 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/spiderman/src/main/java/com/simple/spiderman/CrashActivity.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.content.ClipData;
4 | import android.content.ClipboardManager;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Canvas;
9 | import android.graphics.Paint;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.PopupMenu;
18 | import android.widget.ScrollView;
19 | import android.widget.TextView;
20 | import android.widget.Toast;
21 |
22 | import androidx.annotation.StringRes;
23 | import androidx.appcompat.app.AppCompatActivity;
24 | import androidx.core.content.FileProvider;
25 |
26 | import com.simple.spiderman.utils.CrashModel;
27 | import com.simple.spiderman.utils.SpiderManUtils;
28 |
29 | import java.io.File;
30 | import java.io.FileOutputStream;
31 | import java.text.SimpleDateFormat;
32 | import java.util.Locale;
33 |
34 | /**
35 | * author : ChenPeng
36 | * date : 2018/4/20
37 | * description :
38 | */
39 | public class CrashActivity extends AppCompatActivity {
40 |
41 | public static final String CRASH_MODEL = "crash_model";
42 |
43 | private final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH:mm", Locale.getDefault());
44 |
45 | private CrashModel model;
46 |
47 | private ScrollView sScrollView;
48 | private ViewGroup sToolbar;
49 |
50 | @Override
51 | protected void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | setTheme(SpiderMan.getThemeId());
54 | setContentView(R.layout.activity_crash);
55 |
56 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
57 | model = getIntent().getSerializableExtra(CRASH_MODEL, CrashModel.class);
58 | } else {
59 | model = ((CrashModel) getIntent().getSerializableExtra(CRASH_MODEL));
60 | }
61 |
62 | if (model == null) {
63 | return;
64 | }
65 | // if (model.getEx() != null) {
66 | // try {
67 | // Log.e("SpiderMan", Log.getStackTraceString(model.getEx()));
68 | // } catch (Throwable e) {
69 | // e.printStackTrace();
70 | // }
71 | // }
72 |
73 | sScrollView = findViewById(R.id.sScrollView);
74 | sToolbar = findViewById(R.id.sToolbar);
75 | // TextView tv_packageName = findViewById(R.id.tv_packageName);
76 | TextView textMessage = findViewById(R.id.sTextMessage);
77 | TextView tv_className = findViewById(R.id.sTvClassName);
78 | TextView tv_methodName = findViewById(R.id.sTvMethodName);
79 | TextView tv_lineNumber = findViewById(R.id.sTvLineNumber);
80 | TextView tv_exceptionType = findViewById(R.id.sTvExceptionType);
81 | TextView tv_fullException = findViewById(R.id.sTvFullException);
82 | TextView tv_time = findViewById(R.id.sTvTime);
83 | TextView tv_model = findViewById(R.id.sTvModel);
84 | TextView tv_brand = findViewById(R.id.sTvBrand);
85 | TextView tv_version = findViewById(R.id.sTvVersion);
86 | TextView tv_more = findViewById(R.id.sTvMore);
87 | TextView tv_cpuAbi = findViewById(R.id.sTvCpuAbi);
88 | TextView tv_versionCode = findViewById(R.id.sTvVersionCode);
89 | TextView tv_versionName = findViewById(R.id.sTvVersionName);
90 | //
91 | // tv_packageName.setText(model.getClassName());
92 | textMessage.setText(model.getExceptionMsg());
93 | tv_className.setText(model.getFileName());
94 | tv_methodName.setText(model.getMethodName());
95 | tv_lineNumber.setText(String.valueOf(model.getLineNumber()));
96 | tv_exceptionType.setText(model.getExceptionType());
97 | tv_fullException.setText(model.getFullException());
98 | tv_time.setText(df.format(model.getTime()));
99 |
100 | CrashModel.Device device = model.getDevice();
101 | tv_model.setText(model.getDevice().getModel());
102 | tv_brand.setText(model.getDevice().getBrand());
103 | String platform = "Android " + device.getRelease() + "-" + device.getVersion();
104 | tv_version.setText(platform);
105 |
106 | String cpuAbi = device.getCpuAbi();
107 | tv_cpuAbi.setText(cpuAbi);
108 |
109 | tv_versionCode.setText(model.getVersionCode());
110 | tv_versionName.setText(model.getVersionName());
111 |
112 | tv_more.setOnClickListener(new View.OnClickListener() {
113 | @Override
114 | public void onClick(View v) {
115 | showMenu(v);
116 | }
117 | });
118 | }
119 |
120 | private void showMenu(View v) {
121 | PopupMenu menu = new PopupMenu(CrashActivity.this, v);
122 | menu.inflate(R.menu.menu_more);
123 | menu.show();
124 | menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
125 | @Override
126 | public boolean onMenuItemClick(MenuItem item) {
127 | int id = item.getItemId();
128 | if (id == R.id.menu_copy_text) {
129 | String crashText = getShareText(model);
130 | ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
131 | if (cm != null) {
132 | ClipData mClipData = ClipData.newPlainText("crash", crashText);
133 | cm.setPrimaryClip(mClipData);
134 | showToast(getString(R.string.simpleCopied));
135 | }
136 | } else if (id == R.id.menu_share_text) {
137 | String crashText = getShareText(model);
138 | shareText(crashText);
139 | } else if (id == R.id.menu_share_image) {
140 | shareImage();
141 | }
142 | return true;
143 | }
144 | });
145 | }
146 |
147 |
148 | private String getShareText(CrashModel model) {
149 | return SpiderManUtils.getShareText(this.getApplicationContext(), model);
150 | }
151 |
152 | private void shareText(String text) {
153 | Intent intent = new Intent(Intent.ACTION_SEND);
154 | intent.setType("text/plain");
155 | intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.simpleCrashInfo));
156 | intent.putExtra(Intent.EXTRA_TEXT, text);
157 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
158 | startActivity(Intent.createChooser(intent, getString(R.string.simpleShareTo)));
159 | }
160 |
161 | public Bitmap getBitmapByView(ViewGroup toolbar, ScrollView scrollView) {
162 | if (toolbar == null || scrollView == null) return null;
163 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
164 | int svHeight = 0;
165 | for (int i = 0; i < scrollView.getChildCount(); i++) {
166 | svHeight += scrollView.getChildAt(i).getHeight();
167 | }
168 | int height = svHeight + toolbar.getHeight();
169 | //
170 | Bitmap resultBitmap = Bitmap.createBitmap(toolbar.getWidth(), height, Bitmap.Config.ARGB_8888);
171 | Canvas rootCanvas = new Canvas(resultBitmap);
172 | //
173 | Bitmap toolbarBitmap = Bitmap.createBitmap(toolbar.getWidth(), toolbar.getHeight(),
174 | Bitmap.Config.ARGB_8888);
175 | Canvas toolbarCanvas = new Canvas(toolbarBitmap);
176 | toolbarCanvas.drawRGB(255, 255, 255);
177 | toolbar.draw(toolbarCanvas);
178 | //
179 | Bitmap svBitmap = Bitmap.createBitmap(toolbar.getWidth(), svHeight,
180 | Bitmap.Config.ARGB_8888);
181 | Canvas svCanvas = new Canvas(svBitmap);
182 | svCanvas.drawRGB(255, 255, 255);
183 | scrollView.draw(svCanvas);
184 |
185 | rootCanvas.drawBitmap(toolbarBitmap, 0, 0, paint);
186 | rootCanvas.drawBitmap(svBitmap, 0, toolbar.getHeight(), paint);
187 | return resultBitmap;
188 | }
189 |
190 | private File BitmapToFile(Bitmap bitmap) {
191 | if (bitmap == null) return null;
192 | String path = SpiderManUtils.getCachePath(this.getApplicationContext());
193 | File imageFile = new File(path, "SpiderMan-" + df.format(model.getTime()) + ".png");
194 | try {
195 | FileOutputStream out = new FileOutputStream(imageFile);
196 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
197 | out.flush();
198 | out.close();
199 | bitmap.recycle();
200 | } catch (Exception e) {
201 | e.printStackTrace();
202 | }
203 | return imageFile;
204 | }
205 |
206 | private void shareImage() {
207 | File file = BitmapToFile(getBitmapByView(sToolbar, sScrollView));
208 | if (file == null || !file.exists()) {
209 | showToast(R.string.simpleImageNotExist);
210 | return;
211 | }
212 |
213 | Intent intent = new Intent();
214 | intent.setAction(Intent.ACTION_SEND);
215 | intent.setType("image/*");
216 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
217 | Uri contentUri = FileProvider.getUriForFile(getApplicationContext(),
218 | getApplicationContext().getPackageName() + ".spidermanfileprovider", file);
219 | intent.putExtra(Intent.EXTRA_STREAM, contentUri);
220 | } else {
221 | intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
222 | }
223 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
224 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
225 | startActivity(Intent.createChooser(intent, getString(R.string.simpleShareTo)));
226 | }
227 |
228 | private void showToast(String text) {
229 | Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
230 | }
231 |
232 | private void showToast(@StringRes int textId) {
233 | Toast.makeText(getApplicationContext(), textId, Toast.LENGTH_SHORT).show();
234 | }
235 |
236 | }
237 |
--------------------------------------------------------------------------------
/spiderman/src/main/java/com/simple/spiderman/SpiderMan.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.util.Log;
7 |
8 | import androidx.annotation.StyleRes;
9 |
10 | import com.simple.spiderman.utils.CrashModel;
11 | import com.simple.spiderman.utils.SpiderManUtils;
12 |
13 | @SuppressLint("StaticFieldLeak")
14 | public class SpiderMan implements Thread.UncaughtExceptionHandler {
15 |
16 | public static final String TAG = "SpiderMan";
17 |
18 | private static Context mContext;
19 |
20 | private static int mThemeId = R.style.SpiderManTheme_Light;
21 |
22 | private static OnCrashListener mOnCrashListener;
23 |
24 | private Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
25 |
26 | private SpiderMan() {
27 | defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
28 | Thread.setDefaultUncaughtExceptionHandler(this);
29 | }
30 |
31 | public static void init(Context context) {
32 | mContext = context;
33 | new SpiderMan();
34 | }
35 |
36 | @Override
37 | public void uncaughtException(Thread t, Throwable ex) {
38 | //解析Throwable
39 | CrashModel model = SpiderManUtils.parseCrash(mContext, ex);
40 | //跳转CrashActivity
41 | handleException(model);
42 | //回调异常
43 | callbackCrash(t, ex);
44 | //打印异常
45 | logThrowable(ex);
46 | //杀掉App进程
47 | SpiderManUtils.killApp();
48 | //回调给其他的UncaughtExceptionHandler
49 | if (defaultUncaughtExceptionHandler != null && defaultUncaughtExceptionHandler != this) {
50 | defaultUncaughtExceptionHandler.uncaughtException(t, ex);
51 | }
52 | }
53 |
54 | public static void setTheme(@StyleRes int themeId) {
55 | mThemeId = themeId;
56 | }
57 |
58 | protected static int getThemeId() {
59 | return mThemeId;
60 | }
61 |
62 | private static void handleException(CrashModel model) {
63 | try {
64 | Intent intent = new Intent(getContext(), CrashActivity.class);
65 | intent.putExtra(CrashActivity.CRASH_MODEL, model);
66 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
67 | mContext.startActivity(intent);
68 | } catch (Throwable e) {
69 | e.printStackTrace();
70 | }
71 | }
72 |
73 | public static void show(Throwable e) {
74 | CrashModel model = SpiderManUtils.parseCrash(mContext, e);
75 | handleException(model);
76 | }
77 |
78 | public static void logThrowable(Throwable throwable) {
79 | try {
80 | Log.e("SpiderMan", Log.getStackTraceString(throwable));
81 | } catch (Throwable e) {
82 | e.printStackTrace();
83 | }
84 | }
85 |
86 | public static Context getContext() {
87 | if (mContext == null) {
88 | throw new NullPointerException("Please call init method in Application onCreate");
89 | }
90 | return mContext;
91 | }
92 |
93 | public static void setOnCrashListener(OnCrashListener listener) {
94 | mOnCrashListener = listener;
95 | }
96 |
97 | public interface OnCrashListener {
98 | void onCrash(Thread t, Throwable ex);
99 | }
100 |
101 | private static void callbackCrash(Thread t, Throwable ex) {
102 | if (mOnCrashListener == null) return;
103 | mOnCrashListener.onCrash(t, ex);
104 | }
105 | }
--------------------------------------------------------------------------------
/spiderman/src/main/java/com/simple/spiderman/SpiderManFileProvider.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import androidx.core.content.FileProvider;
4 |
5 | public class SpiderManFileProvider extends FileProvider {
6 | }
7 |
--------------------------------------------------------------------------------
/spiderman/src/main/java/com/simple/spiderman/SpiderManInitProvider.java:
--------------------------------------------------------------------------------
1 | package com.simple.spiderman;
2 |
3 | import android.content.ContentProvider;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 |
12 | import com.simple.spiderman.utils.SpiderManUtils;
13 |
14 | public class SpiderManInitProvider extends ContentProvider {
15 |
16 | @Override
17 | public boolean onCreate() {
18 | Context application = getContext().getApplicationContext();
19 | if (application == null) {
20 | application = SpiderManUtils.getApplicationByReflect();
21 | }
22 | SpiderMan.init(application);
23 | return true;
24 | }
25 |
26 | @Nullable
27 | @Override
28 | public Cursor query(@NonNull Uri uri,
29 | @Nullable String[] projection,
30 | @Nullable String selection,
31 | @Nullable String[] selectionArgs,
32 | @Nullable String sortOrder) {
33 | return null;
34 | }
35 |
36 | @Nullable
37 | @Override
38 | public String getType(@NonNull Uri uri) {
39 | return null;
40 | }
41 |
42 | @Nullable
43 | @Override
44 | public Uri insert(@NonNull Uri uri,
45 | @Nullable ContentValues values) {
46 | return null;
47 | }
48 |
49 | @Override
50 | public int delete(@NonNull Uri uri,
51 | @Nullable String selection,
52 | @Nullable String[] selectionArgs) {
53 | return 0;
54 | }
55 |
56 | @Override
57 | public int update(@NonNull Uri uri,
58 | @Nullable ContentValues values,
59 | @Nullable String selection,
60 | @Nullable String[] selectionArgs) {
61 | return 0;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/layout/activity_crash.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
25 |
26 |
39 |
40 |
41 |
46 |
47 |
52 |
53 |
59 |
60 |
67 |
68 |
74 |
75 |
80 |
81 |
87 |
88 |
95 |
96 |
97 |
98 |
103 |
104 |
110 |
111 |
118 |
119 |
120 |
121 |
126 |
127 |
133 |
134 |
141 |
142 |
143 |
144 |
149 |
150 |
156 |
157 |
164 |
165 |
166 |
167 |
172 |
173 |
179 |
180 |
187 |
188 |
189 |
190 |
196 |
197 |
202 |
203 |
209 |
210 |
217 |
218 |
219 |
220 |
225 |
226 |
232 |
233 |
240 |
241 |
242 |
243 |
248 |
249 |
255 |
256 |
263 |
264 |
265 |
266 |
271 |
272 |
278 |
279 |
286 |
287 |
288 |
289 |
295 |
296 |
301 |
302 |
308 |
309 |
316 |
317 |
318 |
319 |
324 |
325 |
331 |
332 |
339 |
340 |
341 |
342 |
348 |
349 |
355 |
356 |
362 |
363 |
364 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/menu/menu_more.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values-en/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SpiderMan
4 | Crash Info Display
5 | Copy Text
6 | Share Text
7 | Share Image
8 | Crash Info:
9 | Class Name:
10 | Fun Name:
11 | Exception Type:
12 | Line Num:
13 | Time:
14 | Device:
15 | Brand:
16 | Version:
17 | CPU-ABI:
18 | All Info:
19 | Please authorize sd card permissions
20 | Share
21 | Please insert SD card
22 | Image file does not exist
23 | ShareTo:
24 | Copy Success
25 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/colors_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #465a64
4 | #617d8a
5 | #ffffff
6 | #ffffff
7 | #ffffff
8 | #000000
9 | #617d8a
10 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/colors_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #af0839
5 | #e71e62
6 | #ffffff
7 | #ffffff
8 | #ffffff
9 | #cbcbcb
10 | #e71e62
11 |
12 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SpiderMan
4 | 崩溃信息展示
5 | 拷贝文本
6 | 分享文本
7 | 分享长图
8 | 崩溃信息:
9 | 类名:
10 | 方法:
11 | 行数:
12 | 类型:
13 | 时间:
14 | 设备名称:
15 | 设备厂商:
16 | 系统版本:
17 | CPU-ABI:
18 | 全部信息:
19 | 请授予SD卡权限才能分享图片
20 | 分享
21 | 未插入sd卡
22 | 图片文件不存在
23 | 分享到:
24 | 拷贝成功
25 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 18sp
4 |
--------------------------------------------------------------------------------
/spiderman/src/main/res/xml/spiderman_file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/statics/crash_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/statics/crash_info.png
--------------------------------------------------------------------------------
/statics/crash_info_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/statics/crash_info_share.png
--------------------------------------------------------------------------------
/statics/dark_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/statics/dark_en.png
--------------------------------------------------------------------------------
/statics/light_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/statics/light_en.png
--------------------------------------------------------------------------------
/statics/q_group.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simplepeng/SpiderMan/135bc6d2b0cc4d65276c8f83d39759e3ef9cec45/statics/q_group.jpg
--------------------------------------------------------------------------------