Skip to content

Instantly share code, notes, and snippets.

@D-clock
Last active August 16, 2017 10:12
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save D-clock/1bbe20a3f144abb49cc9a15ded5c0fc9 to your computer and use it in GitHub Desktop.
Save D-clock/1bbe20a3f144abb49cc9a15ded5c0fc9 to your computer and use it in GitHub Desktop.
Android Java层崩溃日志捕获类
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Looper;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* app奔溃异常处理器
* <p/>
* 使用此类需要在AndroidManifest.xml配置以下权限
* <p/>
* <bold>android.permission.READ_EXTERNAL_STORAGE</bold>
* <p/>
* <bold>android.permission.WRITE_EXTERNAL_STORAGE</bold>
* <p/>
* <bold>android.permission.READ_PHONE_STATE</bold>
* <p/>
* Created by Clock on 2016/1/24.
*/
public class CrashExceptionHandler implements Thread.UncaughtExceptionHandler {
private final static String TAG = CrashExceptionHandler.class.getSimpleName();
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmm");
private Context mApplicationContext;
/**
* 保存闪退日志的文件目录
*/
private File mCrashInfoFolder;
/**
* 向远程服务器发送错误信息
*/
private CrashExceptionRemoteReport mCrashExceptionRemoteReport;
/**
* @param context
* @param crashInfoFolder 保存闪退日志的文件夹目录
*/
public CrashExceptionHandler(Context context, File crashInfoFolder) {
this.mApplicationContext = context.getApplicationContext();
this.mCrashInfoFolder = crashInfoFolder;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
ex.printStackTrace();
handleException(ex);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//杀死进程
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 配置远程传回log到服务器的设置
*
* @param crashExceptionRemoteReport
*/
public void configRemoteReport(CrashExceptionRemoteReport crashExceptionRemoteReport) {
this.mCrashExceptionRemoteReport = crashExceptionRemoteReport;
}
/**
* 处理异常
*
* @param ex
*/
private void handleException(Throwable ex) {
if (ex == null) {
return;
} else {
saveCrashInfoToFile(ex);
sendCrashInfoToServer(ex);
//使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
try {
Toast.makeText(mApplicationContext, "程序出现异常 , 即将退出....", Toast.LENGTH_LONG).show();
} catch (Exception ex) {
ex.printStackTrace();
}
Looper.loop();
}
}.start();
}
}
/**
* 保存闪退信息到本地文件中
*
* @param ex
*/
private void saveCrashInfoToFile(Throwable ex) {
try {
if (mCrashInfoFolder == null) {
return;
}
if (!mCrashInfoFolder.exists()) {//闪退日志目录不存在则先创建闪退日志目录
mCrashInfoFolder.mkdirs();
}
if (mCrashInfoFolder.exists()) {
String timeStampString = DATE_FORMAT.format(new Date());//当先的时间格式化
String crashLogFileName = timeStampString + ".log";
File crashLogFile = new File(mCrashInfoFolder, crashLogFileName);
crashLogFile.createNewFile();
//记录闪退环境的信息
RandomAccessFile randomAccessFile = new RandomAccessFile(crashLogFile, "rw");
randomAccessFile.write("------------Crash Environment Info------------\n".getBytes());
randomAccessFile.write(("Manufacture: " + SystemUtils.getDeviceManufacture() + "\n").getBytes());
randomAccessFile.write(("DeviceName: " + SystemUtils.getDeviceName() + "\n").getBytes());
randomAccessFile.write(("SystemVersion: " + SystemUtils.getSystemVersion() + "\n").getBytes());
randomAccessFile.write(("DeviceIMEI: " + SystemUtils.getDeviceIMEI(context) + "\n").getBytes());
randomAccessFile.write(("AppVersion: " + SystemUtils.getAppVersion(context) + "\n").getBytes());
randomAccessFile.write("Crash Environment Info------------\n".getBytes());
randomAccessFile.write("\n".getBytes());
randomAccessFile.close();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(crashLogFile.getAbsolutePath(), true)), true);
ex.printStackTrace(pw);//写入奔溃的日志信息
pw.close();
} else {
Log.e(TAG, "crash info folder create failure!!!");
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送发送闪退信息到远程服务器
*
* @param ex
*/
private void sendCrashInfoToServer(Throwable ex) {
if (mCrashExceptionRemoteReport != null) {
mCrashExceptionRemoteReport.onCrash(ex);
}
}
/**
* 闪退日志远程奔溃接口,主要考虑不同app下,把log回传给服务器的方式不一样,所以此处留一个对外开放的接口
*/
public static interface CrashExceptionRemoteReport {
/**
* 当闪退发生时,回调此接口函数
*
* @param ex
*/
public void onCrash(Throwable ex);
}
private static class SystemUtils {
private SystemUtils() {
}
/**
* 获取设备的制造商
*
* @return 设备制造商
*/
public static String getDeviceManufacture() {
return android.os.Build.MANUFACTURER;
}
/**
* 获取设备名称
*
* @return 设备名称
*/
public static String getDeviceName() {
return android.os.Build.MODEL;
}
/**
* 获取系统版本号
*
* @return 系统版本号
*/
public static String getSystemVersion() {
return android.os.Build.VERSION.RELEASE;
}
/**
* 获取设备号
*
* @param context
* @return
*/
public static String getDeviceIMEI(Context context) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager == null || TextUtils.isEmpty(telephonyManager.getDeviceId())) {
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
} else {
return telephonyManager.getDeviceId();
}
}
/**
* 获取应用的版本号
*
* @param context
* @return
*/
public static String getAppVersion(Context context) {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 判断当前有没有网络连接
*
* @param context
* @return
*/
public static boolean getNetworkState(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkinfo = manager.getActiveNetworkInfo();
if (networkinfo == null || !networkinfo.isAvailable()) {
return false;
}
return true;
}
/**
* SD卡是否挂载
*
* @return
*/
public static boolean mountedSdCard() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment