Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

空相册清理 (EmptyAlbumCleaner)

批量勾选删除 MIUI / HyperOS 系统相册(com.miui.gallery)里的空相册的 LSPosed 模块。删除走相册自身的删除接口,云端相册会同步删除。

功能

  • 在相册「相册」Tab 的右上角(标题「相册」右边、排序图标左边)注入一个 「清理」 按钮
  • 点击后弹出「清理空相册」列表,自动扫描出所有空相册(照片数为 0)
  • 支持全选 / 全不选 / 单独勾选,底部显示当前勾选数量
  • 批量删除,可选项同时删除仍占磁盘的空文件夹
  • 列表可滚动,不会闪退

空相册的定义

一个相册满足以下条件即判定为「空相册」,会出现在清理列表里:

  1. 相册对应的 album 表中该相册没有被删除状态的储存项(cloud 表按 localGroupId 统计,排除 serverStatus='deleted'),即一张照片都没有
  2. 磁盘上对应文件夹不存在,或存在但没有任何媒体文件(jpg/png/mp4 等常见扩展名)
  3. 不在受保护名单内

受保护相册(永远不会出现在清理列表):sdcard存储卡SD卡最近删除回收站收藏最爱,以及 DCIMDCIM/CameraDCIM/ScreenshotsDCIM/screenrecorderPicturesDownloadMovies 等系统目录相册。

工作原理

  • 技术路线:现代 libxposed API 102(io.github.libxposed.api.XposedModule),入口类 com.jp.emptyalbumcleaner.ModuleEntry
  • 模块元数据META-INF/xposed/{module.prop, java_init.list, scope.list},作用域固定为 com.miui.gallery
  • Hook 点AlbumTabFragment.onResume —— 每次进入相册 Tab 时把「清理」按钮挂载到宿主窗口(用独立 FrameLayout 叠加在 action bar 区域,不侵入相册视图树)
  • 扫描:直接在相册进程里打开 /data/data/com.miui.gallery/databases/gallery.db(同为相册 uid,无权限问题),统计 cloud 表各 localGroupId 的媒体数,再检查磁盘文件夹
  • 删除:通过相册自己的 ContentProvider content://com.miui.gallery.cloud.provider/album_id 删除,走的是与相册自身界面完全一致的删除逻辑,所以记录被干净移除,且云端相册会同步删除

说明:删除接口实测有效(记录直接从 album 表移除,不留墓碑标记)。磁盘文件夹不会随记录联动删除,因此清理列表提供「同时删除空文件夹」选项,由模块自行递归删除(仅删除不含任何媒体文件的目录)。

使用步骤

1. 安装模块

  1. 在 LSPosed Manager 中启用「空相册清理」
  2. 作用域勾选 「系统相册」com.miui.gallery
  3. 强制停止相册,再重新打开

2. 使用

  1. 打开系统相册 → 切到 「相册」Tab
  2. 右上角标题旁点 「清理」
  3. 列表会显示所有空相册(名称 + 状态说明,如「云端相册 · 文件夹不存在,仅剩记录」)
  4. 勾选要删除的(或点「全选/全不选」全选)→ 点底部的 「删除所选(N)」
  5. 确认后批量删除

⚠️ 若登录了小米云,删除对应云端相册不可恢复,请谨慎勾选;已删除的相册不会进回收站。

构建教程

本项目使用 build_module.sh 独立构建流水线(无需 Gradle、无需 Android Studio):

aapt2 link → javac(libxposed API 以 compileOnly stub 参与编译)→ d8 → zip 打包 → zipalign → apksigner 签名

1. 环境要求(Windows)

组件 要求 说明
Android SDK platforms/android-36.1 + build-tools/36.1.0 脚本里 SDK 路径写死为 C:/Users/<你>/AppData/Local/Android/Sdk,如不同请改 build_module.sh 顶部 SDK=
JDK 17(Temurin 等均可) 脚本会找 tools/jdk-17*;没有则需你系统的 java/javac 可用
Android 平台 jar platforms/android-36.1/android.jar 编译 classpath

脚本假设 SDK 在默认位置。如果你的 SDK 在别处,编辑 build_module.sh 第 5-6 行的 SDK=BT=AJ= 指向实际路径。

2. 一键构建

# 在项目根目录
bash build_module.sh

脚本步骤:

  1. 编译 libxposed API stub —— 把 api_stub/(compileOnly 用,不进 APK)和 tools/maven/api_src 官方源码编译成 build/libxposed_api.jar
  2. aapt2 link —— 用 AndroidManifest.xml 生成中间 base.apk
  3. javac —— 编译 app/src/main/java 下所有模块类(classpath 含 android.jar + libxposed api jar)
  4. d8 —— 把 classes 转 dex(--min-api 27
  5. 打包 —— dex 与 META-INF/xposed/*(模块元数据)写入 APK
  6. zipalign + apksigner 签名 —— 用 keystore/debug.keystore(首次自动生成)

产出:build/EmptyAlbumCleaner.apk

3. 签名说明

  • 首次运行会自动生成调试签名 keystore/debug.keystore(别名 eac,密码 android
  • 重新构建会复用同一密钥,所以可以覆盖安装同一台手机上的旧版
  • 若要分发给别人,建议换成自己的正式签名(改 build_module.sh 里 apksigner 参数)

4. 验证产物

# 检查模块元数据是否打进 APK(缺失会导致 LSPosed 不识别)
unzip -l build/EmptyAlbumCleaner.apk | grep -E "META-INF/xposed"
# 应看到:
#   META-INF/xposed/module.prop
#   META-INF/xposed/java_init.list
#   META-INF/xposed/scope.list

# 检查签名
/你的SDK/build-tools/36.1.0/apksigner.bat verify --print-certs build/EmptyAlbumCleaner.apk

5. 安装到手机

adb install -r build/EmptyAlbumCleaner.apk
# 或在手机上用系统安装器打开 APK

安装后在 LSPosed 管理器 → 模块 里勾选「空相册清理」,作用域勾选 com.miui.gallery,强停相册后重开即可。

6. 常见构建问题

问题 原因 / 解决
javac: 找不到符号 android.* classpath 里 android.jar 路径不对;确认 SDK/platforms/android-36.1/android.jar 存在且 build_module.shAJ= 正确
aapt2: error: failed processing manifest manifest 语法错(如 description 属性不能直接写中文字符串),检查 app/src/main/AndroidManifest.xml
d8: 找不到类 build/classes 为空或 javac 没产出;先修 javac 报错
手机上模块不生效 确认 APK 内 META-INF/xposed/* 齐全(第 4 步验证)、模块已启用、作用域已勾选、相册已强停/重启
LSPosed 管理器里看不到模块 你的 LSPosed 必须是 v2.x(现代 API);旧版框架不识别 API 102 模块

项目结构

app/
└── src/main/
    ├── AndroidManifest.xml           # 应用声明(去掉旧 xposed meta-data)
    ├── java/com/jp/emptyalbumcleaner/
    │   ├── ModuleEntry.java          # API 102 入口:hook AlbumTabFragment,挂「清理」按钮
    │   ├── AlbumScanner.java         # 扫描 gallery.db + 磁盘,判定空相册
    │   ├── CleanDialog.java          # 勾选列表 + 批量删除对话框
    │   └── CleanActivity.java        # 独立的说明页(桌面图标可打开)
    └── resources/META-INF/xposed/    # 现代模块元数据
        ├── module.prop               # minApiVersion=101, targetApiVersion=102, scope 固定
        ├── java_init.list            # com.jp.emptyalbumcleaner.ModuleEntry
        └── scope.list                # com.miui.gallery

api_stub/       # 编译期 libxposed API stub(compileOnly,不打进 APK)
build_module.sh  # 构建脚本

兼容性

  • 适配 LSPosed v2.x(现代 API 102 框架)。旧式 Xposed 模块(IXposedHookLoadPackage + assets/xposed_init + xposedmodule meta-data)在新版 LSPosed 里不会被识别为模块——早期版本即因此无法出现在管理器列表。
  • 目标:小米相册 com.miui.gallery(HyperOS / MIUI)。
  • 关键类(AlbumTabFragmentgallery.db 表结构)在不同相册版本可能变化,若相册大版本更新后按钮不出现或列表异常,请重新验证 Hook 点。

常见问题

Q: LSPosed 管理器里看不到「空相册清理」? A: 确认你的 LSPosed 是 v2.x(现代 API)。模块必须包含 META-INF/xposed/* 元数据,且入口类继承 XposedModule。安装后需要强制停止相册或重启手机。

Q: 点「清理」没反应 / 列表为空? A: 检查作用域是否勾选了 com.miui.gallery;若确实没有空相册会提示「没有发现空相册」。

Q: 列表滚动会闪退? A: 早期版本列表项复用有 bug(CheckBox 强转为 ViewGroup)。当前版本已改为每次 new 行,滚动安全。

Q: 删错了能恢复吗? A: 走相册原生删除接口,云端相册不可恢复;请务必先只勾选确认无误的相册。

About

批量勾选删除 MIUI 相册空相册的 LSPosed 模块 (libxposed API 102)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages