Tasker 永久试用修改思路
首先贴出 官网 和 Google Play 商店链接 。建议购买正版支持原作者,不贵,当前 4.49 USD。制作此改版是由于我有台不带 Google 框架的设备无法通过验证。
成品下载: OneDrive | 123 云盘 | 蓝奏云 。
目前网上很多所谓“破解版”下载后校验就是官方签名,说明根本没改过,真搞笑。此应用 7 天试用期内无任何提示,许多人在各论坛分享假“破解版”,骗取回帖经验值。
由于目前最新版 6.6.20 体积较大,这里选择相对旧的 6.2.22 (Target API SDK 33 T),功能够用且不包含 Google Gemini 等无聊组件。经尝试相同修改思路对新版也有效。
java -jar apktool.jar d origin.apk -o apk_decoded -f # 解开 apk
rm -rf apk_decoded/lib # 删除原生库试用机制分析(感谢 MiMo-V2.5 模型 提供的支持):
- 安装时间戳存储在
SharedPreferences,key 为idt。 - 试用期计算在
Licence.smali及Main.smali中。逻辑为daysPassed = (currentTimeMillis - idt) / 86400000。试用期硬编码为 7 天(const/4 v0, 0x7)。
最简单的思路就是改安装时间戳,改到下辈子去。正好 Main.aa() 中有判断 idt 是否为异常值的逻辑,每次启动都会执行。我们就改它,免得改别处又被它覆盖。所以打开 Main.smali 找到:
invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
# ...
cmp-long v1, v4, v8
if-gtz v1, :cond_2
cmp-long v1, v4, v2
if-nez v1, :cond_1
:cond_1
# ...
invoke-interface {v1, v4, v8, v9}, Landroid/content/SharedPreferences$Editor;->putLong(Ljava/lang/String;J)Landroid/content/SharedPreferences$Editor;把第一个 if-gtz v1, :cond_2 改成 goto :cond_1,永远当成异常值。写入逻辑用了 v8, v9 凑成的 64 位,所以在前面加上 const-wide v8, 0x223344556677L 完事。
为了看着开心,还可以改下 Licence.smali。找到这样的逻辑:
invoke-virtual {v4, v5}, Landroid/widget/TextView;->setTextIsSelectable(Z)V
const/4 v4, 0x0
if-eqz v2, :cond_2
const v0, 0x7f100818
iget-object v2, p0, Lnet/dinglisch/android/taskerm/Licence;->v:Landroid/widget/EditText;把 if-eqz v2, :cond_2 删除即可。
另外,重新打包会破坏签名造成 Google Sign In 不可用,分享 As Link 自然需要联网验证,而用 Data URI 功能分享单个 task/profile 理应不依赖 Google 登录,却被故意限制,这里单独解除,文件 smali_classes2/com/joaomgcd/taskerm/datashare/export/d$c.smali:
move-result-object v4
sget-object v9, Lcom/joaomgcd/taskerm/signin/a;->a:Lcom/joaomgcd/taskerm/signin/a$a;
# ...
:cond_5
:try_start_2
iget-object v5, p0, Lcom/joaomgcd/taskerm/datashare/export/d$c;->p:Landroid/app/Activity;在 move-result-object v4 之后加上 goto :cond_5 即可。
打包后发现 State 类型的 profile(如 State: %Temp1 = 9)永不触发,而 Event 类型(如监听通知)正常。即使对官方版不做修改 unzip → zip → align → sign 也会出现,说明有签名验证。
经探索,mn.smali 中的 mn.v(Context) 通过 getPackageInfo(..., 0x40) 取到当前 APK 签名,与硬编码的 0x15a25eb8 比较。所以,我们在 mn.smali:12150 找到:
invoke-virtual {p0}, Landroid/content/pm/Signature;->hashCode()I
move-result p0
if-eq p0, v0, :cond_0把 if-eq xxx 改成 goto :cond_0。此处修改也同时移除了 ExecuteService.f4 对旧版动作(Variable Set/Flash 等)的拦截。
顺带在 res/values-zh/strings.xml 加几条缺失的翻译。最后重新打包、压缩、签名。这里过程中还使用了 ect(优化过的 zopfli)。
java -jar apktool.jar build apk_decoded -o raw.apk
aapt2 optimize -o optimized.apk --shorten-resource-paths --deduplicate-entry-values --enable-compact-entries raw.apk
rm -rf /tmp/apk_extreme
mkdir /tmp/apk_extreme
d=$(pwd)
pushd /tmp/apk_extreme
unzip -q $d/optimized.apk
zip -q -1 -r -x resources.arsc -X $d/a.apk .
$d/zcodecs12 ect -9 --strict -zip $d/a.apk # extreme compress
zip -q -0 -X $d/a.apk resources.arsc # arsc as store
popd
zipalign -f -p 16 a.apk a.aligned.apk # 16k align
apksigner sign \
--ks "password=123456.keystore" \
--ks-pass pass:123456 \
--key-pass pass:123456 \
--ks-key-alias tasker-crack \
--v1-signing-enabled true \
--v2-signing-enabled true \
a.aligned.apk
apksigner verify a.aligned.apk
# C:\Users\klc2u1\AppData\Local\Android\Sdk\build-tools\36.1.0\d8 classes.dex classes2.dex --min-api 21 --lib C:\Users\klc2u1\AppData\Local\Android\Sdk\platforms\android-35\android.jar --release --output .\dex_output\使用 apktool(或 mt 管理器)解开 dex 到 smali 后重新生成会增大体积,因此建议在验证可行性后,只编辑对应的 dex,避免触碰其他无关 dex。对于已被修改且体积膨胀的 dex,可以这样挽救一部分:
curl -o smali.jar -L https://github.com/baksmali/smali/releases/download/3.0.9/smali-3.0.9-fat-release.jar -o baksmali.jar -L https://github.com/baksmali/smali/releases/download/3.0.9/baksmali-3.0.9-fat-release.jar
# 已经修改且打包过的 dex 文件,使用 baksmali 再一次反编译并安全剥离调试信息,然后再 smali 回去
java -jar baksmali.jar disassemble --debug-info false -o smali_out classes2.dex
java -jar smali.jar assemble smali_out -o classes2_next.dex不要尝试使用 facebook redex 来优化。对于这种没有调试信息的 dex 来说风险太大。很容易炸飞自己。
(AI 生成内容) Tasker 添加单点执行按钮
附加功能目标:TASKS 列表每个条目末尾增加一个 ▷ 按钮,直接执行该条目,不再需要长按选中后点顶栏 Play。
调用链:
- TASKS 列表适配器由
Main.db()创建,类是net.dinglisch.android.taskerm.el。 - 条目布局由
el.getView()加载,文件是res/layout/task_list_item.xml。 - 单个任务对象是
net.dinglisch.android.taskerm.cl。 - Tasker 已有现成的直接执行入口:
invoke-virtual {v0, v1}, Lnet/dinglisch/android/taskerm/cl;->v0(Landroid/content/Context;)V它内部调用 ExecuteService.h7(Context, cl)。因此不用追顶栏 Play 的 ActionMode 逻辑,只需要让行内按钮拿到当前 cl 并调用这个入口。
修改布局:
修改 apk_decoded/res/layout/task_list_item.xml。在 drag_margin 后面加一个 TextView;同时在 LinearLayout 的末尾加一小段占位空间,避免原来的右侧图标被按钮压住:
<LinearLayout ...>
<!-- 原有 name、lock_icon、icon、problem_icon 保持不动 -->
<View android:layout_width="42.0dp" android:layout_height="match_parent" />
</LinearLayout>
<View android:id="@id/drag_margin"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@id/playpause"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="40.0dp"
android:gravity="center"
android:text=" ▷ "
android:textColor="?android:textColorPrimary"
android:textSize="16.0sp" />这里复用了 APK 里已经存在的 playpause ID,不需要分配新资源 ID。按钮文本是四个字符:左侧两个全角空格,右侧一个全角空格,中间是 U+25B7。
给 Holder 加字段:
修改 apk_decoded/smali_classes2/net/dinglisch/android/taskerm/el$a.smali,在实例字段里加:
.field h:Landroid/widget/TextView;完整字段顺序大致保持原有字段不动即可。
让适配器处理点击:
修改 el.smali 头部,让它实现 OnClickListener:
.class public Lnet/dinglisch/android/taskerm/el;
.super Lnet/dinglisch/android/taskerm/ff;
.implements Landroid/view/View$OnClickListener;
.source "SourceFile"在 getView() 创建新行的分支中,原代码把 drag_margin 放进 holder 字段 f 之后,继续初始化新按钮:
const v2, 0x7f090278
invoke-virtual {p2, v2}, Landroid/view/View;->findViewById(I)Landroid/view/View;
move-result-object v2
check-cast v2, Landroid/widget/TextView;
iput-object v2, v1, Lnet/dinglisch/android/taskerm/el$a;->h:Landroid/widget/TextView;
invoke-virtual {v2, p0}, Landroid/view/View;->setOnClickListener(Landroid/view/View$OnClickListener;)V0x7f090278 就是现有资源里的 playpause。注意这里 receptor 是 root view p2,holder 是 v1。
然后找到每次绑定当前位置的位置。这段附近会先从 e:ArrayList 取出当前项并转成 cl:
move-result-object p1
check-cast p1, Lnet/dinglisch/android/taskerm/cl;在紧接着的绑定区域加两行,把当前任务对象写进按钮 tag:
iget-object v3, v1, Lnet/dinglisch/android/taskerm/el$a;->h:Landroid/widget/TextView;
invoke-virtual {v3, p1}, Landroid/view/View;->setTag(Ljava/lang/Object;)V最后给 el.smali 追加点击方法:
.method public onClick(Landroid/view/View;)V
.locals 2
invoke-virtual {p1}, Landroid/view/View;->getTag()Ljava/lang/Object;
move-result-object v0
check-cast v0, Lnet/dinglisch/android/taskerm/cl;
iget-object v1, p0, Lnet/dinglisch/android/taskerm/ff;->a:Landroid/content/Context;
invoke-virtual {v0, v1}, Lnet/dinglisch/android/taskerm/cl;->v0(Landroid/content/Context;)V
return-void
.end methodff.a 是 public 的 Context 字段。
已踩过的小坑:
RelativeLayout里的子控件必须显式写layout_width和layout_height,否则 AAPT 能编译通过,运行 inflate 时 crash。- 同一个 holder 字段名必须全程使用完全相同的类型描述符;写成声明
TextView但读取ImageView会报NoSuchFieldError。
更新日志
20260827_v5
- 在 Tasks 这个 Tab 里,为所有 Task 条目的右侧添加一个立刻执行的按钮,方便使用。原版无此功能。感谢 GLM-5.3-Flash 提供的帮助。
20260811_v4
- 移除隐藏的签名验证逻辑,避免 State、Vars 相关功能异常。
20260805_v3
- 修复导入 Data URI 时被强制要求 Google 登录(离线导入以 Data URI 形式分享的 Task、Profile 等)。
- 修复 Play 框架导致的试用到期。
- 补充部分缺失汉化条目,并且进一步精简体积。
20260725_v2
- 由于 6.1.32 版本的“添加到主屏幕”功能缺失,切换到基于 6.2.22 修改。