package cn.flightfeather.thirdappmodule.util.crashreport
|
|
import android.content.Context
|
import android.content.SharedPreferences
|
import android.os.Build
|
import android.os.Environment
|
import android.os.Process
|
import android.util.Log
|
import cn.flightfeather.thirdappmodule.BuildConfig
|
import cn.flightfeather.thirdappmodule.common.net.ResultCallBack
|
import cn.flightfeather.thirdappmodule.repository.CommonRepository
|
import java.io.BufferedWriter
|
import java.io.File
|
import java.io.FileWriter
|
import java.io.PrintWriter
|
import java.text.SimpleDateFormat
|
import java.util.*
|
import kotlin.system.exitProcess
|
|
/**
|
* @author riku
|
* Date: 2020/4/23
|
*/
|
class MyCrashHandler(private val context: Context) : Thread.UncaughtExceptionHandler {
|
|
companion object {
|
private const val TAG = "MyCrashHandler"
|
private const val FILE_NAME = "crash_"
|
private const val FILE_NAME_SUFFIX = ".log"
|
|
var instance: MyCrashHandler? = null
|
}
|
|
private val crashPath = Environment.getExternalStorageDirectory().absolutePath + "/Crash/log/"
|
|
private var mDefaultCrashHandler: Thread.UncaughtExceptionHandler? = null
|
|
private val commonRepository: CommonRepository = CommonRepository.instance
|
|
private var accountName = ""
|
|
fun init() {
|
//读取登录用户信息
|
val sharedPre: SharedPreferences = context.getSharedPreferences("config", Context.MODE_PRIVATE)
|
accountName = sharedPre.getString("username", "") ?: ""
|
|
Thread.setDefaultUncaughtExceptionHandler(this)
|
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler()
|
if (instance == null) {
|
instance = this
|
}
|
}
|
|
override fun uncaughtException(t: Thread?, e: Throwable?) {
|
catchException(e)
|
|
e?.printStackTrace()
|
|
try {
|
Thread.sleep(3000)
|
} catch (e: Exception) {
|
e.printStackTrace()
|
}
|
onDone(t, e)
|
}
|
|
fun catchException(e: Throwable?) {
|
try {
|
val crashInfo = dumpCrashInfo()
|
val crashFile = dumpExceptionToLocal(crashInfo, e)
|
uploadExceptionToServer(crashFile, object : ResultCallBack<Boolean> {
|
override fun onSuccess(result: Boolean?) {
|
}
|
|
override fun onFailure() {
|
}
|
})
|
} catch (e: Exception) {
|
e.printStackTrace()
|
}
|
}
|
|
private fun dumpExceptionToLocal(crashInfo: CrashInfo, e: Throwable?): File? {
|
if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
|
if (BuildConfig.DEBUG) {
|
Log.w(TAG, "sdcard unmounted,skip dump exception")
|
}
|
return null
|
}
|
|
val dir = File(crashPath)
|
if (!dir.exists()) {
|
dir.mkdirs()
|
}
|
val time = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()).format(crashInfo.time)
|
val file = File(crashPath + FILE_NAME + time + FILE_NAME_SUFFIX)
|
try {
|
PrintWriter(BufferedWriter(FileWriter(file))).apply {
|
println(time)
|
println("UserId: ${crashInfo.userId}")
|
println("UserName: ${crashInfo.userName}")
|
println("RealName: ${crashInfo.realName}")
|
println("Brand: ${crashInfo.brand}")
|
println("Vendor: ${crashInfo.vendor}")
|
println("Model: ${crashInfo.model}")
|
println("OS Version: ${crashInfo.osVersion}")
|
println("App Version: ${crashInfo.appVersion}")
|
println("CPU ABI: ${crashInfo.cpuAbi}")
|
println()
|
e?.printStackTrace(this)
|
close()
|
}
|
} catch (e: Throwable) {
|
Log.e(TAG, "dump crash info failed" + e.message)
|
}
|
|
return file
|
}
|
|
private fun dumpCrashInfo(): CrashInfo {
|
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
return CrashInfo().apply {
|
time = Date()
|
// userId = appGlobalData.userId
|
userName = accountName
|
// realName = appGlobalData.realName
|
brand = Build.BRAND
|
vendor = Build.MANUFACTURER
|
model = Build.MODEL
|
osVersion = "Android_${Build.VERSION.RELEASE}_${Build.VERSION.SDK_INT}"
|
appVersion = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
"${packageInfo.versionName}_${packageInfo.longVersionCode}"
|
} else {
|
"${packageInfo.versionName}_${packageInfo.versionCode}"
|
}
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
Build.SUPPORTED_ABIS.forEach {
|
cpuAbi += "${it};"
|
}
|
}
|
}
|
}
|
|
private fun uploadExceptionToServer(crashFile: File?, resultCallBack: ResultCallBack<Boolean>) {
|
if (crashFile == null) {
|
resultCallBack.onFailure()
|
} else {
|
commonRepository.upLoadCrashInfo(accountName, crashFile, resultCallBack)
|
}
|
}
|
|
private fun onDone(t: Thread?, e: Throwable?) {
|
// if (mDefaultCrashHandler != null) {
|
// mDefaultCrashHandler?.uncaughtException(t, e)
|
// } else {
|
// Process.killProcess(Process.myPid())
|
// }
|
Process.killProcess(Process.myPid())
|
exitProcess(1)
|
}
|
}
|