import android.content.Context
import android.os.Environment
import android.text.TextUtils
import android.util.Log
import java.io.*
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
class MyCrashHandler(private val context: Context) : Thread.UncaughtExceptionHandler {
private val TAG = MyCrashHandler::class.java.simpleName
private val logFilePath =
Environment.getExternalStorageDirectory().path + File.separator + Utils.getPackageName(
context
) + File.separator + "Log" + File.separator + "crashlog"
override fun uncaughtException(t: Thread, e: Throwable) {
val stackTraceInfo = getStackInfo(e)
saveThrowableMessage(stackTraceInfo)
object : Thread() {
override fun run() {
Looper.prepare()
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
Looper.loop()
}
}.start()
}
private fun getStackInfo(e: Throwable): String {
var pw: PrintWriter? = null
var writer: Writer = StringWriter()
try {
pw = PrintWriter(writer)
e.printStackTrace(pw)
} catch (e: Exception) {
return ""
} finally {
pw?.close()
}
return writer.toString()
}
private fun saveThrowableMessage(errorMessage: String) {
if (TextUtils.isEmpty(errorMessage)) {
return;
}
val file = File(logFilePath)
if (!file.exists()) {
val mkdirs = file.mkdirs()
if (mkdirs) {
writeStringToFile(errorMessage, file)
}
} else {
writeStringToFile(errorMessage, file)
}
}
private fun writeStringToFile(errorMessage: String, file: File) {
var fos: FileOutputStream? = null
try {
val content: String = errorMessage + "[" + Utils.getCurrentDateTime() + "]\r\n"
val bais = ByteArrayInputStream(content.toByteArray(Charsets.UTF_8))
val crashLog = createCrashLogFile(file)
fos = FileOutputStream(crashLog, true)
var len: Int
val bytes = ByteArray(1024)
// while ((bais.read(bytes).let{ len = it; it != -1 })) {
while ((bais.read(bytes).also{ len = it }) != -1) {
fos.write(bytes, 0, len)
}
fos.flush()
Log.e(TAG, "寫入本地文件成功:" + file.absolutePath)
} catch (e: Exception) {
e.printStackTrace()
} finally {
fos?.close()
}
}
private fun getAllCrashFiles(): List<String> {
val dir = File(logFilePath)
val files = dir.listFiles()
val fileNames = ArrayList<String>()
for (i: Int in files.indices) {
if (files[i].isFile) {
fileNames.add(files[i].name)
}
}
return fileNames
}
private fun createCrashLogFile(file: File): File {
val sdf = SimpleDateFormat("yyyyMMdd", Locale.CHINA)
val currentDate = sdf.format(Date())
val crashLog = File(file, "$currentDate.txt")
if (!crashLog.exists()) {
crashLog.createNewFile()
val crashLogNames = getAllCrashFiles()
if (crashLogNames.size > 10) {
val currentTimeMilSeconds = Date().time
val earliestDate = sdf.format(currentTimeMilSeconds - 24 * 60 * 60 * 10 * 1000)
deleteFile("$earliestDate.txt")
}
}
return crashLog
}
private fun deleteFile(fileName: String) {
val file = File(logFilePath + File.separator + fileName)
if (file.exists()) {
file.delete()
}
}
}