ZenTasker 是一个基于 Shizuku 的 Android 本地自动化调度应用,使用 AlarmManager 做链式唤醒,用 Jetpack Compose 提供控制台界面,并通过 Shell + uiautomator dump 完成基础自动化执行。
项目目标很明确:不用无障碍常驻,不开前台服务,把任务注册、唤醒、执行、重调度全部收敛在一个低常驻成本的本地自动化流程里。
本项目采用 GNU General Public License v3.0,许可证全文见根目录 LICENSE。
除非另有说明,项目源码 Copyright (C) 2026 loong,并按 GPL-3.0-only 发布。这意味着:
- 你可以使用、修改和分发本项目代码
- 如果你分发修改版或基于本项目的衍生项目,必须继续以
GPL-3.0公开其对应源码 - 本项目按“无担保”方式提供
- 基于
AlarmManager的单线链式调度,只注册最近一次可执行任务 - 支持开机后与应用升级后的自动重建调度
- 支持任务脚本可视化编辑和 JSON 编辑
- 支持
shell、swipe、sleep、find_and_tap四类动作 find_and_tap基于uiautomator dump解析节点文字或content-desc后点击中心点- 支持
everyday、workday_only两种触发条件 - 提供 Shizuku、日历权限、电池优化白名单状态面板
- 提供干跑测试和应用内日志查看
应用当前包含 3 个主页面:
Dashboard:权限状态、下一次任务、调度预览、重载注册、干跑测试Editor:任务表单编辑和 JSON 编辑Logs:查看与清空执行日志
ZenTasker 采用“只调度下一个任务”的链式模型:
- 从本地配置读取全部 jobs
- 计算当前时间之后最近且满足条件的一个 job
- 使用
setExactAndAllowWhileIdle注册闹钟 - 闹钟触发后由
TaskReceiver拉起执行 - 执行结束后立即重新计算并注册下一次任务
如果设备未授权精确闹钟,应用会降级为普通调度,并在界面上显示对应状态。
- Kotlin
- Jetpack Compose
- Kotlin Coroutines
- Gson
- Shizuku API
13.1.5 - Android AlarmManager / BroadcastReceiver / CalendarContract
- Android Studio 新版本
- JDK 11
- Android SDK:
compileSdk = 36targetSdk = 36minSdk = 26
.\gradlew.bat assembleDebug.\gradlew.bat testDebugUnitTestRelease 构建要求提供签名配置。可以二选一:
- 在项目根目录创建
keystore.properties - 配置环境变量:
ZEN_TASKER_STOREFILEZEN_TASKER_STOREPASSWORDZEN_TASKER_KEYALIASZEN_TASKER_KEYPASSWORD
可参考项目中的 keystore.properties.example。
.\gradlew.bat assembleRelease本仓库的 release 构建已经支持从环境变量读取签名配置,所以在 GitHub Actions 中只需要恢复 keystore 文件并注入这些 secrets:
SIGNING_KEYSTORE_BASE64ZEN_TASKER_STOREPASSWORDZEN_TASKER_KEYALIASZEN_TASKER_KEYPASSWORD
其中 SIGNING_KEYSTORE_BASE64 是 .jks 文件的 Base64 内容。Windows PowerShell 可这样生成:
[Convert]::ToBase64String([IO.File]::ReadAllBytes("zentasker-release.jks"))工作流文件是 .github/workflows/release.yml,支持两种触发方式:
- 推送 tag,例如
v1.1.0,自动构建签名 APK 并发布 GitHub Release - 在 Actions 页面手动运行,构建并上传 APK artifact
示例:
git tag v1.1.0
git push origin v1.1.0应用要正常执行自动化任务,至少需要满足这些条件:
- 已安装并启动 Shizuku
- 已向 ZenTasker 授予 Shizuku 权限
- 建议关闭电池优化
- Android 12+ 建议授权精确闹钟
- 如果使用
workday_only,建议授予日历读取权限
workday_only 的判断逻辑如下:
- 优先读取系统日历事件标题
- 命中 “班” 或 “调休” 视为工作日
- 命中 “休” 或 “节假日” 视为非工作日
- 如果没有日历权限或没有匹配事件,则回退到普通周一到周五判断
运行时配置不是直接读取仓库内文件,而是保存在应用私有目录中的 config.json。首次启动时会自动写入一份默认模板。
当前任务模型示例:
{
"jobs": [
{
"job_id": "morning_clock_in",
"job_name": "上班打卡",
"trigger_time": "08:50",
"condition": "workday_only",
"tasks": [
{
"action": "shell",
"cmd": "input keyevent 224",
"desc": "点亮屏幕"
},
{
"action": "sleep",
"duration": 1000,
"desc": "等待系统就绪"
},
{
"action": "swipe",
"x1": 500,
"y1": 2000,
"x2": 500,
"y2": 500,
"duration": 300,
"desc": "滑动解锁"
},
{
"action": "find_and_tap",
"target_text": "工作台",
"timeout_ms": 15000,
"retry_interval_ms": 2000,
"desc": "查找并点击工作台"
}
]
}
]
}说明:
job_id需要唯一trigger_time格式为HH:mmcondition当前仅支持everyday与workday_only- JSON 字段名使用
snake_case - 表单编辑和 JSON 编辑都会写回本地
config.json app/src/main/assets/jobs.json当前更接近示例素材,不是主要运行时数据源
直接通过 Shizuku UserService 执行 Shell 命令。
关键字段:
cmdtimeout_ms可选
本质上会转换成:
input swipe x1 y1 x2 y2 duration关键字段:
x1y1x2y2duration可选timeout_ms可选
挂起协程等待指定毫秒数。
关键字段:
duration
执行流程:
uiautomator dump /data/local/tmp/window_dump.xmlcat /data/local/tmp/window_dump.xml- 匹配节点
text或content-desc - 解析
bounds - 计算中心点并执行
input tap
关键字段:
target_texttimeout_ms可选retry_interval_ms可选
- 应用日志保存在私有文件
zentasker_logs.txt - 日志页会读取最近的日志内容
- 干跑测试会按当前选中的 job 顺序执行其全部任务并记录结果
常见问题优先检查:
- Shizuku 是否已运行
- ZenTasker 是否已获得 Shizuku 权限
- 精确闹钟是否可用
- 电池优化是否放行
workday_only是否因日历规则或周末判断被跳过find_and_tap目标文字是否真的出现在当前界面节点树里
app/src/main/java/com/zentasker
├─ executor # Shizuku 远程执行与智能点击
├─ scheduler # 条件判断、链式调度、广播接收器
├─ script # JSON 配置解析与模型
├─ ui # Compose 页面与组件
└─ utils # 日志等工具
ScheduleManager:计算下一次任务并注册系统闹钟TaskReceiver:执行任务并在结束后续约下一次调度RescheduleReceiver:开机或应用升级后重建调度SmartExecutor:封装 Shizuku UserService 和任务动作执行JobScriptParser:本地配置读写、JSON 校验与默认配置注入
- 这是一个强依赖系统能力与 Shizuku 运行状态的本地自动化项目
- 不使用无障碍服务,不提供前台服务常驻
find_and_tap依赖界面文字或无障碍描述,目标控件不可见时会失败- 节假日判断依赖系统日历事件命名习惯,适合本地自定义环境,不适合作为通用法定节假日服务