Skip to content

Commit 5a84ca4

Browse files
committed
Initial commit: BetterHeybox - LSPosed module for Heybox
An Xposed/LSPosed module (libxposed Modern API 102) that enhances the Heybox (XiaoHeiHe) app, targeting com.max.xiaoheihe. Features: - Ad filtering (per-toggle, instant effect via RemotePreferences): splash ads, feed ads, bubble ads, corner badge ads, promoted posts - Bottom navigation bar hiding (home / hot / games / add button), requires app restart - Post enhancement: bypass copy protection, restore system text selection and cross-line drag selection - Injected "BetterHeybox settings" entry in Heybox settings page; optional hidden launcher icon - Settings UI with per-feature switches, no-root restart via LSPosed hot reload Build: - Gradle 9.5.1 / AGP 9.2.1, compileSdk 37, minSdk 26, Java 17 - Release signing via keystore.properties (kept out of VCS) - GitHub Actions workflow: tag-triggered release builds
0 parents  commit 5a84ca4

26 files changed

Lines changed: 2437 additions & 0 deletions

.github/workflows/release.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Build Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
19+
- name: Set up JDK 17
20+
uses: actions/setup-java@v4
21+
with:
22+
distribution: temurin
23+
java-version: 17
24+
25+
- name: Set up Gradle
26+
uses: gradle/actions/setup-gradle@v4
27+
28+
# 从仓库 Secrets 恢复签名。未配置时构建 unsigned APK(不阻塞)
29+
- name: Restore signing keystore from secrets
30+
env:
31+
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
32+
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
33+
run: |
34+
if [ -n "$KEYSTORE_BASE64" ]; then
35+
mkdir -p keystore
36+
echo "$KEYSTORE_BASE64" | base64 -d > keystore/release.jks
37+
cat > keystore.properties <<EOF
38+
storeFile=keystore/release.jks
39+
storePassword=$KEYSTORE_PASSWORD
40+
keyAlias=betterheybox
41+
keyPassword=$KEYSTORE_PASSWORD
42+
EOF
43+
else
44+
echo "No KEYSTORE_BASE64 secret - building unsigned APK"
45+
fi
46+
47+
- name: Build release APK
48+
run: ./gradlew assembleRelease
49+
50+
- name: Upload APK artifact
51+
uses: actions/upload-artifact@v4
52+
with:
53+
name: app-release
54+
path: app/build/outputs/apk/release/*.apk
55+
56+
- name: Publish GitHub Release (on tag)
57+
if: startsWith(github.ref, 'refs/tags/')
58+
uses: softprops/action-gh-release@v2
59+
with:
60+
files: app/build/outputs/apk/release/*.apk
61+
generate_release_notes: true

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Gradle
2+
.gradle/
3+
build/
4+
!gradle/wrapper/gradle-wrapper.jar
5+
6+
# IDE
7+
.idea/
8+
*.iml
9+
local.properties
10+
11+
# Android
12+
captures/
13+
.externalNativeBuild/
14+
.cxx/
15+
16+
# Kotlin
17+
.kotlin/
18+
19+
# Temp
20+
analysis/
21+
docs/
22+
23+
# Keystore
24+
keystore/
25+
keystore.properties
26+
*.jks
27+
*.keystore
28+
29+
# Others
30+
*.hprof
31+
.DS_Store
32+
Thumbs.db

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Changelog
2+
3+
本项目版本号在 `gradle.properties` 统一管理(`VERSION_CODE` / `VERSION_NAME`)。
4+
发布时递增 `VERSION_CODE` 并打 tag(如 `v0.2.0`),CI 会自动构建并发布 Release。
5+
6+
## [Unreleased]
7+
8+
## [0.2.0] - 未发布
9+
10+
首个可分发版本。
11+
12+
### 广告过滤(开关即时生效)
13+
- 开屏广告:拦截 `module.ads.e.g()`
14+
- 信息流广告:Gson 反序列化阶段过滤 `content_type=23` 条目
15+
- 气泡广告:拦截 `module.ads.h.l()` 展示检查
16+
- 角标广告:阻断 `module.ads.h.h()` 广告拉取
17+
- 推广贴:屏蔽 `content_type` 28/29 及指定官方账号帖子
18+
19+
### 界面增强
20+
- 底部导航栏屏蔽(需重启生效):首页 / 热点 / 游戏库 / 加号,隐藏加号联动隐藏推荐占位
21+
- 小黑盒「设置」页注入 BetterHeybox 设置入口(复用 SettingItemView 样式)
22+
23+
### 帖子增强
24+
- 解除防复制,恢复系统标准文本选择(长按弹「复制/全选」)
25+
- 修复拖动选择只能拉一行(选择时放行滚动容器触摸拦截)
26+
27+
### 通用
28+
- 不显示桌面图标(组件级禁用,可从小黑盒设置页入口进入)
29+
- 设置页「立即重启」:杀小黑盒后台进程 + LSPosed 热重载(无 root)

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# BetterHeybox
2+
3+
小黑盒(Heybox)增强的 LSPosed 模块(libxposed Modern API 102)。
4+
5+
## Note
6+
本应用基于小黑盒1.3.393上完成,低于此版本出现的问题不会进行处理
7+
8+
## 功能
9+
10+
所有功能开关均可在模块自带设置界面(`SettingsActivity`)独立控制;
11+
开关经 LSPosed **RemotePreferences** 跨进程同步,**广告过滤类开关即时生效**
12+
13+
### 广告过滤
14+
15+
| 类型 |
16+
|------|
17+
| 开屏广告 |
18+
| 信息流广告|
19+
| 气泡广告 |
20+
| 角标广告 |
21+
| 推广贴 |
22+
23+
### 界面增强
24+
25+
- **底部导航栏优化**(需重启小黑盒生效):隐藏「首页 / 热点 / 游戏库 / 加号」;
26+
隐藏加号时联动隐藏「推荐」占位,剩余 tab 完全等分、无空白
27+
- **设置页入口注入**:小黑盒「我的 → 设置」页顶部自动插入 "BetterHeybox 设置" 入口,
28+
优先复用小黑盒 `SettingItemView` 样式(失败回退纯代码构建,深浅色均清晰)
29+
30+
### 帖子增强
31+
32+
- **解除复制**:Hook 掉小黑盒自定义 `TextSelectHandler` 的长按拦截,
33+
恢复安卓系统标准文本选择(长按正文弹「复制/全选」菜单,采用系统复制)
34+
- **拖动跨行选择修复**:文本选择激活时放行滚动容器的触摸拦截,选择手柄可跨行拖动
35+
36+
### 通用
37+
38+
- **不显示桌面图标**:组件级禁用 `LaunchActivity`(立即生效),
39+
隐藏后仍可从小黑盒设置页注入的入口进入模块设置
40+
41+
## 技术栈
42+
43+
|||
44+
|----|----|
45+
| 语言 | Java 17 |
46+
| Hook API | `io.github.libxposed:api:102.0.0` |
47+
| Service | `io.github.libxposed:service:102.0.0` |
48+
| compileSdk / targetSdk | 37 |
49+
| minSdk | 26 |
50+
| AGP / Gradle | 9.2.1 / 9.5.1 |
51+
| JDK | 17+ |
52+
53+
## 工程结构
54+
55+
```
56+
app/src/main/
57+
├── AndroidManifest.xml # 模块名/描述 = android:label / android:description
58+
├── java/com/better/heybox/
59+
│ ├── MainModule.java # 模块入口
60+
│ ├── App.java # Application:连接框架服务、RemotePreferences 存取
61+
│ ├── SettingsActivity.java # 模块设置界面
62+
│ └── LaunchActivity.java # 桌面图标入口
63+
├── res/ # 设置页布局 / 字符串 / drawable
64+
└── resources/META-INF/xposed/ # 模块声明
65+
```
66+
67+
另有 `docs/`(开发前置准备文档)与 `analysis/`(逆向分析工作区,不入库)。
68+
69+
## 模块声明
70+
71+
不再使用 Manifest meta-data 与 `assets/xposed_init`,全部声明在 `META-INF/xposed/`
72+
73+
```
74+
app/src/main/resources/META-INF/xposed/
75+
├── java_init.list # 入口类
76+
├── module.prop # minApiVersion=101
77+
└── scope.list # 作用域
78+
```
79+
80+
- 模块名称 / 描述:`android:label` / `android:description`(见 `res/values/strings.xml`
81+
82+
## 构建与使用
83+
84+
1. **环境**:Android Studio 打开本目录(首次自动下载 Gradle 9.5.1 + 依赖,需网络;
85+
若提示缺 wrapper 让 AS 自动补全;SDK Manager 需装有 **Platform 37**
86+
2. **编译**
87+
- Windows:`gradlew.bat assembleDebug`
88+
- 命令行/CI:`./gradlew assembleDebug`
89+
- 或 Android Studio `Build > Make Project`
90+
- 产物:`app/build/outputs/apk/debug/app-debug.apk`
91+
3. **刷入**
92+
- 模拟器/真机需 root + **支持 API 102 的 LSPosed**
93+
- 安装 APK → LSPosed Manager 启用模块。
94+
`staticScope=true` 时作用域固定为 scope.list 中的小黑盒,无需(也无法)手动勾选其它应用
95+
- 重启小黑盒进程
96+
4. **看日志**`adb logcat -s BetterHeybox`(每个 Hook 安装成功/失败均有 ✔/✘ 日志)
97+
98+
# 免责声明
99+
本应用与清枫(北京)科技有限公司无关,仅学习研究小黑盒APP原理,请在下载后24h内删除

app/build.gradle.kts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import java.util.Properties
2+
3+
plugins {
4+
alias(libs.plugins.android.application)
5+
}
6+
7+
// 从 keystore.properties 读取签名信息(该文件不入库,本地手动创建;CI 中由 Secrets 生成)
8+
val keystoreProps = Properties().apply {
9+
val f = rootProject.file("keystore.properties")
10+
if (f.exists()) {
11+
f.inputStream().use { load(it) }
12+
}
13+
}
14+
15+
android {
16+
namespace = "com.better.heybox"
17+
compileSdk = 37
18+
buildToolsVersion = "36.0.0"
19+
20+
defaultConfig {
21+
applicationId = "com.better.heybox"
22+
minSdk = 26 // LSPosed 最低支持 Android 8.0 (API 26)
23+
targetSdk = 37
24+
// 版本号统一在 gradle.properties 管理(versionCode 递增决定升级判定)
25+
versionCode = (project.findProperty("VERSION_CODE") as String? ?: "1").toInt()
26+
versionName = project.findProperty("VERSION_NAME") as String? ?: "0.2.0"
27+
}
28+
29+
signingConfigs {
30+
// keystore.properties 存在才配置 release 签名;缺失时 release 产物为 unsigned
31+
if (keystoreProps.containsKey("storeFile")) {
32+
create("release") {
33+
storeFile = rootProject.file(keystoreProps.getProperty("storeFile"))
34+
storePassword = keystoreProps.getProperty("storePassword")
35+
keyAlias = keystoreProps.getProperty("keyAlias")
36+
keyPassword = keystoreProps.getProperty("keyPassword")
37+
}
38+
}
39+
}
40+
41+
buildTypes {
42+
release {
43+
// Xposed 模块不要开混淆:会干扰 Hook 目标定位与入口类
44+
isMinifyEnabled = false
45+
// 挂上官方规则(供日后启用 R8 时使用)
46+
proguardFiles(
47+
getDefaultProguardFile("proguard-android-optimize.txt"),
48+
"proguard-rules.pro"
49+
)
50+
signingConfig = signingConfigs.findByName("release")
51+
}
52+
}
53+
54+
compileOptions {
55+
sourceCompatibility = JavaVersion.VERSION_17
56+
targetCompatibility = JavaVersion.VERSION_17
57+
}
58+
59+
// 把 META-INF/xposed/ 下的模块声明文件(java_init.list / module.prop / scope.list)
60+
// 合并进 APK,避免被 AGP 默认排除
61+
packaging {
62+
resources {
63+
merges += "META-INF/xposed/*"
64+
excludes += "**"
65+
}
66+
}
67+
}
68+
69+
dependencies {
70+
// 编译期引用,不打进 APK;运行时由 LSPosed 框架提供
71+
compileOnly(libs.libxposed.api)
72+
// 打包进 APK:模块 App 通过它与框架通信(RemotePreferences 跨进程共享开关)
73+
implementation(libs.libxposed.service)
74+
}

app/proguard-rules.pro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# libxposed API 官方推荐规则(即使未开混淆也建议保留,供日后启用 R8 时使用)
2+
-dontwarn io.github.libxposed.annotation.**
3+
-adaptresourcefilecontents META-INF/xposed/java_init.list
4+
-keep,allowoptimization,allowobfuscation public class * extends io.github.libxposed.api.XposedModule {
5+
public <init>();
6+
}

app/src/main/AndroidManifest.xml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<!-- 无 root 重启小黑盒:杀掉其后台进程(普通权限,自动授予) -->
6+
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
7+
8+
<!--
9+
现代 API 102:不再使用 xposedmodule / xposedminversion meta-data。
10+
模块声明全部由 META-INF/xposed/ 下的文件提供:
11+
- module.prop API 版本 / staticScope / autoHotReload
12+
- java_init.list 入口类
13+
- scope.list 作用域(staticScope=true 时生效)
14+
模块名称 = android:label,模块描述 = android:description。
15+
-->
16+
<application
17+
android:name=".App"
18+
android:label="@string/app_name"
19+
android:description="@string/module_description"
20+
tools:ignore="MissingApplicationIcon">
21+
22+
<!--
23+
桌面图标入口(可被「不显示桌面图标」开关禁用)。
24+
隐藏后仍可通过 小黑盒设置 → BetterHeybox 设置 进入模块设置。
25+
-->
26+
<activity
27+
android:name=".LaunchActivity"
28+
android:exported="true"
29+
android:theme="@android:style/Theme.DeviceDefault.DayNight">
30+
<intent-filter>
31+
<action android:name="android.intent.action.MAIN" />
32+
<category android:name="android.intent.category.LAUNCHER" />
33+
</intent-filter>
34+
</activity>
35+
36+
<!--
37+
模块设置界面。exported=true:允许小黑盒进程(Hook 注入的入口)启动它。
38+
不设 LAUNCHER:由 LaunchActivity 作为桌面入口(可被开关禁用)。
39+
-->
40+
<activity
41+
android:name=".SettingsActivity"
42+
android:exported="true"
43+
android:theme="@android:style/Theme.DeviceDefault.DayNight" />
44+
</application>
45+
46+
</manifest>

0 commit comments

Comments
 (0)