-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
10 changed files
with
2,386 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
<manifest package="com.zxxdream.helperlibrary" | ||
xmlns:android="http://schemas.android.com/apk/res/android"/> | ||
xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
280 changes: 280 additions & 0 deletions
280
MVPLib/src/main/java/com/zhangxiaoxiao/helperlibrary/utils/CrashUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
package com.zhangxiaoxiao.helperlibrary.utils; | ||
|
||
import android.annotation.SuppressLint; | ||
import android.content.pm.PackageInfo; | ||
import android.content.pm.PackageManager; | ||
import android.os.Build; | ||
import android.os.Environment; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.RequiresPermission; | ||
import android.util.Log; | ||
|
||
import com.zhangxiaoxiao.helperlibrary.base.HelperConfig; | ||
|
||
import java.io.BufferedWriter; | ||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.io.IOException; | ||
import java.io.PrintWriter; | ||
import java.io.StringWriter; | ||
import java.lang.Thread.UncaughtExceptionHandler; | ||
import java.text.Format; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Date; | ||
import java.util.concurrent.Callable; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.Future; | ||
|
||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; | ||
|
||
/** | ||
* ProjectName: helperHabit | ||
* Author: xxzhang | ||
* CreateAt: 2018/9/3 15:58 | ||
* Description: 异常捕捉 | ||
* Copyright © itzxx Inc. All Rights Reserved | ||
*/ | ||
public final class CrashUtils { | ||
|
||
private static String defaultDir; | ||
private static String dir; | ||
private static String versionName; | ||
private static int versionCode; | ||
|
||
private static final String FILE_SEP = System.getProperty("file.separator"); | ||
@SuppressLint("SimpleDateFormat") | ||
private static final Format FORMAT = new SimpleDateFormat("MM-dd HH-mm-ss"); | ||
|
||
private static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER; | ||
private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER; | ||
|
||
private static OnCrashListener sOnCrashListener; | ||
|
||
static { | ||
try { | ||
PackageInfo pi = HelperConfig.getContext() | ||
.getPackageManager() | ||
.getPackageInfo(HelperConfig.getContext().getPackageName(), 0); | ||
if (pi != null) { | ||
versionName = pi.versionName; | ||
versionCode = pi.versionCode; | ||
} | ||
} catch (PackageManager.NameNotFoundException e) { | ||
e.printStackTrace(); | ||
} | ||
DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); | ||
|
||
UNCAUGHT_EXCEPTION_HANDLER = new UncaughtExceptionHandler() { | ||
@Override | ||
public void uncaughtException(final Thread t, final Throwable e) { | ||
if (e == null) { | ||
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) { | ||
DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, null); | ||
} else { | ||
android.os.Process.killProcess(android.os.Process.myPid()); | ||
System.exit(1); | ||
} | ||
return; | ||
} | ||
|
||
final String time = FORMAT.format(new Date(System.currentTimeMillis())); | ||
final StringBuilder sb = new StringBuilder(); | ||
final String head = "************* Log Head ****************" + | ||
"\nTime Of Crash : " + time + | ||
"\nDevice Manufacturer: " + Build.MANUFACTURER + | ||
"\nDevice Model : " + Build.MODEL + | ||
"\nAndroid Version : " + Build.VERSION.RELEASE + | ||
"\nAndroid SDK : " + Build.VERSION.SDK_INT + | ||
"\nApp VersionName : " + versionName + | ||
"\nApp VersionCode : " + versionCode + | ||
"\n************* Log Head ****************\n\n"; | ||
sb.append(head); | ||
StringWriter sw = new StringWriter(); | ||
PrintWriter pw = new PrintWriter(sw); | ||
e.printStackTrace(pw); | ||
Throwable cause = e.getCause(); | ||
while (cause != null) { | ||
cause.printStackTrace(pw); | ||
cause = cause.getCause(); | ||
} | ||
pw.flush(); | ||
sb.append(sw.toString()); | ||
final String crashInfo = sb.toString(); | ||
final String fullPath = (dir == null ? defaultDir : dir) + "MVPHabit-Exception-"+time + ".txt"; | ||
if (createOrExistsFile(fullPath)) { | ||
input2File(crashInfo, fullPath); | ||
} else { | ||
Log.e("CrashUtils", "create " + fullPath + " failed!"); | ||
} | ||
|
||
if (sOnCrashListener != null) { | ||
sOnCrashListener.onCrash(crashInfo, e); | ||
} | ||
|
||
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) { | ||
DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(t, e); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
private CrashUtils() { | ||
throw new UnsupportedOperationException("u can't instantiate me..."); | ||
} | ||
|
||
/** | ||
* Initialization. | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init() { | ||
init(""); | ||
} | ||
|
||
/** | ||
* Initialization | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
* | ||
* @param crashDir The directory of saving crash information. | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init(@NonNull final File crashDir) { | ||
init(crashDir.getAbsolutePath(), null); | ||
} | ||
|
||
/** | ||
* Initialization | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
* | ||
* @param crashDirPath The directory's path of saving crash information. | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init(final String crashDirPath) { | ||
init(crashDirPath, null); | ||
} | ||
|
||
/** | ||
* Initialization | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
* | ||
* @param onCrashListener The crash listener. | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init(final OnCrashListener onCrashListener) { | ||
init("", onCrashListener); | ||
} | ||
|
||
/** | ||
* Initialization | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
* | ||
* @param crashDir The directory of saving crash information. | ||
* @param onCrashListener The crash listener. | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init(@NonNull final File crashDir, final OnCrashListener onCrashListener) { | ||
init(crashDir.getAbsolutePath(), onCrashListener); | ||
} | ||
|
||
/** | ||
* Initialization | ||
* <p>Must hold | ||
* {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />}</p> | ||
* | ||
* @param crashDirPath The directory's path of saving crash information. | ||
* @param onCrashListener The crash listener. | ||
*/ | ||
@RequiresPermission(WRITE_EXTERNAL_STORAGE) | ||
public static void init(final String crashDirPath, final OnCrashListener onCrashListener) { | ||
if (isSpace(crashDirPath)) { | ||
dir = null; | ||
} else { | ||
dir = crashDirPath.endsWith(FILE_SEP) ? crashDirPath : crashDirPath + FILE_SEP; | ||
} | ||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) | ||
&& HelperConfig.getContext().getExternalCacheDir() != null) | ||
defaultDir = HelperConfig.getContext().getExternalCacheDir() + FILE_SEP + "crash" + FILE_SEP; | ||
else { | ||
defaultDir = HelperConfig.getContext().getCacheDir() + FILE_SEP + "crash" + FILE_SEP; | ||
} | ||
sOnCrashListener = onCrashListener; | ||
Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER); | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////// | ||
// interface | ||
/////////////////////////////////////////////////////////////////////////// | ||
|
||
public interface OnCrashListener { | ||
void onCrash(String crashInfo, Throwable e); | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////// | ||
// other utils methods | ||
/////////////////////////////////////////////////////////////////////////// | ||
|
||
private static void input2File(final String input, final String filePath) { | ||
Future<Boolean> submit = Executors.newSingleThreadExecutor().submit(new Callable<Boolean>() { | ||
@Override | ||
public Boolean call() { | ||
BufferedWriter bw = null; | ||
try { | ||
bw = new BufferedWriter(new FileWriter(filePath, true)); | ||
bw.write(input); | ||
return true; | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return false; | ||
} finally { | ||
try { | ||
if (bw != null) { | ||
bw.close(); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
}); | ||
try { | ||
if (submit.get()) return; | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} catch (ExecutionException e) { | ||
e.printStackTrace(); | ||
} | ||
Log.e("CrashUtils", "write crash info to " + filePath + " failed!"); | ||
} | ||
|
||
private static boolean createOrExistsFile(final String filePath) { | ||
File file = new File(filePath); | ||
if (file.exists()) return file.isFile(); | ||
if (!createOrExistsDir(file.getParentFile())) return false; | ||
try { | ||
return file.createNewFile(); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return false; | ||
} | ||
} | ||
|
||
private static boolean createOrExistsDir(final File file) { | ||
return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); | ||
} | ||
|
||
private static boolean isSpace(final String s) { | ||
if (s == null) return true; | ||
for (int i = 0, len = s.length(); i < len; ++i) { | ||
if (!Character.isWhitespace(s.charAt(i))) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
} |
Oops, something went wrong.