diff --git a/module-app/src/main/java/com/fankes/apperrorstracking/bean/AppErrorsInfoBean.kt b/module-app/src/main/java/com/fankes/apperrorstracking/bean/AppErrorsInfoBean.kt index 058146c..92d341e 100644 --- a/module-app/src/main/java/com/fankes/apperrorstracking/bean/AppErrorsInfoBean.kt +++ b/module-app/src/main/java/com/fankes/apperrorstracking/bean/AppErrorsInfoBean.kt @@ -183,43 +183,67 @@ data class AppErrorsInfoBean( /** * 获取异常堆栈分享模板 + * @param sDeviceBrand + * @param sDeviceModel + * @param sDisplay + * @param sPackageName * @return [String] */ - val stackOutputShareContent - get() = """ + fun stackOutputShareContent( + sDeviceBrand: Boolean = true, + sDeviceModel: Boolean = true, + sDisplay: Boolean = true, + sPackageName: Boolean = true + ) = """ Generated by AppErrorsTracking $ModuleVersion Project URL: https://github.com/KitsunePie/AppErrorsTracking =============== - """.trimIndent() + "\n$environmentInfo" + """.trimIndent() + "\n${environmentInfo(sDeviceBrand, sDeviceModel, sDisplay, sPackageName)}" /** * 获取异常堆栈文件模板 + * @param sDeviceBrand + * @param sDeviceModel + * @param sDisplay + * @param sPackageName * @return [String] */ - val stackOutputFileContent - get() = """ + fun stackOutputFileContent( + sDeviceBrand: Boolean = true, + sDeviceModel: Boolean = true, + sDisplay: Boolean = true, + sPackageName: Boolean = true + ) = """ ================================================================ Generated by AppErrorsTracking $ModuleVersion Project URL: https://github.com/KitsunePie/AppErrorsTracking ================================================================ - """.trimIndent() + "\n$environmentInfo" + """.trimIndent() + "\n${environmentInfo(sDeviceBrand, sDeviceModel, sDisplay, sPackageName)}" /** * 获取运行环境信息 + * @param sDeviceBrand + * @param sDeviceModel + * @param sDisplay + * @param sPackageName * @return [String] */ - private val environmentInfo - get() = """ - [Device Brand]: ${Build.BRAND} - [Device Model]: ${Build.MODEL} - [Display]: ${Build.DISPLAY} + private fun environmentInfo( + sDeviceBrand: Boolean, + sDeviceModel: Boolean, + sDisplay: Boolean, + sPackageName: Boolean + ) = """ + [Device Brand]: ${Build.BRAND.by(sDeviceBrand)} + [Device Model]: ${Build.MODEL.by(sDeviceModel)} + [Display]: ${Build.DISPLAY.by(sDisplay)} [Android Version]: ${Build.VERSION.RELEASE} [Android API Level]: ${Build.VERSION.SDK_INT} [System Locale]: ${Locale.getDefault()} [Process ID]: $pid [User ID]: $userId [CPU ABI]: ${cpuAbi.ifBlank { "none" }} - [Package Name]: $packageName + [Package Name]: ${packageName.by(sPackageName)} [Version Name]: ${versionName.ifBlank { "unknown" }} [Version Code]: ${versionCode.takeIf { it != -1L } ?: "unknown"} [Target SDK]: ${targetSdk.takeIf { it != -1 } ?: "unknown"} @@ -227,5 +251,12 @@ data class AppErrorsInfoBean( [Error Type]: ${if (isNativeCrash) "Native" else "JVM"} [Crash Time]: $utcTime [Stack Trace]: - """.trimIndent() + "\n$stackTrace" + """.trimIndent() + "\n$stackTrace" + + /** + * 判断字符串是否需要显示 + * @param isDisplay 是否需要显示 + * @return [String] + */ + private fun String.by(isDisplay: Boolean) = if (isDisplay) this else "***" } \ No newline at end of file diff --git a/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt b/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt index 497059e..fd1dfb2 100644 --- a/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt +++ b/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt @@ -45,6 +45,7 @@ import com.fankes.apperrorstracking.utils.factory.navigate import com.fankes.apperrorstracking.utils.factory.openSelfSetting import com.fankes.apperrorstracking.utils.factory.showDialog import com.fankes.apperrorstracking.utils.factory.toast +import com.fankes.apperrorstracking.utils.tool.StackTraceShareHelper import com.highcapable.yukihookapi.hook.log.loggerE class AppErrorsDetailActivity : BaseActivity() { @@ -121,22 +122,31 @@ class AppErrorsDetailActivity : BaseActivity() { loggerE(msg = appErrorsInfo.stackTrace) toast(locale.printToLogcatSuccess) } - binding.copyIcon.setOnClickListener { copyToClipboard(appErrorsInfo.stackOutputShareContent) } + binding.copyIcon.setOnClickListener { + StackTraceShareHelper.showChoose(context = this, locale.copyErrorStack) { sDeviceBrand, sDeviceModel, sDisplay, sPackageName -> + copyToClipboard(appErrorsInfo.stackOutputShareContent(sDeviceBrand, sDeviceModel, sDisplay, sPackageName)) + } + } binding.exportIcon.setOnClickListener { - stackTrace = appErrorsInfo.stackOutputFileContent - runCatching { - startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/application" - putExtra(Intent.EXTRA_TITLE, "${appErrorsInfo.packageName}_${appErrorsInfo.utcTime}.log") - }, WRITE_REQUEST_CODE) - }.onFailure { toast(msg = "Start Android SAF failed") } + StackTraceShareHelper.showChoose(context = this, locale.exportToFile) { sDeviceBrand, sDeviceModel, sDisplay, sPackageName -> + stackTrace = appErrorsInfo.stackOutputFileContent(sDeviceBrand, sDeviceModel, sDisplay, sPackageName) + runCatching { + startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "*/application" + val packageName = if (sPackageName) appErrorsInfo.packageName else "anonymous" + putExtra(Intent.EXTRA_TITLE, "${packageName}_${appErrorsInfo.utcTime}.log") + }, WRITE_REQUEST_CODE) + }.onFailure { toast(msg = "Start Android SAF failed") } + } } binding.shareIcon.setOnClickListener { - startActivity(Intent.createChooser(Intent(Intent.ACTION_SEND).apply { - type = "text/plain" - putExtra(Intent.EXTRA_TEXT, appErrorsInfo.stackOutputShareContent) - }, locale.shareErrorStack)) + StackTraceShareHelper.showChoose(context = this, locale.shareErrorStack) { sDeviceBrand, sDeviceModel, sDisplay, sPackageName -> + startActivity(Intent.createChooser(Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, appErrorsInfo.stackOutputShareContent(sDeviceBrand, sDeviceModel, sDisplay, sPackageName)) + }, locale.shareErrorStack)) + } } binding.appIcon.setImageDrawable(appIconOf(appErrorsInfo.packageName)) binding.appNameText.text = appNameOf(appErrorsInfo.packageName).ifBlank { appErrorsInfo.packageName } diff --git a/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt b/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt index 174d503..5243102 100644 --- a/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt +++ b/module-app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt @@ -50,6 +50,7 @@ import com.fankes.apperrorstracking.utils.factory.showDialog import com.fankes.apperrorstracking.utils.factory.toUtcTime import com.fankes.apperrorstracking.utils.factory.toast import com.fankes.apperrorstracking.utils.tool.FrameworkTool +import com.fankes.apperrorstracking.utils.tool.StackTraceShareHelper import com.fankes.apperrorstracking.utils.tool.ZipFileTool import com.fankes.apperrorstracking.wrapper.BuildConfigWrapper import java.io.File @@ -176,20 +177,24 @@ class AppErrorsRecordActivity : BaseActivity() { /** 打包导出全部 */ private fun exportAll() { clearAllExportTemp() - ("${cacheDir.absolutePath}/temp").also { path -> - File(path).mkdirs() - listData.takeIf { it.isNotEmpty() }?.forEach { - File("$path/${it.packageName}_${it.utcTime}.log").writeText(it.stackOutputFileContent) + StackTraceShareHelper.showChoose(context = this, locale.exportAll) { sDeviceBrand, sDeviceModel, sDisplay, sPackageName -> + ("${cacheDir.absolutePath}/temp").also { path -> + File(path).mkdirs() + listData.takeIf { it.isNotEmpty() }?.forEachIndexed { index, bean -> + val packageName = if (sPackageName) bean.packageName else "anonymous_$index" + File("$path/${packageName}_${bean.utcTime}.log") + .writeText(bean.stackOutputFileContent(sDeviceBrand, sDeviceModel, sDisplay, sPackageName)) + } + outPutFilePath = "${cacheDir.absolutePath}/temp_${System.currentTimeMillis()}.zip" + ZipFileTool.zipMultiFile(path, outPutFilePath) + runCatching { + startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "*/application" + putExtra(Intent.EXTRA_TITLE, "app_errors_info_${System.currentTimeMillis().toUtcTime()}.zip") + }, WRITE_REQUEST_CODE) + }.onFailure { toast(msg = "Start Android SAF failed") } } - outPutFilePath = "${cacheDir.absolutePath}/temp_${System.currentTimeMillis()}.zip" - ZipFileTool.zipMultiFile(path, outPutFilePath) - runCatching { - startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/application" - putExtra(Intent.EXTRA_TITLE, "app_errors_info_${System.currentTimeMillis().toUtcTime()}.zip") - }, WRITE_REQUEST_CODE) - }.onFailure { toast(msg = "Start Android SAF failed") } } } diff --git a/module-app/src/main/java/com/fankes/apperrorstracking/utils/tool/StackTraceShareHelper.kt b/module-app/src/main/java/com/fankes/apperrorstracking/utils/tool/StackTraceShareHelper.kt new file mode 100644 index 0000000..9e0addf --- /dev/null +++ b/module-app/src/main/java/com/fankes/apperrorstracking/utils/tool/StackTraceShareHelper.kt @@ -0,0 +1,57 @@ +/* + * AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer. + * Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com) + * https://github.com/KitsunePie/AppErrorsTracking + * + * This software is non-free but opensource software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * and eula along with this software. If not, see + * + * + * This file is created by fankes on 2023/11/3. + */ +package com.fankes.apperrorstracking.utils.tool + +import android.content.Context +import com.fankes.apperrorstracking.databinding.DiaStackTraceShareBinding +import com.fankes.apperrorstracking.utils.factory.showDialog + +/** + * 异常堆栈分享工具类 + */ +object StackTraceShareHelper { + + /** + * 显示分享选择器 + * @param context 当前实例 + * @param title 对话框标题 + * @param onChoose 回调选择的结果 + */ + fun showChoose( + context: Context, + title: String, + onChoose: (sDeviceBrand: Boolean, sDeviceModel: Boolean, sDisplay: Boolean, sPackageName: Boolean) -> Unit + ) { + context.showDialog { + this.title = title + confirmButton { + val sDeviceBrand = binding.configCheck0.isChecked + val sDeviceModel = binding.configCheck1.isChecked + val sDisplay = binding.configCheck2.isChecked + val sPackageName = binding.configCheck3.isChecked + onChoose(sDeviceBrand, sDeviceModel, sDisplay, sPackageName) + cancel() + } + cancelButton() + } + } +} \ No newline at end of file diff --git a/module-app/src/main/res/layout/dia_stack_trace_share.xml b/module-app/src/main/res/layout/dia_stack_trace_share.xml new file mode 100644 index 0000000..cd42716 --- /dev/null +++ b/module-app/src/main/res/layout/dia_stack_trace_share.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module-app/src/main/res/values-ja/strings.xml b/module-app/src/main/res/values-ja/strings.xml index 9c35c7f..a52954f 100644 --- a/module-app/src/main/res/values-ja/strings.xml +++ b/module-app/src/main/res/values-ja/strings.xml @@ -148,4 +148,11 @@ %1$s の合計紀錄 CI 自動ビルド手順 コミット ID %1$s の CI 自動ビルドを使用しています。\n\nコードが送信された後、自動的にトリガーされてビルドされ、自動的にコンパイルされてリリースされますが、安定性についてはテストされていません。ご自身の責任で使用してください。 + 共有したいコンテンツを選択すると、表示したくないコンテンツの一部を非表示にすることができます。 + システム言語地域、バージョン、アプリケーションのバージョン、およびエラー ログは、非表示にしてはいけないコンテンツとして共有する必要があります。これらのコンテンツは、開発者が問題を特定するのに役立ちます。 + デバイスのブランド + デバイスモデル + システムビルドID + アプリのパッケージ名 + その他の要件 \ No newline at end of file diff --git a/module-app/src/main/res/values-zh-rCN/strings.xml b/module-app/src/main/res/values-zh-rCN/strings.xml index 7dd8609..549c695 100644 --- a/module-app/src/main/res/values-zh-rCN/strings.xml +++ b/module-app/src/main/res/values-zh-rCN/strings.xml @@ -148,4 +148,11 @@ 共 %1$s 条记录 CI 自动构建说明 你正在使用的是 CI 自动构建版本,Commit ID 为 %1$s。\n\n它是由代码提交后自动触发并构建、自动编译发布的,并未经任何稳定性测试,使用风险自负。 + 选择你想要分享的内容,你可以隐藏部分你不想展示的内容。 + 系统语言区域、版本、应用版本和错误日志等作为必须分享的内容不能被隐藏,这些内容都有助于帮助开发者定位问题。 + 设备制造商 + 设备型号 + 系统构建 ID + APP 包名 + 其它必要信息 \ No newline at end of file diff --git a/module-app/src/main/res/values-zh-rHK/strings.xml b/module-app/src/main/res/values-zh-rHK/strings.xml index f32c5cb..eb066df 100644 --- a/module-app/src/main/res/values-zh-rHK/strings.xml +++ b/module-app/src/main/res/values-zh-rHK/strings.xml @@ -148,4 +148,11 @@ 共 %1$s 條紀錄 CI 自動建置說明 你正在使用的是 CI 自動建置版本,Commit ID 為 %1$s。\n\n它是由程式碼提交後自動觸發並建置、自動編譯發布的,並未經任何穩定性測試,使用風險自負。 + 選擇您要分享的內容,您可以隱藏一些您不想顯示的內容。 + 系統語言區域、版本、應用程式版本和錯誤日誌必須作為內容共享,且不得隱藏,這些內容將幫助開發人員定位問題。 + 設備品牌 + 設備型號 + 系統建置 ID + 應用程式包名稱 + 其它必要資訊 \ No newline at end of file diff --git a/module-app/src/main/res/values-zh-rMO/strings.xml b/module-app/src/main/res/values-zh-rMO/strings.xml index f56110f..b58b659 100644 --- a/module-app/src/main/res/values-zh-rMO/strings.xml +++ b/module-app/src/main/res/values-zh-rMO/strings.xml @@ -148,4 +148,11 @@ 共 %1$s 條紀錄 CI 自動建置說明 你正在使用的是 CI 自動建置版本,Commit ID 為 %1$s。\n\n它是由程式碼提交後自動觸發並建置、自動編譯發布的,並未經任何穩定性測試,使用風險自負。 + 選擇您要分享的內容,您可以隱藏一些您不想顯示的內容。 + 系統語言區域、版本、應用程式版本和錯誤日誌必須作為內容共享,且不得隱藏,這些內容將幫助開發人員定位問題。 + 設備品牌 + 設備型號 + 系統建置 ID + 應用程式包名稱 + 其它必要資訊 \ No newline at end of file diff --git a/module-app/src/main/res/values-zh-rTW/strings.xml b/module-app/src/main/res/values-zh-rTW/strings.xml index 746c2e6..b0c3de3 100644 --- a/module-app/src/main/res/values-zh-rTW/strings.xml +++ b/module-app/src/main/res/values-zh-rTW/strings.xml @@ -148,4 +148,11 @@ 共 %1$s 條紀錄 CI 自動建置說明 你正在使用的是 CI 自動建置版本,Commit ID 為 %1$s。\n\n它是由程式碼提交後自動觸發並建置、自動編譯發布的,並未經任何穩定性測試,使用風險自負。 + 選擇您要分享的內容,您可以隱藏一些您不想顯示的內容。 + 系統語言區域、版本、應用程式版本和錯誤日誌必須作為內容共享,且不得隱藏,這些內容將幫助開發人員定位問題。 + 設備品牌 + 設備型號 + 系統建置 ID + 應用程式包名稱 + 其它必要資訊 \ No newline at end of file diff --git a/module-app/src/main/res/values/strings.xml b/module-app/src/main/res/values/strings.xml index e563257..24742dc 100644 --- a/module-app/src/main/res/values/strings.xml +++ b/module-app/src/main/res/values/strings.xml @@ -151,4 +151,11 @@ You are using a CI automated build with Commit ID %1$s.\n\nIt is automatically triggered and built after the code is committed, automatically compiled and released, and has not been tested for stability, use it at your own risk. Target %1$s Min %1$s + Select the content you want to share, and you can hide some of the content you don\'t want to show. + System language region, version, application version and error logs must be shared as content that must not be hidden, these content will help developers locate problems. + Device Brand + Device Model + System Build ID + App Package Name + Other Requirement \ No newline at end of file