25 Commits
1.2 ... 1.25

Author SHA1 Message Date
06324d104a Update version to 1.25 2023-04-17 06:41:55 +08:00
0ed2cf4903 Modify merge to YukiHookAPI new usage 2023-04-17 06:38:05 +08:00
d278faf7c9 Modify merge to YukiHookAPI new usage 2023-04-17 06:06:35 +08:00
823c5c690f Update Gradle dependencies 2023-04-17 06:05:05 +08:00
a4e1c82ad0 Update YukiHookAPI 2023-04-17 06:03:55 +08:00
07e13ccf04 Modify merge contents of build.gradle into constant definitions 2023-04-15 23:01:55 +08:00
e19f8ea4af Update Gradle dependencies 2023-04-14 17:57:05 +08:00
45c337d475 Modify change uninstalled apps or unknown apps to show their package name for users 2023-04-09 20:52:55 +08:00
8690e8afdb Modify change apps related functions returned "" for default value in FunctionFactory 2023-04-09 20:51:55 +08:00
ec7dcabdb8 Added loading view and errors records count in AppErrorsRecordActivity, activity_app_errors_record 2023-04-09 20:31:55 +08:00
0db82b5630 Added i18n strings 2023-04-09 20:30:35 +08:00
1207dbb561 Modify replace YukiHookAPI to YukiReflection in demo-app 2023-04-08 00:06:05 +08:00
785208a5bb Update Gradle & Kotlin
- Update Kotlin version to 1.8.20
- Update Gradle version to 8.0.2
- Update Gradle dependencies
2023-04-08 00:03:55 +08:00
3dbd80e06e Added start history chart in README 2023-02-19 14:39:55 +08:00
f452bb2b32 Modify change ProgressBar to CircularProgressIndicator in activity_config 2023-02-08 13:42:55 +08:00
39b779eab9 Added new bug report issues template 2023-02-08 13:25:55 +08:00
948095c016 Fix CI compiler problem and add debug version on CI 2023-02-08 13:03:15 +08:00
1a7775d5cc Fix "GitHub" spelling in all files 2023-02-07 05:27:55 +08:00
00cfca12b0 Modify change ProgressBar to CircularProgressIndicator in DialogBuilderFactory 2023-02-03 23:17:15 +08:00
556951c27c Fix some problems in CompoundButtonFactory 2023-02-03 03:39:05 +08:00
b478654008 Modify merge to CompoundButtonDataBinder and optimize code in AppErrorsDetailActivity 2023-02-03 02:26:09 +08:00
b47543e71a Modify merge to CompoundButtonDataBinder and optimize code in MainActivity 2023-02-03 02:22:05 +08:00
6ffe4bc15d Update YukiHookAPI 2023-02-01 04:32:05 +08:00
bb94689baa Update .gitignore 2023-02-01 04:31:10 +08:00
6803b60dca Update Gradle dependencies 2023-01-31 23:50:05 +08:00
39 changed files with 481 additions and 182 deletions

100
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,100 @@
name: Issues and Bugs Report / 问题与 BUG 反馈
description: 问题反馈必须使用此模板进行提交 / Issues and bugs report must be submitted using this template
labels: [ bug ]
title: "[Issues and Bugs Report] (Briefly describe the cause of the problem)"
body:
- type: markdown
attributes:
value: |
### Please fill in the specific reason and steps to reproduce the problem below.
In the event of an exception, crash functional problem, you must submit a problem log, if not, your issues will be closed directly.
### 请在下方填写问题发生的具体原因和复现步骤。
发生异常、崩溃、闪退或功能性问题,必须提交问题 Log (日志),没有 Log 的 issues 将直接被关闭。
- type: input
attributes:
label: Module App version / 模块版本
description: |
Please fill in the complete version of the Module App currently in use, for example: **1.0**
请填写当前使用的模块完整版本号,例如:**1.0**
validations:
required: true
- type: input
attributes:
label: Device model and system in used / 正在使用的设备型号以及使用的系统
description: |
Fill in the current device model and system here, the system such as (MIUI, ColorOS, OxygenOS, PE/Native)
这里填写当前使用的设备型号以及使用的系统,系统例如 (MIUI、ColorOS、OxygenOS、PE/原生)
validations:
required: true
- type: dropdown
attributes:
label: Android version / Android 版本
options:
- 13
- 12L/12.1
- 12
- 11
- 10
- 9
- 8.1
- 8.0.0
- 7.1.2
- 7.1.1
- 7.0
validations:
required: true
- type: input
attributes:
label: Xposed Framework name and version / Xposed 框架名称与版本号
description: |
Please fill in the currently used Xposed Framework, for example: **LSPosed 1.8.4 (version code)**
请填写当前使用的 Xposed 框架,例如:**LSPosed 1.8.4 (次版本号)**
validations:
required: true
- type: input
attributes:
label: Xposed Modules with the same scope / 与当前同作用域的 Xposed 模块
description: |
The scope of this module is the System Framework (Android System).
To ensure that the problem is not caused by conflicts with other modules, please be sure to fill in the relevant modules that you are currently activating at the same time.
If not, please fill in "none" directly below.
此模块的作用域为系统框架 (Android 系统),为确保非其它模块冲突造成的问题,请一定要填写当前你同时激活的相关模块。
若没有,请直接在下方填写“无”。
validations:
required: true
- type: textarea
attributes:
label: Describe in detail why the problem occurred / 详细描述问题发生的具体原因
description: 请在下方详细描述问题发生的具体场景、复现步骤和经过,以便我们能够按照你所描述的步骤复现这个问题。
validations:
required: true
- type: textarea
attributes:
label: Provide module problem logs or necessary logs / 提供模块问题 Log 或必要 Log
description: |
If you are using LSPosed, you can view and filter the logs containing `AppErrorsTracking` in the log management.
LSPosed 可在日志管理中查看并筛选包含 `AppErrorsTracking` 的日志。
value: |
<details><summary>Click to expand / 展开查看</summary><pre><code>
(Paste problem log here / 此处粘贴问题 Log)
</code></pre></details>
<!-- When submitting, please delete the parentheses including the parentheses, paste the logs you copied, and do not break the code format -->
<!-- 提交时请将括号内容包括括号全部删除,粘贴你复制的日志,不要破坏代码格式 -->
validations:
required: true
- type: checkboxes
attributes:
label: Confirm the contents you submitted / 确认一下你提交的信息
description: |
In order to ensure the quality of issues and avoid wasting unnecessary time, issues that do not check the options below will be closed directly.
Please make sure you have **checked the option below** before submitting.
为了确保 issues 的质量和避免浪费不必要的时间,未勾选下方选项的 issues 将直接被关闭。
请一定确保你已经**勾选下方的选项**后再提交。
options:
- label: I certify that the above contents is correct / 我确保上述信息准确无误
required: false

View File

@@ -47,17 +47,31 @@ jobs:
gradle-builds
- name: Build with Gradle
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
./gradlew :demo-app:assembleDebug
./gradlew :demo-app:assembleRelease
echo "APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_APK_FILE=$(find demo-app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(module)
echo "MODULE_DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_DEBUG_APK_FILE=$(find demo-app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "MODULE_RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_RELEASE_APK_FILE=$(find demo-app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(module-debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.APK_FILE }}
path: ${{ env.MODULE_DEBUG_APK_FILE }}
name: module-debug
- name: Upload Artifacts(demo-debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEMO_DEBUG_APK_FILE }}
name: demo-debug
- name: Upload Artifacts(module-release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.MODULE_RELEASE_APK_FILE }}
name: module-release
- name: Upload Artifacts(demo-app)
- name: Upload Artifacts(demo-release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEMO_APK_FILE }}
path: ${{ env.DEMO_RELEASE_APK_FILE }}
name: demo-release

View File

@@ -46,17 +46,31 @@ jobs:
gradle-builds
- name: Build with Gradle
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
./gradlew :demo-app:assembleDebug
./gradlew :demo-app:assembleRelease
echo "APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_APK_FILE=$(find demo-app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(module)
echo "MODULE_DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_DEBUG_APK_FILE=$(find demo-app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "MODULE_RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
echo "DEMO_RELEASE_APK_FILE=$(find demo-app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(module-debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.APK_FILE }}
path: ${{ env.MODULE_DEBUG_APK_FILE }}
name: module-debug
- name: Upload Artifacts(demo-debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEMO_DEBUG_APK_FILE }}
name: demo-debug
- name: Upload Artifacts(module-release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.MODULE_RELEASE_APK_FILE }}
name: module-release
- name: Upload Artifacts(demo-app)
- name: Upload Artifacts(demo-release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEMO_APK_FILE }}
path: ${{ env.DEMO_RELEASE_APK_FILE }}
name: demo-release

2
.gitignore vendored
View File

@@ -1,7 +1,7 @@
# Project exclude paths
*.iml
.gradle
.secret
.secret/APP_CENTER_SECRET
/local.properties
/.idea/caches
/.idea/libraries

View File

@@ -0,0 +1,6 @@
{
"keyAlias": "public",
"keyPassword": "123456",
"storeFileName": "universal.p12",
"storePassword": "123456"
}

View File

@@ -2,7 +2,7 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/KitsunePie/AppErrorsTracking)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/KitsunePie/AppErrorsTracking/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v1.2-green)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/badge/version-v1.25-green)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/github/downloads/KitsunePie/AppErrorsTracking/total?label=Release)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.apperrorstracking/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.apperrorstracking/releases)
<br/><br/>
@@ -59,7 +59,7 @@
- [Automatic Build on Commit](https://github.com/KitsunePie/AppErrorsTracking/actions/workflows/commit_ci.yml)
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **Github Actions** 进行查看,本更新由开源的流程自动编译发布,**不保证其稳定性**,所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号。
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **GitHub Actions** 进行查看,本更新由开源的流程自动编译发布,**不保证其稳定性**,所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号。
- [Release](https://github.com/KitsunePie/AppErrorsTracking/releases)
- [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.apperrorstracking/releases)
@@ -80,6 +80,10 @@
上述状态为当前发行的稳定版可能存在严重问题但并未及时进行修复且并未发布稳定版。
## Star History
![Star History Chart](https://api.star-history.com/svg?repos=KitsunePie/AppErrorsTracking&type=Date)
## 许可证
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)

View File

@@ -2,7 +2,7 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/KitsunePie/AppErrorsTracking)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/KitsunePie/AppErrorsTracking/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v1.2-green)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/badge/version-v1.25-green)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/github/downloads/KitsunePie/AppErrorsTracking/total?label=Release)](https://github.com/KitsunePie/AppErrorsTracking/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.apperrorstracking/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.apperrorstracking/releases)
<br/><br/>
@@ -68,7 +68,7 @@ Contributions to this project are welcome to translate it into your country's la
The above update is automatically triggered after the code `commit`.
The specific update content can be viewed by clicking the text above and going to **Github Actions**.
The specific update content can be viewed by clicking the text above and going to **GitHub Actions**.
This update is automatically compiled and released by the open source process, **no guarantee of its stability**, so the released version is
**for testing only**, and there is no special explanation or even the version may change or remain the same as the current stable version.
@@ -99,6 +99,10 @@ in a pre-release state.
The above status is that the currently released stable version may have serious problems but have not been fixed in time and the stable version
has not been released.
## Star History
![Star History Chart](https://api.star-history.com/svg?repos=KitsunePie/AppErrorsTracking&type=Date)
## License
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)

16
app/.gitignore vendored
View File

@@ -1,15 +1,3 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/src/main/assets/xposed_init
/src/main/resources/META-INF/yukihookapi_init

View File

@@ -1,43 +1,54 @@
import groovy.json.JsonSlurper
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.devtools.ksp' version '1.7.22-1.0.8'
id 'com.google.devtools.ksp'
}
android {
namespace 'com.fankes.apperrorstracking'
compileSdk 33
signingConfigs {
debug {
storeFile file('../keystore/public')
storePassword '123456'
keyAlias 'public'
keyPassword '123456'
universal {
def dirPath = rootProject.ext.app.signingConfigs.secretConfigsDirPath
def fileName = rootProject.ext.app.signingConfigs.secretConfigsFileName
def configs = new JsonSlurper().parse(file("${dirPath}/${fileName}"))
keyAlias configs.keyAlias
keyPassword configs.keyPassword
storeFile file("${dirPath}/${configs.storeFileName}")
storePassword configs.storePassword
v1SigningEnabled true
v2SigningEnabled true
}
}
defaultConfig {
applicationId "com.fankes.apperrorstracking"
minSdk 24
targetSdk 33
versionCode rootProject.ext.appVersionCode
versionName rootProject.ext.appVersionName
namespace 'com.fankes.apperrorstracking'
compileSdk rootProject.ext.android.compileSdk
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
defaultConfig {
applicationId 'com.fankes.apperrorstracking'
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
versionCode rootProject.ext.app.versionCode
versionName rootProject.ext.app.versionName
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
/** 添加 App Center Secret 到 BuildConfig */
buildConfigField("String", "APP_CENTER_SECRET", "\"${getAppCenterSecret()}\"")
buildConfigField('String', 'APP_CENTER_SECRET', "\"${getAppCenterSecret()}\"")
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.universal
}
release {
minifyEnabled rootProject.ext.enableR8
shrinkResources rootProject.ext.enableR8
zipAlignEnabled rootProject.ext.enableR8
signingConfig signingConfigs.debug
minifyEnabled true
shrinkResources true
zipAlignEnabled true
signingConfig signingConfigs.universal
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
@@ -74,17 +85,17 @@ String getAppCenterSecret() {
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.1.6'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.6'
implementation 'com.microsoft.appcenter:appcenter-analytics:4.4.5'
implementation 'com.microsoft.appcenter:appcenter-crashes:4.4.5'
implementation 'com.highcapable.yukihookapi:api:1.1.9'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.9'
implementation 'com.microsoft.appcenter:appcenter-analytics:5.0.0'
implementation 'com.microsoft.appcenter:appcenter-crashes:5.0.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.github.duanhong169:drawabletoolbox:1.0.7'
implementation 'com.github.topjohnwu.libsu:core:3.1.2'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'com.github.topjohnwu.libsu:core:5.0.4'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

View File

@@ -1 +0,0 @@
com.fankes.apperrorstracking.hook.AppErrorsTracking

View File

@@ -1 +0,0 @@
com.fankes.apperrorstracking.hook.HookEntry

View File

@@ -100,7 +100,7 @@ data class AppErrorsInfoBean(
userId = userId,
cpuAbi = packageName?.let { context.appCpuAbiOf(it) } ?: "",
packageName = packageName ?: "unknown",
versionName = packageName?.let { context.appVersionNameOf(it) } ?: "",
versionName = packageName?.let { context.appVersionNameOf(it).ifBlank { "unknown" } } ?: "",
versionCode = packageName?.let { context.appVersionCodeOf(it) } ?: -1L,
isNativeCrash = isNativeCrash,
exceptionClassName = crashInfo?.exceptionClassName ?: "unknown",

View File

@@ -87,7 +87,7 @@ object AppErrorsRecordData {
?.toEntityOrNull<CopyOnWriteArrayList<AppErrorsInfoBean>>()
?.onEach { e ->
e.cpuAbi = it.appCpuAbiOf(e.packageName)
e.versionName = it.appVersionNameOf(e.packageName)
e.versionName = it.appVersionNameOf(e.packageName).ifBlank { "unknown" }
e.versionCode = it.appVersionCodeOf(e.packageName)
e.toJsonOrNull()?.also { json -> File(errorsInfoDataFolder.absolutePath, e.jsonFileName).writeText(json) }
}.let { result ->

View File

@@ -25,8 +25,7 @@ package com.fankes.apperrorstracking.data
import android.content.Context
import android.os.Build
import android.widget.CompoundButton
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
@@ -79,7 +78,7 @@ object ConfigData {
* @return [Set]<[String]>
*/
internal fun getStringSet(key: String) = when (instance) {
is Context -> (instance as Context).modulePrefs.getStringSet(key, setOf())
is Context -> (instance as Context).prefs().getStringSet(key, setOf())
is PackageParam -> (instance as PackageParam).prefs.getStringSet(key, setOf())
else -> error("Unknown type for get prefs data")
}
@@ -91,7 +90,7 @@ object ConfigData {
*/
internal fun putStringSet(key: String, value: Set<String>) {
when (instance) {
is Context -> (instance as Context).modulePrefs.putStringSet(key, value)
is Context -> (instance as Context).prefs().edit { putStringSet(key, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
else -> error("Unknown type for put prefs data")
}
@@ -103,7 +102,7 @@ object ConfigData {
* @return [Int]
*/
internal fun getInt(data: PrefsData<Int>) = when (instance) {
is Context -> (instance as Context).modulePrefs.get(data)
is Context -> (instance as Context).prefs().get(data)
is PackageParam -> (instance as PackageParam).prefs.get(data)
else -> error("Unknown type for get prefs data")
}
@@ -115,7 +114,7 @@ object ConfigData {
*/
internal fun putInt(data: PrefsData<Int>, value: Int) {
when (instance) {
is Context -> (instance as Context).modulePrefs.put(data, value)
is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
else -> error("Unknown type for put prefs data")
}
@@ -126,8 +125,8 @@ object ConfigData {
* @param data 键值数据模板
* @return [Boolean]
*/
private fun getBoolean(data: PrefsData<Boolean>) = when (instance) {
is Context -> (instance as Context).modulePrefs.get(data)
internal fun getBoolean(data: PrefsData<Boolean>) = when (instance) {
is Context -> (instance as Context).prefs().get(data)
is PackageParam -> (instance as PackageParam).prefs.get(data)
else -> error("Unknown type for get prefs data")
}
@@ -137,29 +136,14 @@ object ConfigData {
* @param data 键值数据模板
* @param value 键值内容
*/
private fun putBoolean(data: PrefsData<Boolean>, value: Boolean) {
internal fun putBoolean(data: PrefsData<Boolean>, value: Boolean) {
when (instance) {
is Context -> (instance as Context).modulePrefs.put(data, value)
is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
else -> error("Unknown type for put prefs data")
}
}
/**
* 绑定到 [CompoundButton] 自动设置选中状态
* @param data 键值数据模板
* @param onChange 当改变时回调
*/
fun CompoundButton.bind(data: PrefsData<Boolean>, onChange: (Boolean) -> Unit = {}) {
isChecked = getBoolean(data).also(onChange)
setOnCheckedChangeListener { button, isChecked ->
if (button.isPressed) {
putBoolean(data, isChecked)
onChange(isChecked)
}
}
}
/**
* 是否显示开发者提示
* @return [Boolean]

View File

@@ -0,0 +1,101 @@
/*
* 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
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/3.
*/
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
package com.fankes.apperrorstracking.data.factory
import android.widget.CompoundButton
import com.fankes.apperrorstracking.data.ConfigData
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
/**
* 绑定到 [CompoundButton] 自动设置选中状态
* @param data 键值数据模板
* @param initiate 方法体
*/
fun CompoundButton.bind(data: PrefsData<Boolean>, initiate: CompoundButtonDataBinder.(CompoundButton) -> Unit = {}) {
val binder = CompoundButtonDataBinder(button = this).also { initiate(it, this) }
isChecked = ConfigData.getBoolean(data).also { binder.initializeCallback?.invoke(it) }
binder.applyChangesCallback = { ConfigData.putBoolean(data, it) }
setOnCheckedChangeListener { button, isChecked ->
if (button.isPressed) {
if (binder.isAutoApplyChanges) binder.applyChangesCallback?.invoke(isChecked)
binder.changedCallback?.invoke(isChecked)
}
}
}
/**
* [CompoundButton] 数据绑定管理器实例
* @param button 当前实例
*/
class CompoundButtonDataBinder(private val button: CompoundButton) {
/** 状态初始化回调事件 */
internal var initializeCallback: ((Boolean) -> Unit)? = null
/** 状态改变回调事件 */
internal var changedCallback: ((Boolean) -> Unit)? = null
/** 应用更改回调事件 */
internal var applyChangesCallback: ((Boolean) -> Unit)? = null
/** 是否启用自动应用更改 */
var isAutoApplyChanges = true
/**
* 监听状态初始化
* @param result 回调结果
*/
fun onInitialize(result: (Boolean) -> Unit) {
initializeCallback = result
}
/**
* 监听状态改变
* @param result 回调结果
*/
fun onChanged(result: (Boolean) -> Unit) {
changedCallback = result
}
/** 重新初始化 */
fun reinitialize() {
initializeCallback?.invoke(button.isChecked)
}
/** 应用更改并重新初始化 */
fun applyChangesAndReinitialize() {
applyChanges()
reinitialize()
}
/** 应用更改 */
fun applyChanges() {
applyChangesCallback?.invoke(button.isChecked)
}
/** 取消更改 */
fun cancelChanges() {
button.isChecked = button.isChecked.not()
}
}

View File

@@ -38,7 +38,7 @@ object HookEntry : IYukiHookXposedInit {
isRecord = true
}
isDebug = false
isEnableModulePrefsCache = false
isEnablePrefsBridgeCache = false
}
override fun onHook() = encase {

View File

@@ -274,7 +274,7 @@ object FrameworkHooker : YukiBaseHooker() {
*/
private fun AppErrorsProcessData.handleShowAppErrorUi(context: Context) {
/** 当前 APP 名称 */
val appName = appInfo?.let { context.appNameOf(it.packageName) } ?: packageName
val appName = appInfo?.let { context.appNameOf(it.packageName).ifBlank { it.packageName } } ?: packageName
/** 当前 APP 名称 (包含用户 ID) */
val appNameWithUserId = if (userId != 0) "$appName (${LocaleString.userId(userId)})" else appName

View File

@@ -556,4 +556,10 @@ object LocaleString {
/** @string Automatic generated */
fun updateNow(vararg objArrs: Any) = R.string.update_now.bind(*objArrs)
/** @string Automatic generated */
val recordCount get() = recordCount()
/** @string Automatic generated */
fun recordCount(vararg objArrs: Any) = R.string.record_count.bind(*objArrs)
}

View File

@@ -32,7 +32,7 @@ import androidx.core.view.isVisible
import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.data.ConfigData
import com.fankes.apperrorstracking.data.ConfigData.bind
import com.fankes.apperrorstracking.data.factory.bind
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
@@ -106,7 +106,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
}, LocaleString.shareErrorStack))
}
binding.appIcon.setImageDrawable(appIconOf(appErrorsInfo.packageName))
binding.appNameText.text = appNameOf(appErrorsInfo.packageName)
binding.appNameText.text = appNameOf(appErrorsInfo.packageName).ifBlank { appErrorsInfo.packageName }
binding.appVersionText.text = appErrorsInfo.versionBrand
binding.appUserIdText.isVisible = appErrorsInfo.userId > 0
binding.appUserIdText.text = LocaleString.userId(appErrorsInfo.userId)
@@ -123,12 +123,19 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
binding.errorStackTraceMovableText.text = appErrorsInfo.stackTrace
binding.errorStackTraceFixedText.text = appErrorsInfo.stackTrace
binding.disableAutoWrapErrorStackTraceSwitch.bind(ConfigData.DISABLE_AUTO_WRAP_ERROR_STACK_TRACE) {
binding.errorStackTraceScrollView.isVisible = it
binding.errorStackTraceFixedText.isGone = it
resetScrollView()
onInitialize {
binding.errorStackTraceScrollView.isVisible = it
binding.errorStackTraceFixedText.isGone = it
}
onChanged {
reinitialize()
resetScrollView()
}
}
binding.appPanelScrollView.setOnScrollChangeListener { _, _, y, _, _ ->
binding.detailTitleText.text = if (y >= 30.dp(context = this)) appNameOf(appErrorsInfo.packageName) else LocaleString.appName
binding.detailTitleText.text = if (y >= 30.dp(context = this))
appNameOf(appErrorsInfo.packageName).ifBlank { appErrorsInfo.packageName }
else LocaleString.appName
}
binding.detailTitleText.setOnClickListener { binding.appPanelScrollView.smoothScrollTo(0, 0) }
resetScrollView()

View File

@@ -59,7 +59,7 @@ class AppErrorsMutedActivity : BaseActivity<ActivityAppErrorsMutedBinding>() {
onBindViews<AdapterAppErrorsMutedBinding> { binding, position ->
listData[position].also { bean ->
binding.appIcon.setImageDrawable(appIconOf(bean.packageName))
binding.appNameText.text = appNameOf(bean.packageName)
binding.appNameText.text = appNameOf(bean.packageName).ifBlank { bean.packageName }
binding.muteTypeText.text = when (bean.type) {
MutedErrorsAppBean.MuteType.UNTIL_UNLOCKS -> LocaleString.muteIfUnlock
MutedErrorsAppBean.MuteType.UNTIL_REBOOTS -> LocaleString.muteIfRestart

View File

@@ -96,7 +96,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
binding.totalErrorsUnitText.text = LocaleString.totalErrorsUnit(listData.size)
binding.totalAppsUnitText.text = LocaleString.totalAppsUnit(it.size)
binding.mostErrorsAppIcon.setImageDrawable(appIconOf(mostAppPackageName))
binding.mostErrorsAppText.text = appNameOf(mostAppPackageName)
binding.mostErrorsAppText.text = appNameOf(mostAppPackageName).ifBlank { mostAppPackageName }
binding.mostErrorsTypeText.text = mostErrorsType
binding.totalPptOfErrorsText.text = "$pptCount%"
confirmButton(LocaleString.gotIt)
@@ -134,7 +134,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
onBindViews<AdapterAppErrorsRecordBinding> { binding, position ->
listData[position].also { bean ->
binding.appIcon.setImageDrawable(appIconOf(bean.packageName))
binding.appNameText.text = appNameOf(bean.packageName)
binding.appNameText.text = appNameOf(bean.packageName).ifBlank { bean.packageName }
binding.appUserIdText.isVisible = bean.userId > 0
binding.appUserIdText.text = LocaleString.userId(bean.userId)
binding.errorsTimeText.text = bean.crossTime
@@ -152,14 +152,16 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
/** 更新列表数据 */
private fun refreshData() {
FrameworkTool.fetchAppErrorsInfoData(context = this) {
binding.titleCountText.text = LocaleString.recordCount(it.size)
binding.listProgressView.isVisible = false
binding.appErrorSisIcon.isVisible = it.size >= 5
binding.clearAllIcon.isVisible = it.isNotEmpty()
binding.exportAllIcon.isVisible = it.isNotEmpty()
binding.listView.isVisible = it.isNotEmpty()
binding.listNoDataView.isVisible = it.isEmpty()
listData.clear()
it.takeIf { e -> e.isNotEmpty() }?.forEach { e -> listData.add(e) }
onChanged?.invoke()
binding.appErrorSisIcon.isVisible = listData.size >= 5
binding.clearAllIcon.isVisible = listData.isNotEmpty()
binding.exportAllIcon.isVisible = listData.isNotEmpty()
binding.listView.isVisible = listData.isNotEmpty()
binding.listNoDataView.isVisible = listData.isEmpty()
}
}

View File

@@ -28,7 +28,7 @@ import androidx.core.view.isVisible
import com.fankes.apperrorstracking.BuildConfig
import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.data.ConfigData
import com.fankes.apperrorstracking.data.ConfigData.bind
import com.fankes.apperrorstracking.data.factory.bind
import com.fankes.apperrorstracking.databinding.ActivityMainBinding
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
@@ -62,21 +62,24 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
setOnClickListener { function() }
}
}
/** 显示开发者提示 */
if (ConfigData.isShowDeveloperNotice)
showDialog {
title = LocaleString.developerNotice
msg = LocaleString.developerNoticeTip
confirmButton(LocaleString.gotIt) { ConfigData.isShowDeveloperNotice = false }
noCancelable()
}
binding.mainTextVersion.text = LocaleString.moduleVersion(BuildConfig.VERSION_NAME)
binding.mainTextSystemVersion.text = LocaleString.systemVersion(systemVersion)
binding.onlyShowErrorsInFrontSwitch.bind(ConfigData.ENABLE_ONLY_SHOW_ERRORS_IN_FRONT)
binding.onlyShowErrorsInMainProcessSwitch.bind(ConfigData.ENABLE_ONLY_SHOW_ERRORS_IN_MAIN)
binding.alwaysShowsReopenAppOptionsSwitch.bind(ConfigData.ENABLE_ALWAYS_SHOWS_REOPEN_APP_OPTIONS)
binding.enableAppsConfigsTemplateSwitch.bind(ConfigData.ENABLE_APP_CONFIG_TEMPLATE) {
binding.mgrAppsConfigsTemplateButton.isVisible = it
onInitialize { binding.mgrAppsConfigsTemplateButton.isVisible = it }
onChanged { reinitialize() }
}
binding.enableMaterial3AppErrorsDialogSwitch.bind(ConfigData.ENABLE_MATERIAL3_STYLE_APP_ERRORS_DIALOG)
/** 设置桌面图标显示隐藏 */
binding.hideIconInLauncherSwitch.isChecked = isLauncherIconShowing.not()
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
hideOrShowLauncherIcon(b)
}
/** 设置匿名统计 */
binding.enableAnonymousStatisticsSwitch.bindAppAnalytics()
/** 系统版本点击事件 */
@@ -98,14 +101,12 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.titleRestartIcon.setOnClickListener { FrameworkTool.restartSystem(context = this) }
/** 项目地址按钮点击事件 */
binding.titleGithubIcon.setOnClickListener { openBrowser(url = "https://github.com/KitsunePie/AppErrorsTracking") }
/** 显示开发者提示 */
if (ConfigData.isShowDeveloperNotice)
showDialog {
title = LocaleString.developerNotice
msg = LocaleString.developerNoticeTip
confirmButton(LocaleString.gotIt) { ConfigData.isShowDeveloperNotice = false }
noCancelable()
}
/** 设置桌面图标显示隐藏 */
binding.hideIconInLauncherSwitch.isChecked = isLauncherIconShowing.not()
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
hideOrShowLauncherIcon(b)
}
}
/** 刷新模块状态 */

View File

@@ -30,12 +30,12 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.viewbinding.ViewBinding
import com.fankes.apperrorstracking.locale.LocaleString
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.shape.MaterialShapeDrawable
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
@@ -131,7 +131,10 @@ class DialogBuilder<VB : ViewBinding>(
customLayoutView = LinearLayout(context).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER or Gravity.START
addView(ProgressBar(context))
addView(CircularProgressIndicator(context).apply {
isIndeterminate = true
trackCornerRadius = 10.dp(context)
})
addView(View(context).apply { layoutParams = ViewGroup.LayoutParams(20.dp(context), 5) })
addView(TextView(context).apply {
tag = "progressContent"

View File

@@ -133,24 +133,25 @@ fun Context.listOfPackages() = runCatching {
/**
* 得到 APP 名称
* @param packageName APP 包名 - 默认为当前 APP
* @return [String]
* @return [String] 无法获取时返回 ""
*/
fun Context.appNameOf(packageName: String = getPackageName()) =
getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: "unknown"
getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: ""
/**
* 得到 APP 版本信息与版本号
* @param packageName APP 包名 - 默认为当前 APP
* @return [String] 无法获取时返回 "unknown(-1)"
* @return [String] 无法获取时返回 ""
*/
fun Context.appVersionBrandOf(packageName: String = getPackageName()) = "${appVersionNameOf(packageName)}(${appVersionCodeOf(packageName)})"
fun Context.appVersionBrandOf(packageName: String = getPackageName()) =
if (appVersionNameOf(packageName).isNotBlank()) "${appVersionNameOf(packageName)}(${appVersionCodeOf(packageName)})" else ""
/**
* 得到 APP 版本名称
* @param packageName APP 包名 - 默认为当前 APP
* @return [String] 无法获取时返回 "unknown"
* @return [String] 无法获取时返回 ""
*/
fun Context.appVersionNameOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.versionName ?: "unknown"
fun Context.appVersionNameOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.versionName ?: ""
/**
* 得到 APP 版本号
@@ -162,7 +163,7 @@ fun Context.appVersionCodeOf(packageName: String = getPackageName()) = getPackag
/**
* 获取 APP CPU ABI 名称
* @param packageName APP 包名 - 默认为当前 APP
* @return [String]
* @return [String] 无法获取时返回 ""
*/
fun Context.appCpuAbiOf(packageName: String = getPackageName()) = runCatching {
ApplicationInfoClass.field { name = "primaryCpuAbi" }.get(getPackageInfoCompat(packageName)?.applicationInfo).string()

View File

@@ -26,7 +26,7 @@ package com.fankes.apperrorstracking.utils.tool
import android.app.Application
import android.widget.CompoundButton
import com.fankes.apperrorstracking.BuildConfig
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
import com.microsoft.appcenter.AppCenter
import com.microsoft.appcenter.analytics.Analytics
@@ -51,9 +51,9 @@ object AppAnalyticsTool {
* @return [Boolean]
*/
private var isEnableAppCenterAnalytics
get() = instance?.modulePrefs?.get(ENABLE_APP_CENTER_ANALYTICS) ?: true
get() = instance?.prefs()?.get(ENABLE_APP_CENTER_ANALYTICS) ?: true
set(value) {
instance?.modulePrefs?.put(ENABLE_APP_CENTER_ANALYTICS, value)
instance?.prefs()?.edit { put(ENABLE_APP_CENTER_ANALYTICS, value) }
}
/** 绑定到 [CompoundButton] 自动设置选中状态 */

View File

@@ -36,7 +36,7 @@ import java.io.Serializable
import java.util.*
/**
* 获取 Github Release 最新版本工具类
* 获取 GitHub Release 最新版本工具类
*/
object GithubReleaseTool {
@@ -98,7 +98,7 @@ object GithubReleaseTool {
}
/**
* Github Release bean
* GitHub Release bean
* @param name 版本名称
* @param htmlUrl 网页地址
* @param content 更新日志

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -14,9 +15,9 @@
android:elevation="0dp"
android:gravity="center|start"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:paddingTop="13dp"
android:paddingRight="15dp"
android:paddingBottom="15dp">
android:paddingBottom="5dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/title_back_icon"
@@ -29,16 +30,33 @@
android:tint="@color/colorTextGray"
android:tooltipText="@string/back" />
<TextView
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="2.5dp"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/errors_record"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:singleLine="true"
android:text="@string/errors_record"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:id="@+id/title_count_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/loading"
android:textColor="@color/colorTextDark"
android:textSize="11.5sp" />
</LinearLayout>
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/app_error_sis_icon"
@@ -74,7 +92,15 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp">
android:layout_marginTop="10dp">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/list_progress_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:indeterminate="true"
app:trackCornerRadius="10dp" />
<TextView
android:id="@+id/list_no_data_view"
@@ -85,7 +111,8 @@
android:lineSpacingExtra="6dp"
android:text="@string/no_list_data"
android:textColor="@color/colorTextDark"
android:textSize="17sp" />
android:textSize="17sp"
android:visibility="gone" />
<ListView
android:id="@+id/list_view"

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -94,11 +95,13 @@
android:layout_marginTop="10dp"
android:animateLayoutChanges="true">
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/list_progress_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center" />
android:layout_gravity="center"
android:indeterminate="true"
app:trackCornerRadius="10dp" />
<TextView
android:id="@+id/list_no_data_view"

View File

@@ -145,4 +145,5 @@
<string name="latest_version">最新バージョン %1$s</string>
<string name="latest_version_tip">%1$s に投稿\n\n変更ログ\n\n%2$s</string>
<string name="update_now">更新</string>
<string name="record_count">%1$s の合計紀錄</string>
</resources>

View File

@@ -145,4 +145,5 @@
<string name="latest_version">最新版本 %1$s</string>
<string name="latest_version_tip">发布于 %1$s\n\n更新日志\n\n%2$s</string>
<string name="update_now">更新</string>
<string name="record_count">共 %1$s 条记录</string>
</resources>

View File

@@ -145,4 +145,5 @@
<string name="latest_version">最新版本 %1$s</string>
<string name="latest_version_tip">發佈於 %1$s\n\n更新日誌\n\n%2$s</string>
<string name="update_now">升級</string>
<string name="record_count">共 %1$s 條紀錄</string>
</resources>

View File

@@ -145,4 +145,5 @@
<string name="latest_version">最新版本 %1$s</string>
<string name="latest_version_tip">發佈於 %1$s\n\n更新日誌\n\n%2$s</string>
<string name="update_now">升級</string>
<string name="record_count">共 %1$s 條紀錄</string>
</resources>

View File

@@ -145,4 +145,5 @@
<string name="latest_version">最新版本 %1$s</string>
<string name="latest_version_tip">發佈於 %1$s\n\n更新日誌\n\n%2$s</string>
<string name="update_now">升級</string>
<string name="record_count">共 %1$s 條紀錄</string>
</resources>

View File

@@ -146,4 +146,5 @@
<string name="latest_version">Latest Version %1$s</string>
<string name="latest_version_tip">Released on %1$s\n\nChangelog\n\n%2$s</string>
<string name="update_now">Update</string>
<string name="record_count">%1$s records found</string>
</resources>

View File

@@ -1,11 +1,23 @@
plugins {
id 'com.android.application' version '7.4.0' apply false
id 'com.android.library' version '7.4.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.22' apply false
id 'com.android.application' version '7.4.1' apply false
id 'com.android.library' version '7.4.1' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
id 'com.google.devtools.ksp' version '1.8.20-1.0.10' apply false
}
ext {
appVersionName = "1.2"
appVersionCode = 4
enableR8 = true
android = [
compileSdk: 33,
minSdk : 24,
targetSdk : 33,
ndkVersion: '24.0.8215888'
]
app = [
versionName : '1.25',
versionCode : 5,
signingConfigs: [
secretConfigsDirPath : "${projectDir.getAbsolutePath()}/.secret",
secretConfigsFileName: "key_store_secret.json"
]
]
}

View File

@@ -1,3 +1,5 @@
import groovy.json.JsonSlurper
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
@@ -5,39 +7,44 @@ plugins {
android {
namespace 'com.fankes.apperrorsdemo'
compileSdk 33
ndkVersion '24.0.8215888'
compileSdk rootProject.ext.android.compileSdk
ndkVersion rootProject.ext.android.ndkVersion
signingConfigs {
debug {
storeFile file('../keystore/public')
storePassword '123456'
keyAlias 'public'
keyPassword '123456'
universal {
def dirPath = rootProject.ext.app.signingConfigs.secretConfigsDirPath
def fileName = rootProject.ext.app.signingConfigs.secretConfigsFileName
def configs = new JsonSlurper().parse(file("${dirPath}/${fileName}"))
keyAlias configs.keyAlias
keyPassword configs.keyPassword
storeFile file("${dirPath}/${configs.storeFileName}")
storePassword configs.storePassword
v1SigningEnabled true
v2SigningEnabled true
}
}
defaultConfig {
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"
applicationId 'com.fankes.apperrorsdemo'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
externalNativeBuild {
cmake {
cppFlags ""
}
}
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
versionCode rootProject.ext.app.versionCode
versionName rootProject.ext.app.versionName
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.universal
}
release {
minifyEnabled false
signingConfig signingConfigs.debug
signingConfig signingConfigs.universal
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
@@ -68,11 +75,11 @@ android {
}
dependencies {
implementation 'com.highcapable.yukihookapi:api:1.1.6'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'com.highcapable.yukireflection:api:1.0.1'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
}

View File

@@ -31,9 +31,9 @@ import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding
import com.fankes.apperrorsdemo.R
import com.fankes.apperrorsdemo.utils.factory.isNotSystemInDarkMode
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import com.highcapable.yukireflection.factory.current
import com.highcapable.yukireflection.factory.method
import com.highcapable.yukireflection.type.android.LayoutInflaterClass
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {

View File

@@ -1,6 +1,6 @@
#Wed May 04 08:35:13 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME